/* Renesas RX specific support for 32-bit ELF.
- Copyright (C) 2008, 2009, 2010, 2011
- Free Software Foundation, Inc.
+ Copyright (C) 2008-2014 Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
#include "elf-bfd.h"
#include "elf/rx.h"
#include "libiberty.h"
+#include "elf32-rx.h"
#define RX_OPCODE_BIG_ENDIAN 0
+/* This is a meta-target that's used only with objcopy, to avoid the
+ endian-swap we would otherwise get. We check for this in
+ rx_elf_object_p(). */
+const bfd_target rx_elf32_be_ns_vec;
+const bfd_target rx_elf32_be_vec;
+
#ifdef DEBUG
char * rx_get_reloc (long);
void rx_dump_symtab (bfd *, void *, void *);
unsigned int r_type;
r_type = ELF32_R_TYPE (dst->r_info);
- BFD_ASSERT (r_type < (unsigned int) R_RX_max);
+ if (r_type >= (unsigned int) R_RX_max)
+ {
+ _bfd_error_handler (_("%A: invalid RX reloc number: %d"), abfd, r_type);
+ r_type = 0;
+ }
cache_ptr->howto = rx_elf_howto_table + r_type;
}
\f
return value;
}
+static bfd_vma
+get_symbol_value_maybe (const char * name,
+ struct bfd_link_info * info)
+{
+ bfd_vma value = 0;
+ struct bfd_link_hash_entry * h;
+
+ h = bfd_link_hash_lookup (info->hash, name, FALSE, FALSE, TRUE);
+
+ if (h == NULL
+ || (h->type != bfd_link_hash_defined
+ && h->type != bfd_link_hash_defweak))
+ return 0;
+ else
+ value = (h->u.def.value
+ + h->u.def.section->output_section->vma
+ + h->u.def.section->output_offset);
+
+ return value;
+}
static bfd_vma
get_gp (bfd_reloc_status_type * status,
struct elf_link_hash_entry ** sym_hashes;
Elf_Internal_Rela * rel;
Elf_Internal_Rela * relend;
+ bfd_boolean pid_mode;
+ bfd_boolean saw_subtract = FALSE;
+ const char * table_default_cache = NULL;
+ bfd_vma table_start_cache = 0;
+ bfd_vma table_end_cache = 0;
+
+ if (elf_elfheader (output_bfd)->e_flags & E_FLAG_RX_PID)
+ pid_mode = TRUE;
+ else
+ pid_mode = FALSE;
symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
sym_hashes = elf_sym_hashes (input_bfd);
sec = NULL;
relocation = 0;
+ if (rx_stack_top == 0)
+ saw_subtract = FALSE;
+
if (r_symndx < symtab_hdr->sh_info)
{
sym = local_syms + r_symndx;
}
else
{
- bfd_boolean warned;
+ bfd_boolean warned, ignored;
RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
r_symndx, symtab_hdr, sym_hashes, h,
sec, relocation, unresolved_reloc,
- warned);
+ warned, ignored);
name = h->root.root.string;
}
- if (sec != NULL && elf_discarded_section (sec))
+ if (strncmp (name, "$tableentry$default$", 20) == 0)
+ {
+ bfd_vma entry_vma;
+ int idx;
+ char *buf;
+ bfd_reloc_status_type tstat = 0;
+
+ if (table_default_cache != name)
+ {
+
+ /* All relocs for a given table should be to the same
+ (weak) default symbol) so we can use it to detect a
+ cache miss. We use the offset into the table to find
+ the "real" symbol. Calculate and store the table's
+ offset here. */
+
+ table_default_cache = name;
+
+ /* We have already done error checking in rx_table_find(). */
+
+ buf = (char *) malloc (13 + strlen (name + 20));
+
+ sprintf (buf, "$tablestart$%s", name + 20);
+ tstat = 0;
+ table_start_cache = get_symbol_value (buf,
+ &tstat,
+ info,
+ input_bfd,
+ input_section,
+ rel->r_offset);
+
+ sprintf (buf, "$tableend$%s", name + 20);
+ tstat = 0;
+ table_end_cache = get_symbol_value (buf,
+ &tstat,
+ info,
+ input_bfd,
+ input_section,
+ rel->r_offset);
+
+ free (buf);
+ }
+
+ entry_vma = (input_section->output_section->vma
+ + input_section->output_offset
+ + rel->r_offset);
+
+ if (table_end_cache <= entry_vma || entry_vma < table_start_cache)
+ {
+ _bfd_error_handler (_("%B:%A: table entry %s outside table"),
+ input_bfd, input_section,
+ name);
+ }
+ else if ((int) (entry_vma - table_start_cache) % 4)
+ {
+ _bfd_error_handler (_("%B:%A: table entry %s not word-aligned within table"),
+ input_bfd, input_section,
+ name);
+ }
+ else
+ {
+ idx = (int) (entry_vma - table_start_cache) / 4;
+
+ /* This will look like $tableentry$<N>$<name> */
+ buf = (char *) malloc (12 + 20 + strlen (name + 20));
+ sprintf (buf, "$tableentry$%d$%s", idx, name + 20);
+
+ h = (struct elf_link_hash_entry *) bfd_link_hash_lookup (info->hash, buf, FALSE, FALSE, TRUE);
+
+ if (h)
+ {
+ relocation = (h->root.u.def.value
+ + h->root.u.def.section->output_section->vma
+ + h->root.u.def.section->output_offset);;
+ }
+
+ free (buf);
+ }
+ }
+
+ if (sec != NULL && discarded_section (sec))
RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
- rel, relend, howto, contents);
+ rel, 1, relend, howto, 0, contents);
if (info->relocatable)
{
_bfd_error_handler (_("%B:%A: Warning: deprecated Red Hat reloc " type " detected against: %s."), \
input_bfd, input_section, name)
+ /* Check for unsafe relocs in PID mode. These are any relocs where
+ an absolute address is being computed. There are special cases
+ for relocs against symbols that are known to be referenced in
+ crt0.o before the PID base address register has been initialised. */
+#define UNSAFE_FOR_PID \
+ do \
+ { \
+ if (pid_mode \
+ && sec != NULL \
+ && sec->flags & SEC_READONLY \
+ && !(input_section->flags & SEC_DEBUGGING) \
+ && strcmp (name, "__pid_base") != 0 \
+ && strcmp (name, "__gp") != 0 \
+ && strcmp (name, "__romdatastart") != 0 \
+ && !saw_subtract) \
+ _bfd_error_handler (_("%B(%A): unsafe PID relocation %s at 0x%08lx (against %s in %s)"), \
+ input_bfd, input_section, howto->name, \
+ input_section->output_section->vma + input_section->output_offset + rel->r_offset, \
+ name, sec->name); \
+ } \
+ while (0)
+
/* Opcode relocs are always big endian. Data relocs are bi-endian. */
switch (r_type)
{
WARN_REDHAT ("RX_RH_8_NEG");
relocation = - relocation;
case R_RX_DIR8S_PCREL:
+ UNSAFE_FOR_PID;
RANGE (-128, 127);
OP (0) = relocation;
break;
case R_RX_DIR8S:
+ UNSAFE_FOR_PID;
RANGE (-128, 255);
OP (0) = relocation;
break;
case R_RX_DIR8U:
+ UNSAFE_FOR_PID;
RANGE (0, 255);
OP (0) = relocation;
break;
WARN_REDHAT ("RX_RH_16_NEG");
relocation = - relocation;
case R_RX_DIR16S_PCREL:
+ UNSAFE_FOR_PID;
RANGE (-32768, 32767);
#if RX_OPCODE_BIG_ENDIAN
#else
case R_RX_RH_16_OP:
WARN_REDHAT ("RX_RH_16_OP");
+ UNSAFE_FOR_PID;
RANGE (-32768, 32767);
#if RX_OPCODE_BIG_ENDIAN
OP (1) = relocation;
break;
case R_RX_DIR16S:
+ UNSAFE_FOR_PID;
RANGE (-32768, 65535);
if (BIGE (output_bfd) && !(input_section->flags & SEC_CODE))
{
break;
case R_RX_DIR16U:
+ UNSAFE_FOR_PID;
RANGE (0, 65536);
#if RX_OPCODE_BIG_ENDIAN
OP (1) = relocation;
break;
case R_RX_DIR16:
+ UNSAFE_FOR_PID;
RANGE (-32768, 65536);
#if RX_OPCODE_BIG_ENDIAN
OP (1) = relocation;
break;
case R_RX_DIR16_REV:
+ UNSAFE_FOR_PID;
RANGE (-32768, 65536);
#if RX_OPCODE_BIG_ENDIAN
OP (0) = relocation;
break;
case R_RX_RH_24_NEG:
+ UNSAFE_FOR_PID;
WARN_REDHAT ("RX_RH_24_NEG");
relocation = - relocation;
case R_RX_DIR24S_PCREL:
break;
case R_RX_RH_24_OP:
+ UNSAFE_FOR_PID;
WARN_REDHAT ("RX_RH_24_OP");
RANGE (-0x800000, 0x7fffff);
#if RX_OPCODE_BIG_ENDIAN
break;
case R_RX_DIR24S:
+ UNSAFE_FOR_PID;
RANGE (-0x800000, 0x7fffff);
if (BIGE (output_bfd) && !(input_section->flags & SEC_CODE))
{
break;
case R_RX_RH_24_UNS:
+ UNSAFE_FOR_PID;
WARN_REDHAT ("RX_RH_24_UNS");
RANGE (0, 0xffffff);
#if RX_OPCODE_BIG_ENDIAN
break;
case R_RX_RH_32_NEG:
+ UNSAFE_FOR_PID;
WARN_REDHAT ("RX_RH_32_NEG");
relocation = - relocation;
#if RX_OPCODE_BIG_ENDIAN
break;
case R_RX_RH_32_OP:
+ UNSAFE_FOR_PID;
WARN_REDHAT ("RX_RH_32_OP");
#if RX_OPCODE_BIG_ENDIAN
OP (3) = relocation;
/* Complex reloc handling: */
case R_RX_ABS32:
+ UNSAFE_FOR_PID;
RX_STACK_POP (relocation);
#if RX_OPCODE_BIG_ENDIAN
OP (3) = relocation;
break;
case R_RX_ABS32_REV:
+ UNSAFE_FOR_PID;
RX_STACK_POP (relocation);
#if RX_OPCODE_BIG_ENDIAN
OP (0) = relocation;
case R_RX_ABS24S_PCREL:
case R_RX_ABS24S:
+ UNSAFE_FOR_PID;
RX_STACK_POP (relocation);
RANGE (-0x800000, 0x7fffff);
if (BIGE (output_bfd) && !(input_section->flags & SEC_CODE))
break;
case R_RX_ABS16:
+ UNSAFE_FOR_PID;
RX_STACK_POP (relocation);
RANGE (-32768, 65535);
#if RX_OPCODE_BIG_ENDIAN
break;
case R_RX_ABS16_REV:
+ UNSAFE_FOR_PID;
RX_STACK_POP (relocation);
RANGE (-32768, 65535);
#if RX_OPCODE_BIG_ENDIAN
break;
case R_RX_ABS16U:
+ UNSAFE_FOR_PID;
RX_STACK_POP (relocation);
RANGE (0, 65536);
#if RX_OPCODE_BIG_ENDIAN
break;
case R_RX_ABS16UL:
+ UNSAFE_FOR_PID;
RX_STACK_POP (relocation);
relocation >>= 2;
RANGE (0, 65536);
break;
case R_RX_ABS16UW:
+ UNSAFE_FOR_PID;
RX_STACK_POP (relocation);
relocation >>= 1;
RANGE (0, 65536);
break;
case R_RX_ABS8:
+ UNSAFE_FOR_PID;
RX_STACK_POP (relocation);
RANGE (-128, 255);
OP (0) = relocation;
break;
case R_RX_ABS8U:
+ UNSAFE_FOR_PID;
RX_STACK_POP (relocation);
RANGE (0, 255);
OP (0) = relocation;
break;
case R_RX_ABS8UL:
+ UNSAFE_FOR_PID;
RX_STACK_POP (relocation);
relocation >>= 2;
RANGE (0, 255);
break;
case R_RX_ABS8UW:
+ UNSAFE_FOR_PID;
RX_STACK_POP (relocation);
relocation >>= 1;
RANGE (0, 255);
OP (0) = relocation;
break;
- case R_RX_ABS8S_PCREL:
case R_RX_ABS8S:
+ UNSAFE_FOR_PID;
+ case R_RX_ABS8S_PCREL:
RX_STACK_POP (relocation);
RANGE (-128, 127);
OP (0) = relocation;
if (r_symndx < symtab_hdr->sh_info)
RX_STACK_PUSH (sec->output_section->vma
+ sec->output_offset
- + sym->st_value);
+ + sym->st_value
+ + rel->r_addend);
else
{
if (h != NULL
|| h->root.type == bfd_link_hash_defweak))
RX_STACK_PUSH (h->root.u.def.value
+ sec->output_section->vma
- + sec->output_offset);
+ + sec->output_offset
+ + rel->r_addend);
else
_bfd_error_handler (_("Warning: RX_SYM reloc with an unknown symbol"));
}
{
int32_t tmp;
+ saw_subtract = TRUE;
RX_STACK_POP (tmp);
tmp = - tmp;
RX_STACK_PUSH (tmp);
{
int32_t tmp1, tmp2;
+ saw_subtract = TRUE;
RX_STACK_POP (tmp1);
RX_STACK_POP (tmp2);
tmp2 -= tmp1;
if (ssec)
{
if ((ssec->flags & SEC_MERGE)
- && ssec->sec_info_type == ELF_INFO_TYPE_MERGE)
+ && ssec->sec_info_type == SEC_INFO_TYPE_MERGE)
symval = _bfd_merged_section_offset (abfd, & ssec,
elf_section_data (ssec)->sec_info,
symval);
if (shndx_buf == NULL)
goto error_return;
if (bfd_seek (abfd, shndx_hdr->sh_offset, SEEK_SET) != 0
- || bfd_bread ((PTR) shndx_buf, amt, abfd) != amt)
+ || bfd_bread (shndx_buf, amt, abfd) != amt)
goto error_return;
shndx_hdr->contents = (bfd_byte *) shndx_buf;
}
/* Get a copy of the native relocations. */
internal_relocs = (_bfd_elf_link_read_relocs
- (abfd, sec, (PTR) NULL, (Elf_Internal_Rela *) NULL,
+ (abfd, sec, NULL, (Elf_Internal_Rela *) NULL,
link_info->keep_memory));
if (internal_relocs == NULL)
goto error_return;
/* Decodable bits. */
&& (insn[0] & 0xcc) == 0xcc
/* Width. */
- && (insn[0] & 0x30) != 3
+ && (insn[0] & 0x30) != 0x30
/* Register MSBs. */
&& (insn[1] & 0x88) == 0x00)
{
/* Decodable bits. */
&& (insn[0] & 0xc3) == 0xc3
/* Width. */
- && (insn[0] & 0x30) != 3
+ && (insn[0] & 0x30) != 0x30
/* Register MSBs. */
&& (insn[1] & 0x88) == 0x00)
{
ignore_lma = user_ignore_lma;
}
+/* Converts FLAGS into a descriptive string.
+ Returns a static pointer. */
+
+static const char *
+describe_flags (flagword flags)
+{
+ static char buf [128];
+
+ buf[0] = 0;
+
+ if (flags & E_FLAG_RX_64BIT_DOUBLES)
+ strcat (buf, "64-bit doubles");
+ else
+ strcat (buf, "32-bit doubles");
+
+ if (flags & E_FLAG_RX_DSP)
+ strcat (buf, ", dsp");
+ else
+ strcat (buf, ", no dsp");
+
+ if (flags & E_FLAG_RX_PID)
+ strcat (buf, ", pid");
+ else
+ strcat (buf, ", no pid");
+
+ if (flags & E_FLAG_RX_ABI)
+ strcat (buf, ", RX ABI");
+ else
+ strcat (buf, ", GCC ABI");
+
+ return buf;
+}
+
/* Merge backend specific data from an object file to the output
object file when linking. */
}
else if (old_flags != new_flags)
{
- flagword known_flags = E_FLAG_RX_64BIT_DOUBLES | E_FLAG_RX_DSP;
+ flagword known_flags;
+
+ known_flags = E_FLAG_RX_ABI | E_FLAG_RX_64BIT_DOUBLES
+ | E_FLAG_RX_DSP | E_FLAG_RX_PID;
if ((old_flags ^ new_flags) & known_flags)
{
}
else
{
- (*_bfd_error_handler)
- ("ELF header flags mismatch: old_flags = 0x%.8lx, new_flags = 0x%.8lx, filename = %s",
- old_flags, new_flags, bfd_get_filename (ibfd));
+ _bfd_error_handler ("There is a conflict merging the ELF header flags from %s",
+ bfd_get_filename (ibfd));
+ _bfd_error_handler (" the input file's flags: %s",
+ describe_flags (new_flags));
+ _bfd_error_handler (" the output file's flags: %s",
+ describe_flags (old_flags));
error = TRUE;
}
}
flags = elf_elfheader (abfd)->e_flags;
fprintf (file, _("private flags = 0x%lx:"), (long) flags);
- if (flags & E_FLAG_RX_64BIT_DOUBLES)
- fprintf (file, _(" [64-bit doubles]"));
- if (flags & E_FLAG_RX_DSP)
- fprintf (file, _(" [dsp]"));
-
- fputc ('\n', file);
+ fprintf (file, "%s", describe_flags (flags));
return TRUE;
}
/* Return the MACH for an e_flags value. */
static int
-elf32_rx_machine (bfd * abfd)
+elf32_rx_machine (bfd * abfd ATTRIBUTE_UNUSED)
{
+#if 0 /* FIXME: EF_RX_CPU_MASK collides with E_FLAG_RX_...
+ Need to sort out how these flag bits are used.
+ For now we assume that the flags are OK. */
if ((elf_elfheader (abfd)->e_flags & EF_RX_CPU_MASK) == EF_RX_CPU_RX)
+#endif
return bfd_mach_rx;
return 0;
static bfd_boolean
rx_elf_object_p (bfd * abfd)
{
+ int i;
+ unsigned int u;
+ Elf_Internal_Phdr *phdr = elf_tdata (abfd)->phdr;
+ int nphdrs = elf_elfheader (abfd)->e_phnum;
+ sec_ptr bsec;
+ static int saw_be = FALSE;
+
+ /* We never want to automatically choose the non-swapping big-endian
+ target. The user can only get that explicitly, such as with -I
+ and objcopy. */
+ if (abfd->xvec == &rx_elf32_be_ns_vec
+ && abfd->target_defaulted)
+ return FALSE;
+
+ /* BFD->target_defaulted is not set to TRUE when a target is chosen
+ as a fallback, so we check for "scanning" to know when to stop
+ using the non-swapping target. */
+ if (abfd->xvec == &rx_elf32_be_ns_vec
+ && saw_be)
+ return FALSE;
+ if (abfd->xvec == &rx_elf32_be_vec)
+ saw_be = TRUE;
+
bfd_default_set_arch_mach (abfd, bfd_arch_rx,
elf32_rx_machine (abfd));
+
+ /* For each PHDR in the object, we must find some section that
+ corresponds (based on matching file offsets) and use its VMA
+ information to reconstruct the p_vaddr field we clobbered when we
+ wrote it out. */
+ for (i=0; i<nphdrs; i++)
+ {
+ for (u=0; u<elf_tdata(abfd)->num_elf_sections; u++)
+ {
+ Elf_Internal_Shdr *sec = elf_tdata(abfd)->elf_sect_ptr[u];
+
+ if (phdr[i].p_filesz
+ && phdr[i].p_offset <= (bfd_vma) sec->sh_offset
+ && (bfd_vma)sec->sh_offset <= phdr[i].p_offset + (phdr[i].p_filesz - 1))
+ {
+ /* Found one! The difference between the two addresses,
+ plus the difference between the two file offsets, is
+ enough information to reconstruct the lma. */
+
+ /* Example where they aren't:
+ PHDR[1] = lma fffc0100 offset 00002010 size 00000100
+ SEC[6] = vma 00000050 offset 00002050 size 00000040
+
+ The correct LMA for the section is fffc0140 + (2050-2010).
+ */
+
+ phdr[i].p_vaddr = sec->sh_addr + (sec->sh_offset - phdr[i].p_offset);
+ break;
+ }
+ }
+
+ /* We must update the bfd sections as well, so we don't stop
+ with one match. */
+ bsec = abfd->sections;
+ while (bsec)
+ {
+ if (phdr[i].p_filesz
+ && phdr[i].p_vaddr <= bsec->vma
+ && bsec->vma <= phdr[i].p_vaddr + (phdr[i].p_filesz - 1))
+ {
+ bsec->lma = phdr[i].p_paddr + (bsec->vma - phdr[i].p_vaddr);
+ }
+ bsec = bsec->next;
+ }
+ }
+
return TRUE;
}
\f
{
switch (ELF_ST_TYPE (isym->st_info))
{
- case STT_FUNC: st_info_str = "STT_FUNC";
- case STT_SECTION: st_info_str = "STT_SECTION";
- case STT_FILE: st_info_str = "STT_FILE";
- case STT_OBJECT: st_info_str = "STT_OBJECT";
- case STT_TLS: st_info_str = "STT_TLS";
+ case STT_FUNC: st_info_str = "STT_FUNC"; break;
+ case STT_SECTION: st_info_str = "STT_SECTION"; break;
+ case STT_FILE: st_info_str = "STT_FILE"; break;
+ case STT_OBJECT: st_info_str = "STT_OBJECT"; break;
+ case STT_TLS: st_info_str = "STT_TLS"; break;
default: st_info_str = "";
}
switch (ELF_ST_BIND (isym->st_info))
{
- case STB_LOCAL: st_info_stb_str = "STB_LOCAL";
- case STB_GLOBAL: st_info_stb_str = "STB_GLOBAL";
+ case STB_LOCAL: st_info_stb_str = "STB_LOCAL"; break;
+ case STB_GLOBAL: st_info_stb_str = "STB_GLOBAL"; break;
default: st_info_stb_str = "";
}
switch (ELF_ST_VISIBILITY (isym->st_other))
{
- case STV_DEFAULT: st_other_str = "STV_DEFAULT";
- case STV_INTERNAL: st_other_str = "STV_INTERNAL";
- case STV_PROTECTED: st_other_str = "STV_PROTECTED";
+ case STV_DEFAULT: st_other_str = "STV_DEFAULT"; break;
+ case STV_INTERNAL: st_other_str = "STV_INTERNAL"; break;
+ case STV_PROTECTED: st_other_str = "STV_PROTECTED"; break;
default: st_other_str = "";
}
switch (isym->st_shndx)
{
- case SHN_ABS: st_shndx_str = "SHN_ABS";
- case SHN_COMMON: st_shndx_str = "SHN_COMMON";
- case SHN_UNDEF: st_shndx_str = "SHN_UNDEF";
+ case SHN_ABS: st_shndx_str = "SHN_ABS"; break;
+ case SHN_COMMON: st_shndx_str = "SHN_COMMON"; break;
+ case SHN_UNDEF: st_shndx_str = "SHN_UNDEF"; break;
default: st_shndx_str = "";
}
bed = get_elf_backend_data (abfd);
tdata = elf_tdata (abfd);
phdr = tdata->phdr;
- count = tdata->program_header_size / bed->s->sizeof_phdr;
+ count = elf_program_header_size (abfd) / bed->s->sizeof_phdr;
if (ignore_lma)
for (i = count; i-- != 0;)
return TRUE;
}
+
+/* The default literal sections should always be marked as "code" (i.e.,
+ SHF_EXECINSTR). This is particularly important for big-endian mode
+ when we do not want their contents byte reversed. */
+static const struct bfd_elf_special_section elf32_rx_special_sections[] =
+{
+ { STRING_COMMA_LEN (".init_array"), 0, SHT_INIT_ARRAY, SHF_ALLOC + SHF_EXECINSTR },
+ { STRING_COMMA_LEN (".fini_array"), 0, SHT_FINI_ARRAY, SHF_ALLOC + SHF_EXECINSTR },
+ { STRING_COMMA_LEN (".preinit_array"), 0, SHT_PREINIT_ARRAY, SHF_ALLOC + SHF_EXECINSTR },
+ { NULL, 0, 0, 0, 0 }
+};
+\f
+typedef struct {
+ bfd *abfd;
+ struct bfd_link_info *info;
+ bfd_vma table_start;
+ int table_size;
+ bfd_vma *table_handlers;
+ bfd_vma table_default_handler;
+ struct bfd_link_hash_entry **table_entries;
+ struct bfd_link_hash_entry *table_default_entry;
+ FILE *mapfile;
+} RX_Table_Info;
+
+static bfd_boolean
+rx_table_find (struct bfd_hash_entry *vent, void *vinfo)
+{
+ RX_Table_Info *info = (RX_Table_Info *)vinfo;
+ struct bfd_link_hash_entry *ent = (struct bfd_link_hash_entry *)vent;
+ const char *name; /* of the symbol we've found */
+ asection *sec;
+ struct bfd *abfd;
+ int idx;
+ const char *tname; /* name of the table */
+ bfd_vma start_addr, end_addr;
+ char *buf;
+ struct bfd_link_hash_entry * h;
+
+ /* We're looking for globally defined symbols of the form
+ $tablestart$<NAME>. */
+ if (ent->type != bfd_link_hash_defined
+ && ent->type != bfd_link_hash_defweak)
+ return TRUE;
+
+ name = ent->root.string;
+ sec = ent->u.def.section;
+ abfd = sec->owner;
+
+ if (strncmp (name, "$tablestart$", 12))
+ return TRUE;
+
+ sec->flags |= SEC_KEEP;
+
+ tname = name + 12;
+
+ start_addr = ent->u.def.value;
+
+ /* At this point, we can't build the table but we can (and must)
+ find all the related symbols and mark their sections as SEC_KEEP
+ so we don't garbage collect them. */
+
+ buf = (char *) malloc (12 + 10 + strlen (tname));
+
+ sprintf (buf, "$tableend$%s", tname);
+ h = bfd_link_hash_lookup (info->info->hash, buf, FALSE, FALSE, TRUE);
+ if (!h || (h->type != bfd_link_hash_defined
+ && h->type != bfd_link_hash_defweak))
+ {
+ _bfd_error_handler (_("%B:%A: table %s missing corresponding %s"),
+ abfd, sec, name, buf);
+ return TRUE;
+ }
+
+ if (h->u.def.section != ent->u.def.section)
+ {
+ _bfd_error_handler (_("%B:%A: %s and %s must be in the same input section"),
+ h->u.def.section->owner, h->u.def.section,
+ name, buf);
+ return TRUE;
+ }
+
+ end_addr = h->u.def.value;
+
+ sprintf (buf, "$tableentry$default$%s", tname);
+ h = bfd_link_hash_lookup (info->info->hash, buf, FALSE, FALSE, TRUE);
+ if (h && (h->type == bfd_link_hash_defined
+ || h->type == bfd_link_hash_defweak))
+ {
+ h->u.def.section->flags |= SEC_KEEP;
+ }
+
+ for (idx = 0; idx < (int) (end_addr - start_addr) / 4; idx ++)
+ {
+ sprintf (buf, "$tableentry$%d$%s", idx, tname);
+ h = bfd_link_hash_lookup (info->info->hash, buf, FALSE, FALSE, TRUE);
+ if (h && (h->type == bfd_link_hash_defined
+ || h->type == bfd_link_hash_defweak))
+ {
+ h->u.def.section->flags |= SEC_KEEP;
+ }
+ }
+
+ /* Return TRUE to keep scanning, FALSE to end the traversal. */
+ return TRUE;
+}
+
+/* We need to check for table entry symbols and build the tables, and
+ we need to do it before the linker does garbage collection. This function is
+ called once per input object file. */
+static bfd_boolean
+rx_check_directives
+ (bfd * abfd ATTRIBUTE_UNUSED,
+ struct bfd_link_info * info ATTRIBUTE_UNUSED)
+{
+ RX_Table_Info stuff;
+
+ stuff.abfd = abfd;
+ stuff.info = info;
+ bfd_hash_traverse (&(info->hash->table), rx_table_find, &stuff);
+
+ return TRUE;
+}
+
+\f
+static bfd_boolean
+rx_table_map_2 (struct bfd_hash_entry *vent, void *vinfo)
+{
+ RX_Table_Info *info = (RX_Table_Info *)vinfo;
+ struct bfd_link_hash_entry *ent = (struct bfd_link_hash_entry *)vent;
+ int idx;
+ const char *name;
+ bfd_vma addr;
+
+ /* See if the symbol ENT has an address listed in the table, and
+ isn't a debug/special symbol. If so, put it in the table. */
+
+ if (ent->type != bfd_link_hash_defined
+ && ent->type != bfd_link_hash_defweak)
+ return TRUE;
+
+ name = ent->root.string;
+
+ if (name[0] == '$' || name[0] == '.' || name[0] < ' ')
+ return TRUE;
+
+ addr = (ent->u.def.value
+ + ent->u.def.section->output_section->vma
+ + ent->u.def.section->output_offset);
+
+ for (idx = 0; idx < info->table_size; idx ++)
+ if (addr == info->table_handlers[idx])
+ info->table_entries[idx] = ent;
+
+ if (addr == info->table_default_handler)
+ info->table_default_entry = ent;
+
+ return TRUE;
+}
+
+static bfd_boolean
+rx_table_map (struct bfd_hash_entry *vent, void *vinfo)
+{
+ RX_Table_Info *info = (RX_Table_Info *)vinfo;
+ struct bfd_link_hash_entry *ent = (struct bfd_link_hash_entry *)vent;
+ const char *name; /* of the symbol we've found */
+ int idx;
+ const char *tname; /* name of the table */
+ bfd_vma start_addr, end_addr;
+ char *buf;
+ struct bfd_link_hash_entry * h;
+ int need_elipses;
+
+ /* We're looking for globally defined symbols of the form
+ $tablestart$<NAME>. */
+ if (ent->type != bfd_link_hash_defined
+ && ent->type != bfd_link_hash_defweak)
+ return TRUE;
+
+ name = ent->root.string;
+
+ if (strncmp (name, "$tablestart$", 12))
+ return TRUE;
+
+ tname = name + 12;
+ start_addr = (ent->u.def.value
+ + ent->u.def.section->output_section->vma
+ + ent->u.def.section->output_offset);
+
+ buf = (char *) malloc (12 + 10 + strlen (tname));
+
+ sprintf (buf, "$tableend$%s", tname);
+ end_addr = get_symbol_value_maybe (buf, info->info);
+
+ sprintf (buf, "$tableentry$default$%s", tname);
+ h = bfd_link_hash_lookup (info->info->hash, buf, FALSE, FALSE, TRUE);
+ if (h)
+ {
+ info->table_default_handler = (h->u.def.value
+ + h->u.def.section->output_section->vma
+ + h->u.def.section->output_offset);
+ }
+ else
+ /* Zero is a valid handler address! */
+ info->table_default_handler = (bfd_vma) (-1);
+ info->table_default_entry = NULL;
+
+ info->table_start = start_addr;
+ info->table_size = (int) (end_addr - start_addr) / 4;
+ info->table_handlers = (bfd_vma *) malloc (info->table_size * sizeof (bfd_vma));
+ info->table_entries = (struct bfd_link_hash_entry **) malloc (info->table_size * sizeof (struct bfd_link_hash_entry));
+
+ for (idx = 0; idx < (int) (end_addr - start_addr) / 4; idx ++)
+ {
+ sprintf (buf, "$tableentry$%d$%s", idx, tname);
+ h = bfd_link_hash_lookup (info->info->hash, buf, FALSE, FALSE, TRUE);
+ if (h && (h->type == bfd_link_hash_defined
+ || h->type == bfd_link_hash_defweak))
+ {
+ info->table_handlers[idx] = (h->u.def.value
+ + h->u.def.section->output_section->vma
+ + h->u.def.section->output_offset);
+ }
+ else
+ info->table_handlers[idx] = info->table_default_handler;
+ info->table_entries[idx] = NULL;
+ }
+
+ free (buf);
+
+ bfd_hash_traverse (&(info->info->hash->table), rx_table_map_2, info);
+
+ fprintf (info->mapfile, "\nRX Vector Table: %s has %d entries at 0x%08" BFD_VMA_FMT "x\n\n",
+ tname, info->table_size, start_addr);
+
+ if (info->table_default_entry)
+ fprintf (info->mapfile, " default handler is: %s at 0x%08" BFD_VMA_FMT "x\n",
+ info->table_default_entry->root.string,
+ info->table_default_handler);
+ else if (info->table_default_handler != (bfd_vma)(-1))
+ fprintf (info->mapfile, " default handler is at 0x%08" BFD_VMA_FMT "x\n",
+ info->table_default_handler);
+ else
+ fprintf (info->mapfile, " no default handler\n");
+
+ need_elipses = 1;
+ for (idx = 0; idx < info->table_size; idx ++)
+ {
+ if (info->table_handlers[idx] == info->table_default_handler)
+ {
+ if (need_elipses)
+ fprintf (info->mapfile, " . . .\n");
+ need_elipses = 0;
+ continue;
+ }
+ need_elipses = 1;
+
+ fprintf (info->mapfile, " 0x%08" BFD_VMA_FMT "x [%3d] ", start_addr + 4 * idx, idx);
+
+ if (info->table_handlers[idx] == (bfd_vma) (-1))
+ fprintf (info->mapfile, "(no handler found)\n");
+
+ else if (info->table_handlers[idx] == info->table_default_handler)
+ {
+ if (info->table_default_entry)
+ fprintf (info->mapfile, "(default)\n");
+ else
+ fprintf (info->mapfile, "(default)\n");
+ }
+
+ else if (info->table_entries[idx])
+ {
+ fprintf (info->mapfile, "0x%08" BFD_VMA_FMT "x %s\n", info->table_handlers[idx], info->table_entries[idx]->root.string);
+ }
+
+ else
+ {
+ fprintf (info->mapfile, "0x%08" BFD_VMA_FMT "x ???\n", info->table_handlers[idx]);
+ }
+ }
+ if (need_elipses)
+ fprintf (info->mapfile, " . . .\n");
+
+ return TRUE;
+}
+
+void
+rx_additional_link_map_text (bfd *obfd, struct bfd_link_info *info, FILE *mapfile)
+{
+ /* We scan the symbol table looking for $tableentry$'s, and for
+ each, try to deduce which handlers go with which entries. */
+
+ RX_Table_Info stuff;
+
+ stuff.abfd = obfd;
+ stuff.info = info;
+ stuff.mapfile = mapfile;
+ bfd_hash_traverse (&(info->hash->table), rx_table_map, &stuff);
+}
+
\f
#define ELF_ARCH bfd_arch_rx
#define ELF_MACHINE_CODE EM_RX
#define ELF_MAXPAGESIZE 0x1000
-#define TARGET_BIG_SYM bfd_elf32_rx_be_vec
+#define TARGET_BIG_SYM rx_elf32_be_vec
#define TARGET_BIG_NAME "elf32-rx-be"
-#define TARGET_LITTLE_SYM bfd_elf32_rx_le_vec
+#define TARGET_LITTLE_SYM rx_elf32_le_vec
#define TARGET_LITTLE_NAME "elf32-rx-le"
#define elf_info_to_howto_rel NULL
#define bfd_elf32_set_section_contents rx_set_section_contents
#define bfd_elf32_bfd_final_link rx_final_link
#define bfd_elf32_bfd_relax_section elf32_rx_relax_section_wrapper
+#define elf_backend_special_sections elf32_rx_special_sections
+#define elf_backend_check_directives rx_check_directives
+
+#include "elf32-target.h"
+
+/* We define a second big-endian target that doesn't have the custom
+ section get/set hooks, for times when we want to preserve the
+ pre-swapped .text sections (like objcopy). */
+
+#undef TARGET_BIG_SYM
+#define TARGET_BIG_SYM rx_elf32_be_ns_vec
+#undef TARGET_BIG_NAME
+#define TARGET_BIG_NAME "elf32-rx-be-ns"
+#undef TARGET_LITTLE_SYM
+
+#undef bfd_elf32_get_section_contents
+#undef bfd_elf32_set_section_contents
+
+#undef elf32_bed
+#define elf32_bed elf32_rx_be_ns_bed
#include "elf32-target.h"