diff options
Diffstat (limited to 'bfd/elf32-ppc.c')
-rw-r--r-- | bfd/elf32-ppc.c | 646 |
1 files changed, 560 insertions, 86 deletions
diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c index d00a7b2..c55c396 100644 --- a/bfd/elf32-ppc.c +++ b/bfd/elf32-ppc.c @@ -25,19 +25,39 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "bfd.h" #include "sysdep.h" +#include "bfdlink.h" #include "libbfd.h" #include "libelf.h" +#include "elf/ppc.h" static bfd_reloc_status_type ppc_elf_unsupported_reloc PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **)); +static bfd_reloc_status_type ppc_elf_std_reloc + PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **)); + +static bfd_vma ppc_elf_addr16_ha_inner PARAMS ((asection *, bfd_vma, bfd_vma)); static bfd_reloc_status_type ppc_elf_addr16_ha_reloc PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **)); +static bfd_vma ppc_elf_got16_inner PARAMS ((asection *sec)); static bfd_reloc_status_type ppc_elf_got16_reloc PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **)); -static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup +static reloc_howto_type *ppc_elf_reloc_type_lookup PARAMS ((bfd *abfd, bfd_reloc_code_real_type code)); -static void powerpc_info_to_howto +static void ppc_elf_info_to_howto PARAMS ((bfd *abfd, arelent *cache_ptr, Elf32_Internal_Rela *dst)); +static void ppc_elf_howto_init PARAMS ((void)); +static boolean ppc_elf_set_private_flags PARAMS ((bfd *, flagword)); +static boolean ppc_elf_copy_private_bfd_data PARAMS ((bfd *, bfd *)); +static boolean ppc_elf_merge_private_bfd_data PARAMS ((bfd *, bfd *)); + +static boolean ppc_elf_relocate_section PARAMS ((bfd *, + struct bfd_link_info *info, + bfd *, + asection *, + bfd_byte *, + Elf_Internal_Rela *relocs, + Elf_Internal_Sym *local_syms, + asection **)); #define USE_RELA @@ -104,7 +124,10 @@ enum reloc_type R_PPC_max }; -static reloc_howto_type elf_powerpc_howto_table[] = + +static reloc_howto_type *ppc_elf_howto_table[ (int)R_PPC_max ]; + +static reloc_howto_type ppc_elf_howto_raw[] = { /* This reloc does nothing. */ HOWTO (R_PPC_NONE, /* type */ @@ -114,7 +137,7 @@ static reloc_howto_type elf_powerpc_howto_table[] = false, /* pc_relative */ 0, /* bitpos */ complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + ppc_elf_std_reloc, /* special_function */ "R_PPC_NONE", /* name */ false, /* partial_inplace */ 0, /* src_mask */ @@ -129,7 +152,7 @@ static reloc_howto_type elf_powerpc_howto_table[] = false, /* pc_relative */ 0, /* bitpos */ complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + ppc_elf_std_reloc, /* special_function */ "R_PPC_ADDR32", /* name */ false, /* partial_inplace */ 0, /* src_mask */ @@ -145,7 +168,7 @@ static reloc_howto_type elf_powerpc_howto_table[] = false, /* pc_relative */ 0, /* bitpos */ complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + ppc_elf_std_reloc, /* special_function */ "R_PPC_ADDR24", /* name */ false, /* partial_inplace */ 0, /* src_mask */ @@ -160,7 +183,7 @@ static reloc_howto_type elf_powerpc_howto_table[] = false, /* pc_relative */ 0, /* bitpos */ complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + ppc_elf_std_reloc, /* special_function */ "R_PPC_ADDR16", /* name */ false, /* partial_inplace */ 0, /* src_mask */ @@ -175,7 +198,7 @@ static reloc_howto_type elf_powerpc_howto_table[] = false, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + ppc_elf_std_reloc, /* special_function */ "R_PPC_ADDR16_LO", /* name */ false, /* partial_inplace */ 0, /* src_mask */ @@ -190,7 +213,7 @@ static reloc_howto_type elf_powerpc_howto_table[] = false, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + ppc_elf_std_reloc, /* special_function */ "R_PPC_ADDR16_HI", /* name */ false, /* partial_inplace */ 0, /* src_mask */ @@ -222,7 +245,7 @@ static reloc_howto_type elf_powerpc_howto_table[] = false, /* pc_relative */ 0, /* bitpos */ complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + ppc_elf_std_reloc, /* special_function */ "R_PPC_ADDR14", /* name */ false, /* partial_inplace */ 0, /* src_mask */ @@ -271,7 +294,7 @@ static reloc_howto_type elf_powerpc_howto_table[] = true, /* pc_relative */ 0, /* bitpos */ complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + ppc_elf_std_reloc, /* special_function */ "R_PPC_REL24", /* name */ false, /* partial_inplace */ 0, /* src_mask */ @@ -286,7 +309,7 @@ static reloc_howto_type elf_powerpc_howto_table[] = true, /* pc_relative */ 0, /* bitpos */ complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + ppc_elf_std_reloc, /* special_function */ "R_PPC_REL14", /* name */ false, /* partial_inplace */ 0, /* src_mask */ @@ -335,7 +358,7 @@ static reloc_howto_type elf_powerpc_howto_table[] = 16, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ + complain_overflow_signed, /* complain_on_overflow */ ppc_elf_got16_reloc, /* special_function */ "R_PPC_GOT16", /* name */ false, /* partial_inplace */ @@ -400,7 +423,7 @@ static reloc_howto_type elf_powerpc_howto_table[] = true, /* pc_relative */ 0, /* bitpos */ complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + ppc_elf_std_reloc, /* special_function */ "R_PPC_PLT24", /* name */ false, /* partial_inplace */ 0, /* src_mask */ @@ -419,7 +442,7 @@ static reloc_howto_type elf_powerpc_howto_table[] = false, /* pc_relative */ 0, /* bitpos */ complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + ppc_elf_std_reloc, /* special_function */ "R_PPC_COPY", /* name */ false, /* partial_inplace */ 0, /* src_mask */ @@ -435,7 +458,7 @@ static reloc_howto_type elf_powerpc_howto_table[] = false, /* pc_relative */ 0, /* bitpos */ complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + ppc_elf_std_reloc, /* special_function */ "R_PPC_GLOB_DAT", /* name */ false, /* partial_inplace */ 0, /* src_mask */ @@ -450,7 +473,7 @@ static reloc_howto_type elf_powerpc_howto_table[] = false, /* pc_relative */ 0, /* bitpos */ complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + ppc_elf_std_reloc, /* special_function */ "R_PPC_JMP_SLOT", /* name */ false, /* partial_inplace */ 0, /* src_mask */ @@ -467,7 +490,7 @@ static reloc_howto_type elf_powerpc_howto_table[] = false, /* pc_relative */ 0, /* bitpos */ complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + ppc_elf_std_reloc, /* special_function */ "R_PPC_RELATIVE", /* name */ false, /* partial_inplace */ 0, /* src_mask */ @@ -499,7 +522,7 @@ static reloc_howto_type elf_powerpc_howto_table[] = false, /* pc_relative */ 0, /* bitpos */ complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + ppc_elf_std_reloc, /* special_function */ "R_PPC_UADDR32", /* name */ false, /* partial_inplace */ 0, /* src_mask */ @@ -514,7 +537,7 @@ static reloc_howto_type elf_powerpc_howto_table[] = false, /* pc_relative */ 0, /* bitpos */ complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + ppc_elf_std_reloc, /* special_function */ "R_PPC_UADDR16", /* name */ false, /* partial_inplace */ 0, /* src_mask */ @@ -529,7 +552,7 @@ static reloc_howto_type elf_powerpc_howto_table[] = true, /* pc_relative */ 0, /* bitpos */ complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + ppc_elf_std_reloc, /* special_function */ "R_PPC_REL32", /* name */ false, /* partial_inplace */ 0, /* src_mask */ @@ -774,6 +797,224 @@ static reloc_howto_type elf_powerpc_howto_table[] = false), /* pcrel_offset */ }; + +/* Initialize the ppc_elf_howto_table, so that linear accesses can be done. */ + +static void +ppc_elf_howto_init () +{ + unsigned int i, type; + + for (i = 0; i < sizeof (ppc_elf_howto_raw) / sizeof (ppc_elf_howto_raw[0]); i++) + { + type = ppc_elf_howto_raw[i].type; + BFD_ASSERT (type < sizeof(ppc_elf_howto_table) / sizeof(ppc_elf_howto_table[0])); + ppc_elf_howto_table[type] = &ppc_elf_howto_raw[i]; + } +} + + +static reloc_howto_type * +ppc_elf_reloc_type_lookup (abfd, code) + bfd *abfd; + bfd_reloc_code_real_type code; +{ + if (!ppc_elf_howto_table[ R_PPC_ADDR32 ]) /* Initialize howto table if needed */ + ppc_elf_howto_init (); + + switch ((int)code) + { + case BFD_RELOC_NONE: return ppc_elf_howto_table[ (int) R_PPC_NONE ]; + case BFD_RELOC_32: return ppc_elf_howto_table[ (int) R_PPC_ADDR32 ]; + case BFD_RELOC_32_PCREL: return ppc_elf_howto_table[ (int) R_PPC_REL32 ]; + case BFD_RELOC_CTOR: return ppc_elf_howto_table[ (int) R_PPC_ADDR32 ]; + case BFD_RELOC_PPC_B26: return ppc_elf_howto_table[ (int) R_PPC_REL24 ]; + case BFD_RELOC_PPC_BA26: return ppc_elf_howto_table[ (int) R_PPC_ADDR24 ]; + case BFD_RELOC_PPC_TOC16: return ppc_elf_howto_table[ (int) R_PPC_GOT16 ]; + case BFD_RELOC_LO16: return ppc_elf_howto_table[ (int) R_PPC_ADDR16_LO ]; + case BFD_RELOC_HI16: return ppc_elf_howto_table[ (int) R_PPC_ADDR16_HI ]; + case BFD_RELOC_HI16_S: return ppc_elf_howto_table[ (int) R_PPC_ADDR16_HA ]; + } + + return (reloc_howto_type *)NULL; +}; + +/* Set the howto pointer for a PowerPC ELF reloc. */ + +static void +ppc_elf_info_to_howto (abfd, cache_ptr, dst) + bfd *abfd; + arelent *cache_ptr; + Elf32_Internal_Rela *dst; +{ + if (!ppc_elf_howto_table[ R_PPC_ADDR32 ]) /* Initialize howto table if needed */ + ppc_elf_howto_init (); + + BFD_ASSERT (ELF32_R_TYPE (dst->r_info) < (unsigned int) R_PPC_max); + cache_ptr->howto = ppc_elf_howto_table[ELF32_R_TYPE (dst->r_info)]; +} + +/* Function to set whether a module needs the -mrelocatable bit set. */ + +static boolean +ppc_elf_set_private_flags (abfd, flags) + bfd *abfd; + flagword flags; +{ + BFD_ASSERT (!elf_ppc_flags_init (abfd) + || elf_elfheader (abfd)->e_flags == flags); + + elf_elfheader (abfd)->e_flags = flags; + elf_ppc_flags_init (abfd) = true; + return true; +} + +/* Copy backend specific data from one object module to another */ +static boolean +ppc_elf_copy_private_bfd_data (ibfd, obfd) + bfd *ibfd; + bfd *obfd; +{ + /* This function is selected based on the input vector. We only + want to copy information over if the output BFD also uses Elf + format. */ + if (bfd_get_flavour (obfd) != bfd_target_elf_flavour) + return true; + + BFD_ASSERT (!elf_ppc_flags_init (obfd) + || elf_elfheader (obfd)->e_flags == elf_elfheader (ibfd)->e_flags); + + elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags; + elf_ppc_flags_init (obfd) = true; + return true; +} + +/* Merge backend specific data from an object file to the output + object file when linking */ +static boolean +ppc_elf_merge_private_bfd_data (ibfd, obfd) + bfd *ibfd; + bfd *obfd; +{ + flagword old_flags; + flagword new_flags; + + /* Check if we have the same endianess */ + if (ibfd->xvec->byteorder_big_p != obfd->xvec->byteorder_big_p) + { + fprintf (stderr, + "%s: compiled for a %s endian system and target is %s endian.\n", + bfd_get_filename (ibfd), + (ibfd->xvec->byteorder_big_p) ? "big" : "little", + (obfd->xvec->byteorder_big_p) ? "big" : "little"); + + bfd_set_error (bfd_error_wrong_format); + return false; + } + + /* This function is selected based on the input vector. We only + want to copy information over if the output BFD also uses Elf + format. */ + if (bfd_get_flavour (obfd) != bfd_target_elf_flavour) + return true; + + new_flags = elf_elfheader (ibfd)->e_flags; + old_flags = elf_elfheader (obfd)->e_flags; + if (!elf_ppc_flags_init (obfd)) /* First call, no flags set */ + { + elf_ppc_flags_init (obfd) = true; + elf_elfheader (obfd)->e_flags = new_flags; + } + + else if (new_flags == old_flags) /* Compatible flags are ok */ + ; + + else /* Incompatible flags */ + { + /* Warn about -mrelocatable mismatch */ + if ((new_flags & EF_PPC_RELOCATABLE) != 0 && (old_flags & EF_PPC_RELOCATABLE) == 0) + { + new_flags &= ~EF_PPC_RELOCATABLE; + fprintf (stderr, + "%s: compiled with -mrelocatable and linked with modules compiled normally\n", + bfd_get_filename (ibfd)); + } + else if ((new_flags & EF_PPC_RELOCATABLE) == 0 && (old_flags & EF_PPC_RELOCATABLE) != 0) + { + old_flags &= ~EF_PPC_RELOCATABLE; + fprintf (stderr, + "%s: compiled normally and linked with modules compiled with -mrelocatable\n", + bfd_get_filename (ibfd)); + } + + /* Warn about eabi vs. V.4 mismatch */ + if ((new_flags & EF_PPC_EMB) != 0 && (old_flags & EF_PPC_EMB) == 0) + { + new_flags &= ~EF_PPC_EMB; + fprintf (stderr, + "%s: compiled for the eabi and linked with modules compiled for System V\n", + bfd_get_filename (ibfd)); + } + else if ((new_flags & EF_PPC_EMB) == 0 && (old_flags & EF_PPC_EMB) != 0) + { + old_flags &= ~EF_PPC_EMB; + fprintf (stderr, + "%s: compiled for System V and linked with modules compiled for eabi\n", + bfd_get_filename (ibfd)); + } + + /* Warn about any other mismatches */ + if (new_flags != old_flags) + fprintf (stderr, + "%s: uses different e_flags (0x%lx) fields than previous modules (0x%lx)\n", + bfd_get_filename (ibfd), (long)new_flags, (long)old_flags); + + bfd_set_error (bfd_error_bad_value); + return false; + } + + return true; +} + + +/* ELF relocs are against symbols. If we are producing relocateable + output, and the reloc is against an external symbol, and nothing + has given us any additional addend, the resulting reloc will also + be against the same symbol. In such a case, we don't want to + change anything about the way the reloc is handled, since it will + all be done at final link time. Rather than put special case code + into bfd_perform_relocation, all the reloc types use this howto + function. It just short circuits the reloc if producing + relocateable output against an external symbol. */ + +/*ARGSUSED*/ +static bfd_reloc_status_type +ppc_elf_std_reloc (abfd, + reloc_entry, + symbol, + data, + input_section, + output_bfd, + error_message) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + if (output_bfd != (bfd *) NULL + && (symbol->flags & BSF_SECTION_SYM) == 0 + && (! reloc_entry->howto->partial_inplace || reloc_entry->addend == 0)) + { + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + return bfd_reloc_continue; +} + /* Don't pretend we can deal with unsupported relocs. */ /*ARGSUSED*/ @@ -788,11 +1029,39 @@ ppc_elf_unsupported_reloc (abfd, reloc_entry, symbol, data, input_section, bfd *output_bfd; char **error_message; { - abort (); + BFD_ASSERT (reloc_entry->howto != (reloc_howto_type *)0); + fprintf (stderr, + "%s: Relocation %s (%d) is not currently supported.\n", + bfd_get_filename (abfd), + reloc_entry->howto->name, + reloc_entry->howto->type); + + return bfd_reloc_notsupported; +} + +/* Internal function to return the adjustment to the addend for relocations + that return the upper 16 bits after sign extending the lower 16 bits, ie + for use with a ORIS instruction followed by a memory reference using the + bottom 16 bits. */ + +INLINE +static bfd_vma +ppc_elf_addr16_ha_inner (sec, value, addend) + asection *sec; + bfd_vma value; + bfd_vma addend; +{ + bfd_vma relocation = (value + + sec->output_section->vma + + sec->output_offset + + addend); + + return (relocation & 0x8000) << 1; } /* Handle the ADDR16_HA reloc by adjusting the reloc addend. */ +/*ARGSUSED*/ static bfd_reloc_status_type ppc_elf_addr16_ha_reloc (abfd, reloc_entry, symbol, data, input_section, output_bfd, error_message) @@ -804,25 +1073,29 @@ ppc_elf_addr16_ha_reloc (abfd, reloc_entry, symbol, data, input_section, bfd *output_bfd; char **error_message; { - bfd_vma relocation; - if (output_bfd != (bfd *) NULL) - return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, - input_section, output_bfd, error_message); + return ppc_elf_std_reloc (abfd, reloc_entry, symbol, data, + input_section, output_bfd, error_message); - if (bfd_is_com_section (symbol->section)) - relocation = 0; - else - relocation = symbol->value; + reloc_entry->addend += ppc_elf_addr16_ha_inner (symbol->section, + (bfd_is_com_section (symbol->section)) ? 0 : symbol->value, + reloc_entry->addend); + return bfd_reloc_continue; +} - relocation += (symbol->section->output_section->vma - + symbol->section->output_offset - + reloc_entry->addend); +/* Internal function to return the addjustment to the addend for GOT16 + entries */ - if ((relocation & 0x8000) != 0) - reloc_entry->addend += 0x10000; +INLINE +static bfd_vma +ppc_elf_got16_inner (sec) + asection *sec; +{ + BFD_ASSERT (bfd_is_und_section (sec) + || strcmp (bfd_get_section_name (abfd, sec), ".got") == 0 + || strcmp (bfd_get_section_name (abfd, sec), ".cgot") == 0); - return bfd_reloc_continue; + return -(sec->output_section->vma + 0x8000); } /* Handle the GOT16 reloc. We want to use the offset within the .got @@ -831,6 +1104,7 @@ ppc_elf_addr16_ha_reloc (abfd, reloc_entry, symbol, data, input_section, AIX .toc section. When and if we support PIC code, we will have to change this, perhaps by switching off on the e_type field. */ +/*ARGSUSED*/ static bfd_reloc_status_type ppc_elf_got16_reloc (abfd, reloc_entry, symbol, data, input_section, output_bfd, error_message) @@ -842,78 +1116,272 @@ ppc_elf_got16_reloc (abfd, reloc_entry, symbol, data, input_section, bfd *output_bfd; char **error_message; { - asection *sec; - if (output_bfd != (bfd *) NULL) - return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, - input_section, output_bfd, error_message); + return ppc_elf_std_reloc (abfd, reloc_entry, symbol, data, + input_section, output_bfd, error_message); - sec = bfd_get_section (*reloc_entry->sym_ptr_ptr); - BFD_ASSERT (bfd_is_und_section (sec) - || strcmp (bfd_get_section_name (abfd, sec), ".got") == 0 - || strcmp (bfd_get_section_name (abfd, sec), ".cgot") == 0); - reloc_entry->addend -= sec->output_section->vma; + reloc_entry->addend += ppc_elf_got16_inner (bfd_get_section (*reloc_entry->sym_ptr_ptr)); return bfd_reloc_continue; } -/* Map BFD reloc types to PowerPC ELF reloc types. */ + +/* The RELOCATE_SECTION function is called by the ELF backend linker + to handle the relocations for a section. -struct powerpc_reloc_map -{ - unsigned char bfd_reloc_val; - unsigned char elf_reloc_val; -}; + The relocs are always passed as Rela structures; if the section + actually uses Rel structures, the r_addend field will always be + zero. -static const struct powerpc_reloc_map powerpc_reloc_map[] = -{ - { BFD_RELOC_NONE, R_PPC_NONE, }, - { BFD_RELOC_32, R_PPC_ADDR32 }, - { BFD_RELOC_32_PCREL, R_PPC_REL32 }, - { BFD_RELOC_CTOR, R_PPC_ADDR32 }, - { BFD_RELOC_PPC_B26, R_PPC_REL24 }, - { BFD_RELOC_PPC_BA26, R_PPC_ADDR24 }, - { BFD_RELOC_PPC_TOC16, R_PPC_GOT16 }, - { BFD_RELOC_LO16, R_PPC_ADDR16_LO }, - { BFD_RELOC_HI16, R_PPC_ADDR16_HI }, - { BFD_RELOC_HI16_S, R_PPC_ADDR16_HA } -}; + This function is responsible for adjust the section contents as + necessary, and (if using Rela relocs and generating a + relocateable output file) adjusting the reloc addend as + necessary. -static reloc_howto_type * -bfd_elf32_bfd_reloc_type_lookup (abfd, code) - bfd *abfd; - bfd_reloc_code_real_type code; + This function does not have to worry about setting the reloc + address or the reloc symbol index. + + LOCAL_SYMS is a pointer to the swapped in local symbols. + + LOCAL_SECTIONS is an array giving the section in the input file + corresponding to the st_shndx field of each local symbol. + + The global hash table entry for the global symbols can be found + via elf_sym_hashes (input_bfd). + + When generating relocateable output, this function must handle + STB_LOCAL/STT_SECTION symbols specially. The output symbol is + going to be the section symbol corresponding to the output + section, which means that the addend must be adjusted + accordingly. */ + +static boolean +ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section, + contents, relocs, local_syms, local_sections) + bfd *output_bfd; + struct bfd_link_info *info; + bfd *input_bfd; + asection *input_section; + bfd_byte *contents; + Elf_Internal_Rela *relocs; + Elf_Internal_Sym *local_syms; + asection **local_sections; { - int i; + Elf_Internal_Shdr *symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; + struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (input_bfd); + Elf_Internal_Rela *rel = relocs; + Elf_Internal_Rela *relend = relocs + input_section->reloc_count; + boolean ret = true; + +#ifdef DEBUG + fprintf (stderr, "ppc_elf_relocate_section called for %s section %s, %ld relocations%s\n", + bfd_get_filename (input_bfd), + bfd_section_name(input_bfd, input_section), + (long)input_section->reloc_count, + (info->relocateable) ? " (relocatable)" : ""); +#endif + + if (!ppc_elf_howto_table[ R_PPC_ADDR32 ]) /* Initialize howto table if needed */ + ppc_elf_howto_init (); - for (i = 0; - i < sizeof (powerpc_reloc_map) / sizeof (struct powerpc_reloc_map); - i++) + for (; rel < relend; rel++) { - if (powerpc_reloc_map[i].bfd_reloc_val == code) - return &elf_powerpc_howto_table[powerpc_reloc_map[i].elf_reloc_val]; + enum reloc_type r_type = (enum reloc_type)ELF32_R_TYPE (rel->r_info); + bfd_vma offset = rel->r_offset; + bfd_vma addend = rel->r_addend; + bfd_reloc_status_type r = bfd_reloc_other; + Elf_Internal_Sym *sym = (Elf_Internal_Sym *)0; + asection *sec = (asection *)0; + struct elf_link_hash_entry *h = (struct elf_link_hash_entry *)0; + reloc_howto_type *howto; + unsigned long r_symndx; + bfd_vma relocation; + + /* Unknown relocation handling */ + if ((unsigned)r_type >= (unsigned)R_PPC_max || !ppc_elf_howto_table[(int)r_type]) + { + fprintf (stderr, + "%s: Unknown relocation type %d\n", + bfd_get_filename (input_bfd), + (int)r_type); + + bfd_set_error (bfd_error_bad_value); + ret = false; + continue; + } + + howto = ppc_elf_howto_table[(int)r_type]; + r_symndx = ELF32_R_SYM (rel->r_info); + + if (info->relocateable) + { + /* This is a relocateable link. We don't have to change + anything, unless the reloc is against a section symbol, + in which case we have to adjust according to where the + section symbol winds up in the output section. */ + if (r_symndx < symtab_hdr->sh_info) + { + sym = local_syms + r_symndx; + if ((unsigned)ELF_ST_TYPE (sym->st_info) == STT_SECTION) + { + sec = local_sections[r_symndx]; + addend = rel->r_addend += sec->output_offset + sym->st_value; + } + } + +#ifdef DEBUG + fprintf (stderr, "\ttype = %s (%d), symbol index = %ld, offset = %ld, addend = %ld\n", + howto->name, + (int)r_type, + r_symndx, + (long)offset, + (long)addend); +#endif + continue; + } + + /* This is a final link. */ + + /* Complain about known relocation that are not yet supported */ + if (howto->special_function == ppc_elf_unsupported_reloc) + { + fprintf (stderr, + "%s: Relocation %s (%d) is not currently supported.\n", + bfd_get_filename (input_bfd), + howto->name, + (int)r_type); + + bfd_set_error (bfd_error_bad_value); + ret = false; + continue; + } + + if (r_symndx < symtab_hdr->sh_info) + { + sym = local_syms + r_symndx; + sec = local_sections[r_symndx]; + relocation = (sec->output_section->vma + + sec->output_offset + + sym->st_value); + } + else + { + h = sym_hashes[r_symndx - symtab_hdr->sh_info]; + if (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + { + sec = h->root.u.def.section; + relocation = (h->root.u.def.value + + sec->output_section->vma + + sec->output_offset); + } + else if (h->root.type == bfd_link_hash_undefweak) + relocation = 0; + else if (info->shared) + relocation = 0; + else + { + (*info->callbacks->undefined_symbol)(info, + h->root.root.string, + input_bfd, + input_section, + rel->r_offset); + ret = false; + continue; + } + } + + switch ((int)r_type) + { + default: + break; + + case (int)R_PPC_GOT16: /* GOT16 relocations */ + case (int)R_PPC_GOT16_LO: + case (int)R_PPC_GOT16_HI: + BFD_ASSERT (sec != (asection *)0); + addend += ppc_elf_got16_inner (sec); + break; + + case (int)R_PPC_ADDR16_HA: /* arithmetic adjust relocations */ + BFD_ASSERT (sec != (asection *)0); + addend += ppc_elf_addr16_ha_inner (sec, relocation, addend); + break; + } + + +#ifdef DEBUG + fprintf (stderr, "\ttype = %s (%d), symbol index = %ld, offset = %ld, addend = %ld\n", + howto->name, + (int)r_type, + r_symndx, + (long)offset, + (long)addend); +#endif + + r = _bfd_final_link_relocate (howto, + input_bfd, + input_section, + contents, + offset, + relocation, + addend); + + if (r != bfd_reloc_ok) + { + ret = false; + switch (r) + { + default: + break; + + case bfd_reloc_overflow: + { + const char *name; + + if (h != NULL) + name = h->root.root.string; + else + { + name = bfd_elf_string_from_elf_section (input_bfd, + symtab_hdr->sh_link, + sym->st_name); + if (name == NULL) + break; + + if (*name == '\0') + name = bfd_section_name (input_bfd, sec); + } + + (*info->callbacks->reloc_overflow)(info, + name, + howto->name, + (bfd_vma) 0, + input_bfd, + input_section, + offset); + } + break; + + } + } } - return NULL; -} -/* Set the howto pointer for a PowerPC ELF reloc. */ +#ifdef DEBUG + fprintf (stderr, "\n"); +#endif -static void -powerpc_info_to_howto (abfd, cache_ptr, dst) - bfd *abfd; - arelent *cache_ptr; - Elf32_Internal_Rela *dst; -{ - BFD_ASSERT (ELF32_R_TYPE (dst->r_info) < (unsigned int) R_PPC_max); - cache_ptr->howto = &elf_powerpc_howto_table[ELF32_R_TYPE (dst->r_info)]; + return ret; } +#define TARGET_LITTLE_SYM bfd_elf32_powerpcle_vec +#define TARGET_LITTLE_NAME "elf32-powerpcle" #define TARGET_BIG_SYM bfd_elf32_powerpc_vec #define TARGET_BIG_NAME "elf32-powerpc" #define ELF_ARCH bfd_arch_powerpc #define ELF_MACHINE_CODE EM_PPC #define ELF_MAXPAGESIZE 0x10000 -#define elf_info_to_howto powerpc_info_to_howto +#define elf_info_to_howto ppc_elf_info_to_howto #ifdef EM_CYGNUS_POWERPC #define ELF_MACHINE_ALT1 EM_CYGNUS_POWERPC @@ -923,4 +1391,10 @@ powerpc_info_to_howto (abfd, cache_ptr, dst) #define ELF_MACHINE_ALT2 EM_PPC_OLD #endif +#define bfd_elf32_bfd_copy_private_bfd_data ppc_elf_copy_private_bfd_data +#define bfd_elf32_bfd_merge_private_bfd_data ppc_elf_merge_private_bfd_data +#define bfd_elf32_bfd_set_private_flags ppc_elf_set_private_flags +#define bfd_elf32_bfd_reloc_type_lookup ppc_elf_reloc_type_lookup +#define elf_backend_relocate_section ppc_elf_relocate_section + #include "elf32-target.h" |