X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Felf32-rx.c;h=49556d2831ec79c709cebde23a9cf7370a62e4f6;hb=c88960d081f0b37ec03c66a13115e2a68e40d1ad;hp=4b31a35a778a61c18825e4bf5f75fcbd1fbc223e;hpb=9ccb8af972518810c66317c6c942d2268bfb5123;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elf32-rx.c b/bfd/elf32-rx.c index 4b31a35a77..49556d2831 100644 --- a/bfd/elf32-rx.c +++ b/bfd/elf32-rx.c @@ -1,6 +1,5 @@ /* Renesas RX specific support for 32-bit ELF. - Copyright (C) 2008, 2009, 2010 - Free Software Foundation, Inc. + Copyright (C) 2008-2016 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. @@ -20,13 +19,21 @@ #include "sysdep.h" #include "bfd.h" +#include "bfd_stdint.h" #include "libbfd.h" #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 *); @@ -42,7 +49,7 @@ void rx_dump_symtab (bfd *, void *, void *); static reloc_howto_type rx_elf_howto_table [] = { - RXREL (NONE, 0, 0, 0, dont, FALSE), + RXREL (NONE, 3, 0, 0, dont, FALSE), RXREL (DIR32, 2, 32, 0, signed, FALSE), RXREL (DIR24S, 2, 24, 0, signed, FALSE), RXREL (DIR16, 1, 16, 0, dont, FALSE), @@ -248,9 +255,12 @@ static const struct rx_reloc_map rx_reloc_map [] = { BFD_RELOC_RX_RELAX, R_RX_RH_RELAX }, { BFD_RELOC_RX_SYM, R_RX_SYM }, { BFD_RELOC_RX_OP_SUBTRACT, R_RX_OPsub }, + { BFD_RELOC_RX_OP_NEG, R_RX_OPneg }, { BFD_RELOC_RX_ABS8, R_RX_ABS8 }, { BFD_RELOC_RX_ABS16, R_RX_ABS16 }, + { BFD_RELOC_RX_ABS16_REV, R_RX_ABS16_REV }, { BFD_RELOC_RX_ABS32, R_RX_ABS32 }, + { BFD_RELOC_RX_ABS32_REV, R_RX_ABS32_REV }, { BFD_RELOC_RX_ABS16UL, R_RX_ABS16UL }, { BFD_RELOC_RX_ABS16UW, R_RX_ABS16UW }, { BFD_RELOC_RX_ABS16U, R_RX_ABS16U } @@ -267,7 +277,7 @@ rx_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED, if (code == BFD_RELOC_RX_32_OP) return rx_elf_howto_table + R_RX_DIR32; - for (i = ARRAY_SIZE (rx_reloc_map); --i;) + for (i = ARRAY_SIZE (rx_reloc_map); i--;) if (rx_reloc_map [i].bfd_reloc_val == code) return rx_elf_howto_table + rx_reloc_map[i].rx_reloc_val; @@ -297,13 +307,16 @@ rx_info_to_howto_rela (bfd * abfd ATTRIBUTE_UNUSED, 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 (_("%B: invalid RX reloc number: %d"), abfd, r_type); + r_type = 0; + } cache_ptr->howto = rx_elf_howto_table + r_type; } static bfd_vma get_symbol_value (const char * name, - bfd_reloc_status_type * status, struct bfd_link_info * info, bfd * input_bfd, asection * input_section, @@ -317,7 +330,7 @@ get_symbol_value (const char * name, if (h == NULL || (h->type != bfd_link_hash_defined && h->type != bfd_link_hash_defweak)) - * status = info->callbacks->undefined_symbol + (*info->callbacks->undefined_symbol) (info, name, input_bfd, input_section, offset, TRUE); else value = (h->u.def.value @@ -328,8 +341,28 @@ get_symbol_value (const char * name, } static bfd_vma -get_gp (bfd_reloc_status_type * status, - struct bfd_link_info * info, +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 (struct bfd_link_info * info, bfd * abfd, asection * sec, int offset) @@ -339,15 +372,14 @@ get_gp (bfd_reloc_status_type * status, if (!cached) { - cached_value = get_symbol_value ("__gp", status, info, abfd, sec, offset); + cached_value = get_symbol_value ("__gp", info, abfd, sec, offset); cached = TRUE; } return cached_value; } static bfd_vma -get_romstart (bfd_reloc_status_type * status, - struct bfd_link_info * info, +get_romstart (struct bfd_link_info * info, bfd * abfd, asection * sec, int offset) @@ -357,15 +389,14 @@ get_romstart (bfd_reloc_status_type * status, if (!cached) { - cached_value = get_symbol_value ("_start", status, info, abfd, sec, offset); + cached_value = get_symbol_value ("_start", info, abfd, sec, offset); cached = TRUE; } return cached_value; } static bfd_vma -get_ramstart (bfd_reloc_status_type * status, - struct bfd_link_info * info, +get_ramstart (struct bfd_link_info * info, bfd * abfd, asection * sec, int offset) @@ -375,7 +406,7 @@ get_ramstart (bfd_reloc_status_type * status, if (!cached) { - cached_value = get_symbol_value ("__datastart", status, info, abfd, sec, offset); + cached_value = get_symbol_value ("__datastart", info, abfd, sec, offset); cached = TRUE; } return cached_value; @@ -453,6 +484,16 @@ rx_elf_relocate_section 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); @@ -479,6 +520,9 @@ rx_elf_relocate_section sec = NULL; relocation = 0; + if (rx_stack_top == 0) + saw_subtract = FALSE; + if (r_symndx < symtab_hdr->sh_info) { sym = local_syms + r_symndx; @@ -491,28 +535,96 @@ rx_elf_relocate_section } 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) { - /* For relocs against symbols from removed linkonce sections, - or sections discarded by a linker script, we just want the - section contents zeroed. Avoid any special processing. */ - _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset); - rel->r_info = 0; - rel->r_addend = 0; - continue; + bfd_vma entry_vma; + int idx; + char *buf; + + 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); + table_start_cache = get_symbol_value (buf, + info, + input_bfd, + input_section, + rel->r_offset); + + sprintf (buf, "$tableend$%s", name + 20); + table_end_cache = get_symbol_value (buf, + 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$$ */ + 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 (info->relocatable) + if (sec != NULL && discarded_section (sec)) + RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, + rel, 1, relend, howto, 0, contents); + + if (bfd_link_relocatable (info)) { /* This is a relocatable link. We don't have to change anything, unless the reloc is against a section symbol, @@ -551,6 +663,28 @@ rx_elf_relocate_section _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) { @@ -571,16 +705,19 @@ rx_elf_relocate_section 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; @@ -589,6 +726,7 @@ rx_elf_relocate_section 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 @@ -599,6 +737,7 @@ rx_elf_relocate_section 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; @@ -610,6 +749,7 @@ rx_elf_relocate_section break; case R_RX_DIR16S: + UNSAFE_FOR_PID; RANGE (-32768, 65535); if (BIGE (output_bfd) && !(input_section->flags & SEC_CODE)) { @@ -624,6 +764,7 @@ rx_elf_relocate_section break; case R_RX_DIR16U: + UNSAFE_FOR_PID; RANGE (0, 65536); #if RX_OPCODE_BIG_ENDIAN OP (1) = relocation; @@ -635,6 +776,7 @@ rx_elf_relocate_section break; case R_RX_DIR16: + UNSAFE_FOR_PID; RANGE (-32768, 65536); #if RX_OPCODE_BIG_ENDIAN OP (1) = relocation; @@ -646,6 +788,7 @@ rx_elf_relocate_section break; case R_RX_DIR16_REV: + UNSAFE_FOR_PID; RANGE (-32768, 65536); #if RX_OPCODE_BIG_ENDIAN OP (0) = relocation; @@ -663,6 +806,7 @@ rx_elf_relocate_section break; case R_RX_RH_24_NEG: + UNSAFE_FOR_PID; WARN_REDHAT ("RX_RH_24_NEG"); relocation = - relocation; case R_RX_DIR24S_PCREL: @@ -679,6 +823,7 @@ rx_elf_relocate_section break; case R_RX_RH_24_OP: + UNSAFE_FOR_PID; WARN_REDHAT ("RX_RH_24_OP"); RANGE (-0x800000, 0x7fffff); #if RX_OPCODE_BIG_ENDIAN @@ -693,6 +838,7 @@ rx_elf_relocate_section break; case R_RX_DIR24S: + UNSAFE_FOR_PID; RANGE (-0x800000, 0x7fffff); if (BIGE (output_bfd) && !(input_section->flags & SEC_CODE)) { @@ -709,6 +855,7 @@ rx_elf_relocate_section break; case R_RX_RH_24_UNS: + UNSAFE_FOR_PID; WARN_REDHAT ("RX_RH_24_UNS"); RANGE (0, 0xffffff); #if RX_OPCODE_BIG_ENDIAN @@ -723,6 +870,7 @@ rx_elf_relocate_section break; case R_RX_RH_32_NEG: + UNSAFE_FOR_PID; WARN_REDHAT ("RX_RH_32_NEG"); relocation = - relocation; #if RX_OPCODE_BIG_ENDIAN @@ -739,6 +887,7 @@ rx_elf_relocate_section break; case R_RX_RH_32_OP: + UNSAFE_FOR_PID; WARN_REDHAT ("RX_RH_32_OP"); #if RX_OPCODE_BIG_ENDIAN OP (3) = relocation; @@ -799,7 +948,7 @@ rx_elf_relocate_section case R_RX_RH_GPRELB: WARN_REDHAT ("RX_RH_GPRELB"); - relocation -= get_gp (&r, info, input_bfd, input_section, rel->r_offset); + relocation -= get_gp (info, input_bfd, input_section, rel->r_offset); RANGE (0, 65535); #if RX_OPCODE_BIG_ENDIAN OP (1) = relocation; @@ -812,7 +961,7 @@ rx_elf_relocate_section case R_RX_RH_GPRELW: WARN_REDHAT ("RX_RH_GPRELW"); - relocation -= get_gp (&r, info, input_bfd, input_section, rel->r_offset); + relocation -= get_gp (info, input_bfd, input_section, rel->r_offset); ALIGN (1); relocation >>= 1; RANGE (0, 65535); @@ -827,7 +976,7 @@ rx_elf_relocate_section case R_RX_RH_GPRELL: WARN_REDHAT ("RX_RH_GPRELL"); - relocation -= get_gp (&r, info, input_bfd, input_section, rel->r_offset); + relocation -= get_gp (info, input_bfd, input_section, rel->r_offset); ALIGN (3); relocation >>= 2; RANGE (0, 65535); @@ -918,6 +1067,7 @@ rx_elf_relocate_section /* Complex reloc handling: */ case R_RX_ABS32: + UNSAFE_FOR_PID; RX_STACK_POP (relocation); #if RX_OPCODE_BIG_ENDIAN OP (3) = relocation; @@ -933,6 +1083,7 @@ rx_elf_relocate_section break; case R_RX_ABS32_REV: + UNSAFE_FOR_PID; RX_STACK_POP (relocation); #if RX_OPCODE_BIG_ENDIAN OP (0) = relocation; @@ -949,6 +1100,7 @@ rx_elf_relocate_section 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)) @@ -966,6 +1118,7 @@ rx_elf_relocate_section break; case R_RX_ABS16: + UNSAFE_FOR_PID; RX_STACK_POP (relocation); RANGE (-32768, 65535); #if RX_OPCODE_BIG_ENDIAN @@ -978,6 +1131,7 @@ rx_elf_relocate_section break; case R_RX_ABS16_REV: + UNSAFE_FOR_PID; RX_STACK_POP (relocation); RANGE (-32768, 65535); #if RX_OPCODE_BIG_ENDIAN @@ -1006,6 +1160,7 @@ rx_elf_relocate_section break; case R_RX_ABS16U: + UNSAFE_FOR_PID; RX_STACK_POP (relocation); RANGE (0, 65536); #if RX_OPCODE_BIG_ENDIAN @@ -1018,6 +1173,7 @@ rx_elf_relocate_section break; case R_RX_ABS16UL: + UNSAFE_FOR_PID; RX_STACK_POP (relocation); relocation >>= 2; RANGE (0, 65536); @@ -1031,6 +1187,7 @@ rx_elf_relocate_section break; case R_RX_ABS16UW: + UNSAFE_FOR_PID; RX_STACK_POP (relocation); relocation >>= 1; RANGE (0, 65536); @@ -1044,18 +1201,21 @@ rx_elf_relocate_section 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); @@ -1063,14 +1223,16 @@ rx_elf_relocate_section 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; @@ -1080,7 +1242,8 @@ rx_elf_relocate_section 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 @@ -1088,7 +1251,8 @@ rx_elf_relocate_section || 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")); } @@ -1098,6 +1262,7 @@ rx_elf_relocate_section { int32_t tmp; + saw_subtract = TRUE; RX_STACK_POP (tmp); tmp = - tmp; RX_STACK_PUSH (tmp); @@ -1119,6 +1284,7 @@ rx_elf_relocate_section { int32_t tmp1, tmp2; + saw_subtract = TRUE; RX_STACK_POP (tmp1); RX_STACK_POP (tmp2); tmp2 -= tmp1; @@ -1233,11 +1399,11 @@ rx_elf_relocate_section break; case R_RX_OPromtop: - RX_STACK_PUSH (get_romstart (&r, info, input_bfd, input_section, rel->r_offset)); + RX_STACK_PUSH (get_romstart (info, input_bfd, input_section, rel->r_offset)); break; case R_RX_OPramtop: - RX_STACK_PUSH (get_ramstart (&r, info, input_bfd, input_section, rel->r_offset)); + RX_STACK_PUSH (get_ramstart (info, input_bfd, input_section, rel->r_offset)); break; default: @@ -1257,15 +1423,14 @@ rx_elf_relocate_section if (r_type == R_RX_DIR24S_PCREL) msg = _("%B(%A): error: call to undefined function '%s'"); else - r = info->callbacks->reloc_overflow + (*info->callbacks->reloc_overflow) (info, (h ? &h->root : NULL), name, howto->name, (bfd_vma) 0, input_bfd, input_section, rel->r_offset); break; case bfd_reloc_undefined: - r = info->callbacks->undefined_symbol - (info, name, input_bfd, input_section, rel->r_offset, - TRUE); + (*info->callbacks->undefined_symbol) + (info, name, input_bfd, input_section, rel->r_offset, TRUE); break; case bfd_reloc_other: @@ -1291,9 +1456,6 @@ rx_elf_relocate_section if (msg) _bfd_error_handler (msg, input_bfd, input_section, name); - - if (! r) - return FALSE; } } @@ -1357,7 +1519,8 @@ next_smaller_reloc (int r) static bfd_boolean elf32_rx_relax_delete_bytes (bfd *abfd, asection *sec, bfd_vma addr, int count, - Elf_Internal_Rela *alignment_rel, int force_snip) + Elf_Internal_Rela *alignment_rel, int force_snip, + Elf_Internal_Rela *irelstart) { Elf_Internal_Shdr * symtab_hdr; unsigned int sec_shndx; @@ -1384,8 +1547,7 @@ elf32_rx_relax_delete_bytes (bfd *abfd, asection *sec, bfd_vma addr, int count, if (alignment_rel) toaddr = alignment_rel->r_offset; - irel = elf_section_data (sec)->relocs; - irelend = irel + sec->reloc_count; + BFD_ASSERT (toaddr > addr); /* Actually delete the bytes. */ memmove (contents + addr, contents + addr + count, @@ -1399,8 +1561,12 @@ elf32_rx_relax_delete_bytes (bfd *abfd, asection *sec, bfd_vma addr, int count, else memset (contents + toaddr - count, 0x03, count); + irel = irelstart; + BFD_ASSERT (irel != NULL || sec->reloc_count == 0); + irelend = irel + sec->reloc_count; + /* Adjust all the relocs. */ - for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++) + for (; irel < irelend; irel++) { /* Get the new reloc address. */ if (irel->r_offset > addr @@ -1586,7 +1752,7 @@ rx_offset_for_reloc (bfd * abfd, 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); @@ -1724,11 +1890,11 @@ rx_offset_for_reloc (bfd * abfd, break; case R_RX_OPromtop: - RX_STACK_PUSH (get_romstart (&r, info, input_bfd, input_section, rel->r_offset)); + RX_STACK_PUSH (get_romstart (info, input_bfd, input_section, rel->r_offset)); break; case R_RX_OPramtop: - RX_STACK_PUSH (get_ramstart (&r, info, input_bfd, input_section, rel->r_offset)); + RX_STACK_PUSH (get_ramstart (info, input_bfd, input_section, rel->r_offset)); break; case R_RX_DIR16UL: @@ -1763,6 +1929,8 @@ rx_offset_for_reloc (bfd * abfd, rel ++; } + /* FIXME. */ + (void) r; } static void @@ -1791,7 +1959,6 @@ elf32_rx_relax_section (bfd * abfd, Elf_Internal_Shdr * symtab_hdr; Elf_Internal_Shdr * shndx_hdr; Elf_Internal_Rela * internal_relocs; - Elf_Internal_Rela * free_relocs = NULL; Elf_Internal_Rela * irel; Elf_Internal_Rela * srel; Elf_Internal_Rela * irelend; @@ -1817,14 +1984,17 @@ elf32_rx_relax_section (bfd * abfd, /* We don't have to do anything for a relocatable link, if this section does not have relocs, or if this is not a code section. */ - if (link_info->relocatable + if (bfd_link_relocatable (link_info) || (sec->flags & SEC_RELOC) == 0 || sec->reloc_count == 0 || (sec->flags & SEC_CODE) == 0) return TRUE; - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr; + symtab_hdr = & elf_symtab_hdr (abfd); + if (elf_symtab_shndx_list (abfd)) + shndx_hdr = & elf_symtab_shndx_list (abfd)->hdr; + else + shndx_hdr = NULL; sec_start = sec->output_section->vma + sec->output_offset; @@ -1849,7 +2019,7 @@ elf32_rx_relax_section (bfd * abfd, symtab_hdr->contents = (bfd_byte *) intsyms; } - if (shndx_hdr->sh_size != 0) + if (shndx_hdr && shndx_hdr->sh_size != 0) { bfd_size_type amt; @@ -1859,19 +2029,21 @@ elf32_rx_relax_section (bfd * abfd, 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, - link_info->keep_memory)); + /* Note - we ignore the setting of link_info->keep_memory when reading + in these relocs. We have to maintain a permanent copy of the relocs + because we are going to walk over them multiple times, adjusting them + as bytes are deleted from the section, and with this relaxation + function itself being called multiple times on the same section... */ + internal_relocs = _bfd_elf_link_read_relocs + (abfd, sec, NULL, (Elf_Internal_Rela *) NULL, TRUE); if (internal_relocs == NULL) goto error_return; - if (! link_info->keep_memory) - free_relocs = internal_relocs; /* The RL_ relocs must be just before the operand relocs they go with, so we must sort them to guarantee this. We use bubblesort @@ -1961,7 +2133,7 @@ elf32_rx_relax_section (bfd * abfd, nbytes *= alignment; elf32_rx_relax_delete_bytes (abfd, sec, erel->r_offset-nbytes, nbytes, next_alignment, - erel->r_offset == sec->size); + erel->r_offset == sec->size, internal_relocs); *again = TRUE; continue; @@ -2000,7 +2172,7 @@ elf32_rx_relax_section (bfd * abfd, nrelocs --; #define SNIPNR(offset, nbytes) \ - elf32_rx_relax_delete_bytes (abfd, sec, (insn - contents) + offset, nbytes, next_alignment, 0); + elf32_rx_relax_delete_bytes (abfd, sec, (insn - contents) + offset, nbytes, next_alignment, 0, internal_relocs); #define SNIP(offset, nbytes, newtype) \ SNIPNR (offset, nbytes); \ srel->r_info = ELF32_R_INFO (ELF32_R_SYM (srel->r_info), newtype) @@ -2048,7 +2220,7 @@ elf32_rx_relax_section (bfd * abfd, /* Decodable bits. */ && (insn[0] & 0xcc) == 0xcc /* Width. */ - && (insn[0] & 0x30) != 3 + && (insn[0] & 0x30) != 0x30 /* Register MSBs. */ && (insn[1] & 0x88) == 0x00) { @@ -2152,7 +2324,7 @@ elf32_rx_relax_section (bfd * abfd, /* Decodable bits. */ && (insn[0] & 0xc3) == 0xc3 /* Width. */ - && (insn[0] & 0x30) != 3 + && (insn[0] & 0x30) != 0x30 /* Register MSBs. */ && (insn[1] & 0x88) == 0x00) { @@ -2820,9 +2992,6 @@ elf32_rx_relax_section (bfd * abfd, return TRUE; error_return: - if (free_relocs != NULL) - free (free_relocs); - if (free_contents != NULL) free (free_contents); @@ -2858,13 +3027,52 @@ rx_elf_set_private_flags (bfd * abfd, flagword flags) } static bfd_boolean no_warn_mismatch = FALSE; +static bfd_boolean ignore_lma = TRUE; -void bfd_elf32_rx_set_target_flags (bfd_boolean); +void bfd_elf32_rx_set_target_flags (bfd_boolean, bfd_boolean); void -bfd_elf32_rx_set_target_flags (bfd_boolean user_no_warn_mismatch) +bfd_elf32_rx_set_target_flags (bfd_boolean user_no_warn_mismatch, + bfd_boolean user_ignore_lma) { no_warn_mismatch = user_no_warn_mismatch; + 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"); + + if (flags & E_FLAG_RX_SINSNS_SET) + strcat (buf, flags & E_FLAG_RX_SINSNS_YES ? ", uses String instructions" : ", bans String instructions"); + + return buf; } /* Merge backend specific data from an object file to the output @@ -2888,7 +3096,24 @@ rx_elf_merge_private_bfd_data (bfd * ibfd, bfd * obfd) } else if (old_flags != new_flags) { - flagword known_flags = E_FLAG_RX_64BIT_DOUBLES | E_FLAG_RX_DSP; + flagword known_flags; + + if (old_flags & E_FLAG_RX_SINSNS_SET) + { + if ((new_flags & E_FLAG_RX_SINSNS_SET) == 0) + { + new_flags &= ~ E_FLAG_RX_SINSNS_MASK; + new_flags |= (old_flags & E_FLAG_RX_SINSNS_MASK); + } + } + else if (new_flags & E_FLAG_RX_SINSNS_SET) + { + old_flags &= ~ E_FLAG_RX_SINSNS_MASK; + old_flags |= (new_flags & E_FLAG_RX_SINSNS_MASK); + } + + known_flags = E_FLAG_RX_ABI | E_FLAG_RX_64BIT_DOUBLES + | E_FLAG_RX_DSP | E_FLAG_RX_PID | E_FLAG_RX_SINSNS_MASK; if ((old_flags ^ new_flags) & known_flags) { @@ -2901,9 +3126,12 @@ rx_elf_merge_private_bfd_data (bfd * ibfd, bfd * obfd) } 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; } } @@ -2931,21 +3159,20 @@ rx_elf_print_private_bfd_data (bfd * abfd, void * ptr) 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; @@ -2954,8 +3181,79 @@ elf32_rx_machine (bfd * abfd) 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; inum_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 + && sec->sh_size > 0 + && sec->sh_type != SHT_NOBITS + && (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; } @@ -3000,31 +3298,31 @@ rx_dump_symtab (bfd * abfd, void * internal_syms, void * external_syms) { 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 = ""; } @@ -3240,7 +3538,7 @@ rx_set_section_contents (bfd * abfd, if (! rv) return rv; - location ++; + location = (bfd_byte *) location + 1; offset ++; count --; caddr ++; @@ -3266,7 +3564,7 @@ rx_set_section_contents (bfd * abfd, } count -= scount; - location += scount; + location = (bfd_byte *) location + scount; offset += scount; if (count > 0) @@ -3285,7 +3583,7 @@ rx_set_section_contents (bfd * abfd, if (! rv) return rv; - location ++; + location = (bfd_byte *) location + 1; offset ++; count --; caddr ++; @@ -3308,13 +3606,12 @@ rx_final_link (bfd * abfd, struct bfd_link_info * info) #endif if (o->flags & SEC_CODE && bfd_big_endian (abfd) - && (o->size % 4 || o->rawsize % 4)) + && o->size % 4) { #ifdef DJDEBUG fprintf (stderr, "adjusting...\n"); #endif o->size += 4 - (o->size % 4); - o->rawsize += 4 - (o->rawsize % 4); } } @@ -3334,36 +3631,337 @@ elf32_rx_modify_program_headers (bfd * abfd ATTRIBUTE_UNUSED, bed = get_elf_backend_data (abfd); tdata = elf_tdata (abfd); phdr = tdata->phdr; - count = tdata->program_header_size / bed->s->sizeof_phdr; - - for (i = count; i-- != 0; ) - if (phdr[i].p_type == PT_LOAD) - { - /* The Renesas tools expect p_paddr to be zero. However, - there is no other way to store the writable data in ROM for - startup initialization. So, we let the linker *think* - we're using paddr and vaddr the "usual" way, but at the - last minute we move the paddr into the vaddr (which is what - the simulator uses) and zero out paddr. Note that this - does not affect the section headers, just the program - headers. We hope. */ + count = elf_program_header_size (abfd) / bed->s->sizeof_phdr; + + if (ignore_lma) + for (i = count; i-- != 0;) + if (phdr[i].p_type == PT_LOAD) + { + /* The Renesas tools expect p_paddr to be zero. However, + there is no other way to store the writable data in ROM for + startup initialization. So, we let the linker *think* + we're using paddr and vaddr the "usual" way, but at the + last minute we move the paddr into the vaddr (which is what + the simulator uses) and zero out paddr. Note that this + does not affect the section headers, just the program + headers. We hope. */ phdr[i].p_vaddr = phdr[i].p_paddr; - /* If we zero out p_paddr, then the LMA in the section table +#if 0 /* If we zero out p_paddr, then the LMA in the section table becomes wrong. */ - /*phdr[i].p_paddr = 0;*/ - } + phdr[i].p_paddr = 0; +#endif + } 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 } +}; + +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$. */ + 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; +} + + +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$. */ + 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); +} + #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 @@ -3383,5 +3981,25 @@ elf32_rx_modify_program_headers (bfd * abfd ATTRIBUTE_UNUSED, #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"