From: Ian Lance Taylor Date: Fri, 31 May 1996 21:43:35 +0000 (+0000) Subject: * elf64-mips.c: Improve reloc special_functions and handling of X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=bc05732be61676a7ab921b1d3376a64794096487;p=binutils-gdb.git * elf64-mips.c: Improve reloc special_functions and handling of SHT_MIPS_OPTIONS section. * elf32-mips.c (_bfd_mips_elf_hi16_reloc): Rename from mips_elf_hi16_reloc and make globally visible. (_bfd_mips_elf_lo16_reloc): Rename from mips_elf_lo16_reloc and make globally visible. (_bfd_mips_elf_got16_reloc): Rename from mips_elf_got16_reloc and make globally visible. (_bfd_mips_elf_gprel16_reloc): Rename from mips_elf_gprel16_reloc and make globally visible. (gprel16_with_gp): Check howto->src_mask before using value in insn. (_bfd_mips_elf_gprel32_reloc): Rename from mips_elf_gprel32_reloc and make globally visible. (gprel32_with_gp): Check howto->src_mask before fetching value. (bfd_mips_elf_swap_options_in): New function. (bfd_mips_elf_swap_options_out): New function. (_bfd_mips_elf_set_private_flags): Rename from mips_elf_set_private_flags and make globally visible. (_bfd_mips_elf_copy_private_bfd_data): Rename from mips_elf_copy_private_bfd_data and make globally visible. (_bfd_mips_elf_merge_private_bfd_data): Rename from mips_elf_merge_private_bfd_data and make globally visible. (_bfd_mips_elf_section_from_shdr): Accept .MIPS.options as a name for a SHT_MIPS_OPTIONS section. (mips_elf32_section_from_shdr): Handle SHT_MIPS_OPTIONS section. (_bfd_mips_elf_fake_sections): Consider .MIPS.options to be the name of a SHT_MIPS_OPTIONS section. (_bfd_mips_elf_set_section_contents): New function. (mips_elf32_section_processing): Set the GP value in a SHT_MIPS_OPTIONS section. (_bfd_mips_elf_find_nearest_line): Rename from mips_elf_find_nearest_line and make globally visible. (bfd_elf32_set_section_contents): Define. * elf-bfd.h (_bfd_mips_elf_hi16_reloc): Declare. (_bfd_mips_elf_lo16_reloc): Declare. (_bfd_mips_elf_gprel16_reloc): Declare. (_bfd_mips_elf_got16_reloc): Declare. (_bfd_mips_elf_gprel32_reloc): Declare. (_bfd_mips_elf_set_private_flags): Declare. (_bfd_mips_elf_copy_private_bfd_data): Declare. (_bfd_mips_elf_merge_private_bfd_data): Declare. (_bfd_mips_elf_find_nearest_line): Declare. (_bfd_mips_elf_set_section_contents): Declare. --- diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 2dae47a19a8..3e8fc4627ba 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,5 +1,50 @@ Fri May 31 13:51:28 1996 Ian Lance Taylor + * elf64-mips.c: Improve reloc special_functions and handling of + SHT_MIPS_OPTIONS section. + * elf32-mips.c (_bfd_mips_elf_hi16_reloc): Rename from + mips_elf_hi16_reloc and make globally visible. + (_bfd_mips_elf_lo16_reloc): Rename from mips_elf_lo16_reloc and + make globally visible. + (_bfd_mips_elf_got16_reloc): Rename from mips_elf_got16_reloc and + make globally visible. + (_bfd_mips_elf_gprel16_reloc): Rename from mips_elf_gprel16_reloc + and make globally visible. + (gprel16_with_gp): Check howto->src_mask before using value in + insn. + (_bfd_mips_elf_gprel32_reloc): Rename from mips_elf_gprel32_reloc + and make globally visible. + (gprel32_with_gp): Check howto->src_mask before fetching value. + (bfd_mips_elf_swap_options_in): New function. + (bfd_mips_elf_swap_options_out): New function. + (_bfd_mips_elf_set_private_flags): Rename from + mips_elf_set_private_flags and make globally visible. + (_bfd_mips_elf_copy_private_bfd_data): Rename from + mips_elf_copy_private_bfd_data and make globally visible. + (_bfd_mips_elf_merge_private_bfd_data): Rename from + mips_elf_merge_private_bfd_data and make globally visible. + (_bfd_mips_elf_section_from_shdr): Accept .MIPS.options as a name + for a SHT_MIPS_OPTIONS section. + (mips_elf32_section_from_shdr): Handle SHT_MIPS_OPTIONS section. + (_bfd_mips_elf_fake_sections): Consider .MIPS.options to be the + name of a SHT_MIPS_OPTIONS section. + (_bfd_mips_elf_set_section_contents): New function. + (mips_elf32_section_processing): Set the GP value in a + SHT_MIPS_OPTIONS section. + (_bfd_mips_elf_find_nearest_line): Rename from + mips_elf_find_nearest_line and make globally visible. + (bfd_elf32_set_section_contents): Define. + * elf-bfd.h (_bfd_mips_elf_hi16_reloc): Declare. + (_bfd_mips_elf_lo16_reloc): Declare. + (_bfd_mips_elf_gprel16_reloc): Declare. + (_bfd_mips_elf_got16_reloc): Declare. + (_bfd_mips_elf_gprel32_reloc): Declare. + (_bfd_mips_elf_set_private_flags): Declare. + (_bfd_mips_elf_copy_private_bfd_data): Declare. + (_bfd_mips_elf_merge_private_bfd_data): Declare. + (_bfd_mips_elf_find_nearest_line): Declare. + (_bfd_mips_elf_set_section_contents): Declare. + * elf32-hppa.c (elf32_hppa_info_to_howto): Rename from elf_info_to_howto. (elf_info_to_howto): Define. diff --git a/bfd/elf32-mips.c b/bfd/elf32-mips.c index 2beb7204c92..94eb015ca12 100644 --- a/bfd/elf32-mips.c +++ b/bfd/elf32-mips.c @@ -41,41 +41,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #define ECOFF_32 #include "ecoffswap.h" -static bfd_reloc_status_type mips_elf_hi16_reloc PARAMS ((bfd *abfd, - arelent *reloc, - asymbol *symbol, - PTR data, - asection *section, - bfd *output_bfd, - char **error)); -static bfd_reloc_status_type mips_elf_got16_reloc PARAMS ((bfd *abfd, - arelent *reloc, - asymbol *symbol, - PTR data, - asection *section, - bfd *output_bfd, - char **error)); -static bfd_reloc_status_type mips_elf_lo16_reloc PARAMS ((bfd *abfd, - arelent *reloc, - asymbol *symbol, - PTR data, - asection *section, - bfd *output_bfd, - char **error)); -static bfd_reloc_status_type mips_elf_gprel16_reloc PARAMS ((bfd *abfd, - arelent *reloc, - asymbol *symbol, - PTR data, - asection *section, - bfd *output_bfd, - char **error)); -static bfd_reloc_status_type mips_elf_gprel32_reloc PARAMS ((bfd *abfd, - arelent *reloc, - asymbol *symbol, - PTR data, - asection *section, - bfd *output_bfd, - char **error)); static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup PARAMS ((bfd *, bfd_reloc_code_real_type)); static void mips_info_to_howto_rel @@ -91,18 +56,12 @@ static boolean mips_elf_create_procedure_table struct ecoff_debug_info *)); static int mips_elf_additional_program_headers PARAMS ((bfd *)); static boolean mips_elf_modify_segment_map PARAMS ((bfd *)); -static boolean mips_elf_set_private_flags PARAMS ((bfd *, flagword)); -static boolean mips_elf_copy_private_bfd_data PARAMS ((bfd *, bfd *)); -static boolean mips_elf_merge_private_bfd_data PARAMS ((bfd *, bfd *)); static boolean mips_elf32_section_from_shdr PARAMS ((bfd *, Elf32_Internal_Shdr *, char *)); static boolean mips_elf32_section_processing PARAMS ((bfd *, Elf32_Internal_Shdr *)); static boolean mips_elf_is_local_label PARAMS ((bfd *, asymbol *)); -static boolean mips_elf_find_nearest_line - PARAMS ((bfd *, asection *, asymbol **, bfd_vma, const char **, - const char **, unsigned int *)); static struct bfd_hash_entry *mips_elf_link_hash_newfunc PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); static struct bfd_link_hash_table *mips_elf_link_hash_table_create @@ -427,7 +386,7 @@ static reloc_howto_type elf_mips_howto_table[] = false, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ - mips_elf_hi16_reloc, /* special_function */ + _bfd_mips_elf_hi16_reloc, /* special_function */ "R_MIPS_HI16", /* name */ true, /* partial_inplace */ 0xffff, /* src_mask */ @@ -442,7 +401,7 @@ static reloc_howto_type elf_mips_howto_table[] = false, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ - mips_elf_lo16_reloc, /* special_function */ + _bfd_mips_elf_lo16_reloc, /* special_function */ "R_MIPS_LO16", /* name */ true, /* partial_inplace */ 0xffff, /* src_mask */ @@ -457,7 +416,7 @@ static reloc_howto_type elf_mips_howto_table[] = false, /* pc_relative */ 0, /* bitpos */ complain_overflow_signed, /* complain_on_overflow */ - mips_elf_gprel16_reloc, /* special_function */ + _bfd_mips_elf_gprel16_reloc, /* special_function */ "R_MIPS_GPREL16", /* name */ true, /* partial_inplace */ 0xffff, /* src_mask */ @@ -472,7 +431,7 @@ static reloc_howto_type elf_mips_howto_table[] = false, /* pc_relative */ 0, /* bitpos */ complain_overflow_signed, /* complain_on_overflow */ - mips_elf_gprel16_reloc, /* special_function */ + _bfd_mips_elf_gprel16_reloc, /* special_function */ "R_MIPS_LITERAL", /* name */ true, /* partial_inplace */ 0xffff, /* src_mask */ @@ -487,7 +446,7 @@ static reloc_howto_type elf_mips_howto_table[] = false, /* pc_relative */ 0, /* bitpos */ complain_overflow_signed, /* complain_on_overflow */ - mips_elf_got16_reloc, /* special_function */ + _bfd_mips_elf_got16_reloc, /* special_function */ "R_MIPS_GOT16", /* name */ false, /* partial_inplace */ 0, /* src_mask */ @@ -533,7 +492,7 @@ static reloc_howto_type elf_mips_howto_table[] = false, /* pc_relative */ 0, /* bitpos */ complain_overflow_bitfield, /* complain_on_overflow */ - mips_elf_gprel32_reloc, /* special_function */ + _bfd_mips_elf_gprel32_reloc, /* special_function */ "R_MIPS_GPREL32", /* name */ true, /* partial_inplace */ 0xffffffff, /* src_mask */ @@ -727,8 +686,8 @@ struct mips_hi16 static struct mips_hi16 *mips_hi16_list; -static bfd_reloc_status_type -mips_elf_hi16_reloc (abfd, +bfd_reloc_status_type +_bfd_mips_elf_hi16_reloc (abfd, reloc_entry, symbol, data, @@ -820,8 +779,8 @@ mips_elf_hi16_reloc (abfd, inplace relocation; this function exists in order to do the R_MIPS_HI16 relocation described above. */ -static bfd_reloc_status_type -mips_elf_lo16_reloc (abfd, +bfd_reloc_status_type +_bfd_mips_elf_lo16_reloc (abfd, reloc_entry, symbol, data, @@ -930,8 +889,8 @@ mips_elf_lo16_reloc (abfd, This implementation suffices for the assembler, but the linker does not yet know how to create global offset tables. */ -static bfd_reloc_status_type -mips_elf_got16_reloc (abfd, +bfd_reloc_status_type +_bfd_mips_elf_got16_reloc (abfd, reloc_entry, symbol, data, @@ -960,8 +919,8 @@ mips_elf_got16_reloc (abfd, just like HI16. */ if (output_bfd != (bfd *) NULL && (symbol->flags & BSF_SECTION_SYM) != 0) - return mips_elf_hi16_reloc (abfd, reloc_entry, symbol, data, - input_section, output_bfd, error_message); + return _bfd_mips_elf_hi16_reloc (abfd, reloc_entry, symbol, data, + input_section, output_bfd, error_message); abort (); } @@ -1050,14 +1009,9 @@ static bfd_reloc_status_type gprel16_with_gp PARAMS ((bfd *, asymbol *, arelent *, asection *, boolean, PTR, bfd_vma)); -static bfd_reloc_status_type -mips_elf_gprel16_reloc (abfd, - reloc_entry, - symbol, - data, - input_section, - output_bfd, - error_message) +bfd_reloc_status_type +_bfd_mips_elf_gprel16_reloc (abfd, reloc_entry, symbol, data, input_section, + output_bfd, error_message) bfd *abfd; arelent *reloc_entry; asymbol *symbol; @@ -1128,9 +1082,17 @@ gprel16_with_gp (abfd, symbol, reloc_entry, input_section, relocateable, data, insn = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); /* Set val to the offset into the section or symbol. */ - val = ((insn & 0xffff) + reloc_entry->addend) & 0xffff; - if (val & 0x8000) - val -= 0x10000; + if (reloc_entry->howto->src_mask == 0) + { + /* This case occurs with the 64-bit MIPS ELF ABI. */ + val = reloc_entry->addend; + } + else + { + val = ((insn & 0xffff) + reloc_entry->addend) & 0xffff; + if (val & 0x8000) + val -= 0x10000; + } /* Adjust val for the final section location and GP value. If we are producing relocateable output, we don't want to do this for @@ -1159,8 +1121,8 @@ static bfd_reloc_status_type gprel32_with_gp PARAMS ((bfd *, asymbol *, arelent *, asection *, boolean, PTR, bfd_vma)); -static bfd_reloc_status_type -mips_elf_gprel32_reloc (abfd, +bfd_reloc_status_type +_bfd_mips_elf_gprel32_reloc (abfd, reloc_entry, symbol, data, @@ -1237,7 +1199,13 @@ gprel32_with_gp (abfd, symbol, reloc_entry, input_section, relocateable, data, if (reloc_entry->address > input_section->_cooked_size) return bfd_reloc_outofrange; - val = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); + if (reloc_entry->howto->src_mask == 0) + { + /* This case arises with the 64-bit MIPS ELF ABI. */ + val = 0; + } + else + val = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); /* Set val to the offset into the section or symbol. */ val += reloc_entry->addend; @@ -1420,6 +1388,34 @@ bfd_elf32_swap_crinfo_out (abfd, in, ex) bfd_h_put_32 (abfd, (bfd_vma) in->konst, ex->konst); bfd_h_put_32 (abfd, (bfd_vma) in->vaddr, ex->vaddr); } + +/* Swap in an options header. */ + +void +bfd_mips_elf_swap_options_in (abfd, ex, in) + bfd *abfd; + const Elf_External_Options *ex; + Elf_Internal_Options *in; +{ + in->kind = bfd_h_get_8 (abfd, ex->kind); + in->size = bfd_h_get_8 (abfd, ex->size); + in->section = bfd_h_get_16 (abfd, ex->section); + in->info = bfd_h_get_32 (abfd, ex->info); +} + +/* Swap out an options header. */ + +void +bfd_mips_elf_swap_options_out (abfd, in, ex) + bfd *abfd; + const Elf_Internal_Options *in; + Elf_External_Options *ex; +{ + bfd_h_put_8 (abfd, in->kind, ex->kind); + bfd_h_put_8 (abfd, in->size, ex->size); + bfd_h_put_16 (abfd, in->section, ex->section); + bfd_h_put_32 (abfd, in->info, ex->info); +} /* Determine whether a symbol is global for the purposes of splitting the symbol table into global symbols and local symbols. At least @@ -1543,8 +1539,8 @@ _bfd_mips_elf_final_write_processing (abfd, linker) /* Function to keep MIPS specific file flags like as EF_MIPS_PIC. */ -static boolean -mips_elf_set_private_flags (abfd, flags) +boolean +_bfd_mips_elf_set_private_flags (abfd, flags) bfd *abfd; flagword flags; { @@ -1558,8 +1554,8 @@ mips_elf_set_private_flags (abfd, flags) /* Copy backend specific data from one object module to another */ -static boolean -mips_elf_copy_private_bfd_data (ibfd, obfd) +boolean +_bfd_mips_elf_copy_private_bfd_data (ibfd, obfd) bfd *ibfd; bfd *obfd; { @@ -1582,8 +1578,8 @@ mips_elf_copy_private_bfd_data (ibfd, obfd) /* Merge backend specific data from an object file to the output object file when linking. */ -static boolean -mips_elf_merge_private_bfd_data (ibfd, obfd) +boolean +_bfd_mips_elf_merge_private_bfd_data (ibfd, obfd) bfd *ibfd; bfd *obfd; { @@ -1705,7 +1701,8 @@ _bfd_mips_elf_section_from_shdr (abfd, hdr, name) return false; break; case SHT_MIPS_OPTIONS: - if (strcmp (name, ".options") != 0) + if (strcmp (name, ".options") != 0 + && strcmp (name, ".MIPS.options") != 0) return false; break; case SHT_MIPS_DWARF: @@ -1764,6 +1761,47 @@ mips_elf32_section_from_shdr (abfd, hdr, name) elf_gp (abfd) = s.ri_gp_value; } + /* For a SHT_MIPS_OPTIONS section, look for a ODK_REGINFO entry, and + set the gp value based on what we find. We may see both + SHT_MIPS_REGINFO and SHT_MIPS_OPTIONS/ODK_REGINFO; in that case, + they should agree. */ + if (hdr->sh_type == SHT_MIPS_OPTIONS) + { + bfd_byte *contents, *l, *lend; + + contents = (bfd_byte *) bfd_malloc (hdr->sh_size); + if (contents == NULL) + return false; + if (! bfd_get_section_contents (abfd, hdr->bfd_section, contents, + (file_ptr) 0, hdr->sh_size)) + { + free (contents); + return false; + } + l = contents; + lend = contents + hdr->sh_size; + while (l + sizeof (Elf_External_Options) <= lend) + { + Elf_Internal_Options intopt; + + bfd_mips_elf_swap_options_in (abfd, (Elf_External_Options *) l, + &intopt); + if (intopt.kind == ODK_REGINFO) + { + Elf32_RegInfo intreg; + + bfd_mips_elf32_swap_reginfo_in + (abfd, + ((Elf32_External_RegInfo *) + (l + sizeof (Elf_External_Options))), + &intreg); + elf_gp (abfd) = intreg.ri_gp_value; + } + l += intopt.size; + } + free (contents); + } + return true; } @@ -1842,7 +1880,8 @@ _bfd_mips_elf_fake_sections (abfd, hdr, sec) || strcmp (name, ".lit4") == 0 || strcmp (name, ".lit8") == 0) hdr->sh_flags |= SHF_MIPS_GPREL; - else if (strcmp (name, ".options") == 0) + else if (strcmp (name, ".options") == 0 + || strcmp (name, ".MIPS.options") == 0) { hdr->sh_type = SHT_MIPS_OPTIONS; hdr->sh_entsize = 1; @@ -1881,11 +1920,56 @@ _bfd_mips_elf_section_from_bfd_section (abfd, hdr, sec, retval) return false; } -/* Work over a section just before writing it out. We update the GP - value in the .reginfo section based on the value we are using. - This routine is used by both the 32-bit and the 64-bit ABI. FIXME: - We recognize sections that need the SHF_MIPS_GPREL flag by name; - there has to be a better way. */ +/* When are writing out the .options or .MIPS.options section, + remember the bytes we are writing out, so that we can install the + GP value in the section_processing routine. */ + +boolean +_bfd_mips_elf_set_section_contents (abfd, section, location, offset, count) + bfd *abfd; + sec_ptr section; + PTR location; + file_ptr offset; + bfd_size_type count; +{ + if (strcmp (section->name, ".options") == 0 + || strcmp (section->name, ".MIPS.options") == 0) + { + bfd_byte *c; + + if (elf_section_data (section) == NULL) + { + section->used_by_bfd = + (PTR) bfd_zalloc (abfd, sizeof (struct bfd_elf_section_data)); + if (elf_section_data (section) == NULL) + return false; + } + c = (bfd_byte *) elf_section_data (section)->tdata; + if (c == NULL) + { + bfd_size_type size; + + if (section->_cooked_size != 0) + size = section->_cooked_size; + else + size = section->_raw_size; + c = (PTR) bfd_zalloc (abfd, size); + if (c == NULL) + return false; + elf_section_data (section)->tdata = (PTR) c; + } + + memcpy (c + offset, location, count); + } + + return _bfd_elf_set_section_contents (abfd, section, location, offset, + count); +} + +/* Work over a section just before writing it out. This routine is + used by both the 32-bit and the 64-bit ABI. FIXME: We recognize + sections that need the SHF_MIPS_GPREL flag by name; there has to be + a better way. */ boolean _bfd_mips_elf_section_processing (abfd, hdr) @@ -1934,8 +2018,8 @@ _bfd_mips_elf_section_processing (abfd, hdr) } /* Work over a section just before writing it out. We update the GP - value in the .reginfo section based on the value we are using. The - 64 bit ABI does not use the .reginfo section. */ + value in the SHT_MIPS_REGINFO and SHT_MIPS_OPTIONS sections based + on the value we are using. */ static boolean mips_elf32_section_processing (abfd, hdr) @@ -1958,6 +2042,48 @@ mips_elf32_section_processing (abfd, hdr) return false; } + if (hdr->sh_type == SHT_MIPS_OPTIONS + && hdr->bfd_section != NULL + && elf_section_data (hdr->bfd_section) != NULL + && elf_section_data (hdr->bfd_section)->tdata != NULL) + { + bfd_byte *contents, *l, *lend; + + /* We stored the section contents in the elf_section_data tdata + field in the set_section_contents routine. We save the + section contents so that we don't have to read them again. + At this point we know that elf_gp is set, so we can look + through the section contents to see if there is an + ODK_REGINFO structure. */ + + contents = (bfd_byte *) elf_section_data (hdr->bfd_section)->tdata; + l = contents; + lend = contents + hdr->sh_size; + while (l + sizeof (Elf_External_Options) <= lend) + { + Elf_Internal_Options intopt; + + bfd_mips_elf_swap_options_in (abfd, (Elf_External_Options *) l, + &intopt); + if (intopt.kind == ODK_REGINFO) + { + bfd_byte buf[4]; + + if (bfd_seek (abfd, + (hdr->sh_offset + + (l - contents) + + sizeof (Elf_External_Options) + + (sizeof (Elf32_External_RegInfo) - 4)), + SEEK_SET) == -1) + return false; + bfd_h_put_32 (abfd, elf_gp (abfd), buf); + if (bfd_write (buf, 1, 4, abfd) != 4) + return false; + } + l += intopt.size; + } + } + return _bfd_mips_elf_section_processing (abfd, hdr); } @@ -2408,9 +2534,9 @@ struct mips_elf_find_line struct ecoff_find_line i; }; -static boolean -mips_elf_find_nearest_line (abfd, section, symbols, offset, filename_ptr, - functionname_ptr, line_ptr) +boolean +_bfd_mips_elf_find_nearest_line (abfd, section, symbols, offset, filename_ptr, + functionname_ptr, line_ptr) bfd *abfd; asection *section; asymbol **symbols; @@ -5839,7 +5965,7 @@ elf32_mips_get_relocated_section_contents (abfd, link_info, link_order, data, fall over on its own. */ } else if ((*parent)->howto->special_function - == mips_elf_gprel16_reloc) + == _bfd_mips_elf_gprel16_reloc) { /* bypass special_function call */ r = gprel16_with_gp (input_bfd, sym, *parent, input_section, @@ -5980,16 +6106,16 @@ static const struct ecoff_debug_swap mips_elf32_ecoff_debug_swap = #define elf_backend_ecoff_debug_swap &mips_elf32_ecoff_debug_swap #define bfd_elf32_bfd_is_local_label mips_elf_is_local_label -#define bfd_elf32_find_nearest_line mips_elf_find_nearest_line - +#define bfd_elf32_find_nearest_line _bfd_mips_elf_find_nearest_line +#define bfd_elf32_set_section_contents _bfd_mips_elf_set_section_contents #define bfd_elf32_bfd_link_hash_table_create \ mips_elf_link_hash_table_create #define bfd_elf32_bfd_final_link mips_elf_final_link #define bfd_elf32_bfd_copy_private_bfd_data \ - mips_elf_copy_private_bfd_data + _bfd_mips_elf_copy_private_bfd_data #define bfd_elf32_bfd_merge_private_bfd_data \ - mips_elf_merge_private_bfd_data -#define bfd_elf32_bfd_set_private_flags mips_elf_set_private_flags + _bfd_mips_elf_merge_private_bfd_data +#define bfd_elf32_bfd_set_private_flags _bfd_mips_elf_set_private_flags #define elf_backend_add_symbol_hook mips_elf_add_symbol_hook #define elf_backend_create_dynamic_sections \ mips_elf_create_dynamic_sections diff --git a/bfd/elf64-mips.c b/bfd/elf64-mips.c index 2f89b4818c2..ff0b0f242ff 100644 --- a/bfd/elf64-mips.c +++ b/bfd/elf64-mips.c @@ -67,6 +67,8 @@ static boolean mips_elf64_slurp_reloc_table static void mips_elf64_write_relocs PARAMS ((bfd *, asection *, PTR)); static boolean mips_elf64_section_from_shdr PARAMS ((bfd *, Elf_Internal_Shdr *, char *)); +static boolean mips_elf64_section_processing + PARAMS ((bfd *, Elf_Internal_Shdr *)); /* The relocation types. */ @@ -117,14 +119,6 @@ enum mips_elf64_reloc_type from smaller values. Start with zero, widen, *then* decrement. */ #define MINUS_ONE (((bfd_vma)0) - 1) -/* FIXME: These need to be rewritten, or we need to use the versions - in elf32-mips.c. */ -#define mips_elf_hi16_reloc bfd_elf_generic_reloc -#define mips_elf_lo16_reloc bfd_elf_generic_reloc -#define mips_elf_gprel16_reloc bfd_elf_generic_reloc -#define mips_elf_got16_reloc bfd_elf_generic_reloc -#define mips_elf_gprel32_reloc bfd_elf_generic_reloc - /* The relocation table used for SHT_REL sections. */ static reloc_howto_type mips_elf64_howto_table_rel[] = @@ -215,7 +209,7 @@ static reloc_howto_type mips_elf64_howto_table_rel[] = false, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ - mips_elf_hi16_reloc, /* special_function */ + _bfd_mips_elf_hi16_reloc, /* special_function */ "R_MIPS_HI16", /* name */ true, /* partial_inplace */ 0xffff, /* src_mask */ @@ -230,7 +224,7 @@ static reloc_howto_type mips_elf64_howto_table_rel[] = false, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ - mips_elf_lo16_reloc, /* special_function */ + _bfd_mips_elf_lo16_reloc, /* special_function */ "R_MIPS_LO16", /* name */ true, /* partial_inplace */ 0xffff, /* src_mask */ @@ -245,7 +239,7 @@ static reloc_howto_type mips_elf64_howto_table_rel[] = false, /* pc_relative */ 0, /* bitpos */ complain_overflow_signed, /* complain_on_overflow */ - mips_elf_gprel16_reloc, /* special_function */ + _bfd_mips_elf_gprel16_reloc, /* special_function */ "R_MIPS_GPREL16", /* name */ true, /* partial_inplace */ 0xffff, /* src_mask */ @@ -260,7 +254,7 @@ static reloc_howto_type mips_elf64_howto_table_rel[] = false, /* pc_relative */ 0, /* bitpos */ complain_overflow_signed, /* complain_on_overflow */ - mips_elf_gprel16_reloc, /* special_function */ + _bfd_mips_elf_gprel16_reloc, /* special_function */ "R_MIPS_LITERAL", /* name */ true, /* partial_inplace */ 0xffff, /* src_mask */ @@ -275,7 +269,7 @@ static reloc_howto_type mips_elf64_howto_table_rel[] = false, /* pc_relative */ 0, /* bitpos */ complain_overflow_signed, /* complain_on_overflow */ - mips_elf_got16_reloc, /* special_function */ + _bfd_mips_elf_got16_reloc, /* special_function */ "R_MIPS_GOT16", /* name */ false, /* partial_inplace */ 0, /* src_mask */ @@ -321,7 +315,7 @@ static reloc_howto_type mips_elf64_howto_table_rel[] = false, /* pc_relative */ 0, /* bitpos */ complain_overflow_bitfield, /* complain_on_overflow */ - mips_elf_gprel32_reloc, /* special_function */ + _bfd_mips_elf_gprel32_reloc, /* special_function */ "R_MIPS_GPREL32", /* name */ true, /* partial_inplace */ 0xffffffff, /* src_mask */ @@ -782,7 +776,7 @@ static reloc_howto_type mips_elf64_howto_table_rela[] = false, /* pc_relative */ 0, /* bitpos */ complain_overflow_signed, /* complain_on_overflow */ - mips_elf_gprel16_reloc, /* special_function */ + _bfd_mips_elf_gprel16_reloc, /* special_function */ "R_MIPS_GPREL16", /* name */ true, /* partial_inplace */ 0, /* src_mask */ @@ -797,7 +791,7 @@ static reloc_howto_type mips_elf64_howto_table_rela[] = false, /* pc_relative */ 0, /* bitpos */ complain_overflow_signed, /* complain_on_overflow */ - mips_elf_gprel16_reloc, /* special_function */ + _bfd_mips_elf_gprel16_reloc, /* special_function */ "R_MIPS_LITERAL", /* name */ true, /* partial_inplace */ 0, /* src_mask */ @@ -805,6 +799,7 @@ static reloc_howto_type mips_elf64_howto_table_rela[] = false), /* pcrel_offset */ /* Reference to global offset table. */ + /* FIXME: This is not handled correctly. */ HOWTO (R_MIPS_GOT16, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ @@ -812,7 +807,7 @@ static reloc_howto_type mips_elf64_howto_table_rela[] = false, /* pc_relative */ 0, /* bitpos */ complain_overflow_signed, /* complain_on_overflow */ - mips_elf_got16_reloc, /* special_function */ + bfd_elf_generic_reloc, /* special_function */ "R_MIPS_GOT16", /* name */ false, /* partial_inplace */ 0, /* src_mask */ @@ -858,7 +853,7 @@ static reloc_howto_type mips_elf64_howto_table_rela[] = false, /* pc_relative */ 0, /* bitpos */ complain_overflow_bitfield, /* complain_on_overflow */ - mips_elf_gprel32_reloc, /* special_function */ + _bfd_mips_elf_gprel32_reloc, /* special_function */ "R_MIPS_GPREL32", /* name */ true, /* partial_inplace */ 0, /* src_mask */ @@ -1725,6 +1720,47 @@ mips_elf64_write_relocs (abfd, sec, data) == count); } +/* The .MIPS.options section holds register information in an + Elf64_Reginfo structure. These routines swap them in and out. + They are globally visible because they are used outside of BFD. */ + +void +bfd_mips_elf64_swap_reginfo_in (abfd, ex, in) + bfd *abfd; + const Elf64_External_RegInfo *ex; + Elf64_Internal_RegInfo *in; +{ + in->ri_gprmask = bfd_h_get_32 (abfd, (bfd_byte *) ex->ri_gprmask); + in->ri_pad = bfd_h_get_32 (abfd, (bfd_byte *) ex->ri_pad); + in->ri_cprmask[0] = bfd_h_get_32 (abfd, (bfd_byte *) ex->ri_cprmask[0]); + in->ri_cprmask[1] = bfd_h_get_32 (abfd, (bfd_byte *) ex->ri_cprmask[1]); + in->ri_cprmask[2] = bfd_h_get_32 (abfd, (bfd_byte *) ex->ri_cprmask[2]); + in->ri_cprmask[3] = bfd_h_get_32 (abfd, (bfd_byte *) ex->ri_cprmask[3]); + in->ri_gp_value = bfd_h_get_64 (abfd, (bfd_byte *) ex->ri_gp_value); +} + +void +bfd_mips_elf64_swap_reginfo_out (abfd, in, ex) + bfd *abfd; + const Elf64_Internal_RegInfo *in; + Elf64_External_RegInfo *ex; +{ + bfd_h_put_32 (abfd, (bfd_vma) in->ri_gprmask, + (bfd_byte *) ex->ri_gprmask); + bfd_h_put_32 (abfd, (bfd_vma) in->ri_pad, + (bfd_byte *) ex->ri_pad); + bfd_h_put_32 (abfd, (bfd_vma) in->ri_cprmask[0], + (bfd_byte *) ex->ri_cprmask[0]); + bfd_h_put_32 (abfd, (bfd_vma) in->ri_cprmask[1], + (bfd_byte *) ex->ri_cprmask[1]); + bfd_h_put_32 (abfd, (bfd_vma) in->ri_cprmask[2], + (bfd_byte *) ex->ri_cprmask[2]); + bfd_h_put_32 (abfd, (bfd_vma) in->ri_cprmask[3], + (bfd_byte *) ex->ri_cprmask[3]); + bfd_h_put_64 (abfd, (bfd_vma) in->ri_gp_value, + (bfd_byte *) ex->ri_gp_value); +} + /* Handle a 64-bit MIPS ELF specific section. */ static boolean @@ -1736,8 +1772,103 @@ mips_elf64_section_from_shdr (abfd, hdr, name) if (! _bfd_mips_elf_section_from_shdr (abfd, hdr, name)) return false; + /* For a SHT_MIPS_OPTIONS section, look for a ODK_REGINFO entry, and + set the gp value based on what we find. We may see both + SHT_MIPS_REGINFO and SHT_MIPS_OPTIONS/ODK_REGINFO; in that case, + they should agree. */ + if (hdr->sh_type == SHT_MIPS_OPTIONS) + { + bfd_byte *contents, *l, *lend; + + contents = (bfd_byte *) bfd_malloc (hdr->sh_size); + if (contents == NULL) + return false; + if (! bfd_get_section_contents (abfd, hdr->bfd_section, contents, + (file_ptr) 0, hdr->sh_size)) + { + free (contents); + return false; + } + l = contents; + lend = contents + hdr->sh_size; + while (l + sizeof (Elf_External_Options) <= lend) + { + Elf_Internal_Options intopt; + + bfd_mips_elf_swap_options_in (abfd, (Elf_External_Options *) l, + &intopt); + if (intopt.kind == ODK_REGINFO) + { + Elf64_Internal_RegInfo intreg; + + bfd_mips_elf64_swap_reginfo_in + (abfd, + ((Elf64_External_RegInfo *) + (l + sizeof (Elf_External_Options))), + &intreg); + elf_gp (abfd) = intreg.ri_gp_value; + } + l += intopt.size; + } + free (contents); + } + return true; } + +/* Work over a section just before writing it out. We update the GP + value in the SHT_MIPS_OPTIONS section based on the value we are + using. */ + +static boolean +mips_elf64_section_processing (abfd, hdr) + bfd *abfd; + Elf_Internal_Shdr *hdr; +{ + if (hdr->sh_type == SHT_MIPS_OPTIONS + && hdr->bfd_section != NULL + && elf_section_data (hdr->bfd_section) != NULL + && elf_section_data (hdr->bfd_section)->tdata != NULL) + { + bfd_byte *contents, *l, *lend; + + /* We stored the section contents in the elf_section_data tdata + field in the set_section_contents routine. We save the + section contents so that we don't have to read them again. + At this point we know that elf_gp is set, so we can look + through the section contents to see if there is an + ODK_REGINFO structure. */ + + contents = (bfd_byte *) elf_section_data (hdr->bfd_section)->tdata; + l = contents; + lend = contents + hdr->sh_size; + while (l + sizeof (Elf_External_Options) <= lend) + { + Elf_Internal_Options intopt; + + bfd_mips_elf_swap_options_in (abfd, (Elf_External_Options *) l, + &intopt); + if (intopt.kind == ODK_REGINFO) + { + bfd_byte buf[8]; + + if (bfd_seek (abfd, + (hdr->sh_offset + + (l - contents) + + sizeof (Elf_External_Options) + + (sizeof (Elf64_External_RegInfo) - 8)), + SEEK_SET) == -1) + return false; + bfd_h_put_64 (abfd, elf_gp (abfd), buf); + if (bfd_write (buf, 1, 8, abfd) != 8) + return false; + } + l += intopt.size; + } + } + + return _bfd_mips_elf_section_processing (abfd, hdr); +} /* ECOFF swapping routines. These are used when dealing with the .mdebug section, which is in the ECOFF debugging format. */ @@ -1822,13 +1953,20 @@ const struct elf_size_info mips_elf64_size_info = #define elf_backend_fake_sections _bfd_mips_elf_fake_sections #define elf_backend_section_from_bfd_section \ _bfd_mips_elf_section_from_bfd_section -#define elf_backend_section_processing _bfd_mips_elf_section_processing +#define elf_backend_section_processing mips_elf64_section_processing #define elf_backend_symbol_processing _bfd_mips_elf_symbol_processing #define elf_backend_final_write_processing \ _bfd_mips_elf_final_write_processing #define elf_backend_ecoff_debug_swap &mips_elf64_ecoff_debug_swap +#define bfd_elf64_find_nearest_line _bfd_mips_elf_find_nearest_line #define bfd_elf64_get_reloc_upper_bound mips_elf64_get_reloc_upper_bound #define bfd_elf64_bfd_reloc_type_lookup mips_elf64_reloc_type_lookup +#define bfd_elf64_set_section_contents _bfd_mips_elf_set_section_contents +#define bfd_elf64_bfd_copy_private_bfd_data \ + _bfd_mips_elf_copy_private_bfd_data +#define bfd_elf64_bfd_merge_private_bfd_data \ + _bfd_mips_elf_merge_private_bfd_data +#define bfd_elf64_bfd_set_private_flags _bfd_mips_elf_set_private_flags #include "elf64-target.h"