X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Felfxx-mips.c;h=1345b3a3103d769fe6b56019b7fb731586c99ae8;hb=32866df75ece22ec1fd88e99e3c5effe9238e072;hp=c560e18f5693651eb0434d851993e6fb41236a42;hpb=af5978fb749478f01e76455e81e354c9d221c3fa;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elfxx-mips.c b/bfd/elfxx-mips.c index c560e18f56..1345b3a310 100644 --- a/bfd/elfxx-mips.c +++ b/bfd/elfxx-mips.c @@ -1,6 +1,6 @@ /* MIPS-specific support for ELF Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, - 2003, 2004, 2005, 2006 Free Software Foundation, Inc. + 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. Most of the information added by Ian Lance Taylor, Cygnus Support, . @@ -13,7 +13,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -23,12 +23,14 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + /* This file handles functionality common to the different MIPS ABI's. */ -#include "bfd.h" #include "sysdep.h" +#include "bfd.h" #include "libbfd.h" #include "libiberty.h" #include "elf-bfd.h" @@ -488,7 +490,7 @@ typedef struct runtime_pdr { static struct mips_got_entry *mips_elf_create_local_got_entry (bfd *, struct bfd_link_info *, bfd *, struct mips_got_info *, asection *, - asection *, bfd_vma, unsigned long, struct mips_elf_link_hash_entry *, int); + bfd_vma, unsigned long, struct mips_elf_link_hash_entry *, int); static bfd_boolean mips_elf_sort_hash_table_f (struct mips_elf_link_hash_entry *, void *); static bfd_vma mips_elf_high @@ -2413,16 +2415,14 @@ mips_elf_gotplt_index (struct bfd_link_info *info, return got_address - got_value; } -/* Return the GOT offset for address VALUE, which was derived from - a symbol belonging to INPUT_SECTION. If there is not yet a GOT +/* Return the GOT offset for address VALUE. If there is not yet a GOT entry for this value, create one. If R_SYMNDX refers to a TLS symbol, create a TLS GOT entry instead. Return -1 if no satisfactory GOT offset can be found. */ static bfd_vma mips_elf_local_got_index (bfd *abfd, bfd *ibfd, struct bfd_link_info *info, - asection *input_section, bfd_vma value, - unsigned long r_symndx, + bfd_vma value, unsigned long r_symndx, struct mips_elf_link_hash_entry *h, int r_type) { asection *sgot; @@ -2432,8 +2432,7 @@ mips_elf_local_got_index (bfd *abfd, bfd *ibfd, struct bfd_link_info *info, g = mips_elf_got_info (elf_hash_table (info)->dynobj, &sgot); entry = mips_elf_create_local_got_entry (abfd, info, ibfd, g, sgot, - input_section, value, - r_symndx, h, r_type); + value, r_symndx, h, r_type); if (!entry) return MINUS_ONE; @@ -2534,16 +2533,15 @@ mips_elf_global_got_index (bfd *abfd, bfd *ibfd, struct elf_link_hash_entry *h, return index; } -/* Find a GOT page entry that points to within 32KB of VALUE, which was - calculated from a symbol belonging to INPUT_SECTION. These entries - are supposed to be placed at small offsets in the GOT, i.e., within - 32KB of GP. Return the index of the GOT entry, or -1 if no entry - could be created. If OFFSETP is nonnull, use it to return the +/* Find a GOT page entry that points to within 32KB of VALUE. These + entries are supposed to be placed at small offsets in the GOT, i.e., + within 32KB of GP. Return the index of the GOT entry, or -1 if no + entry could be created. If OFFSETP is nonnull, use it to return the offset of the GOT entry from VALUE. */ static bfd_vma mips_elf_got_page (bfd *abfd, bfd *ibfd, struct bfd_link_info *info, - asection *input_section, bfd_vma value, bfd_vma *offsetp) + bfd_vma value, bfd_vma *offsetp) { asection *sgot; struct mips_got_info *g; @@ -2554,8 +2552,7 @@ mips_elf_got_page (bfd *abfd, bfd *ibfd, struct bfd_link_info *info, page = (value + 0x8000) & ~(bfd_vma) 0xffff; entry = mips_elf_create_local_got_entry (abfd, info, ibfd, g, sgot, - input_section, page, 0, - NULL, R_MIPS_GOT_PAGE); + page, 0, NULL, R_MIPS_GOT_PAGE); if (!entry) return MINUS_ONE; @@ -2568,15 +2565,13 @@ mips_elf_got_page (bfd *abfd, bfd *ibfd, struct bfd_link_info *info, return index; } -/* Find a local GOT entry for an R_MIPS_GOT16 relocation against VALUE, - which was calculated from a symbol belonging to INPUT_SECTION. +/* Find a local GOT entry for an R_MIPS_GOT16 relocation against VALUE. EXTERNAL is true if the relocation was against a global symbol that has been forced local. */ static bfd_vma mips_elf_got16_entry (bfd *abfd, bfd *ibfd, struct bfd_link_info *info, - asection *input_section, bfd_vma value, - bfd_boolean external) + bfd_vma value, bfd_boolean external) { asection *sgot; struct mips_got_info *g; @@ -2592,8 +2587,7 @@ mips_elf_got16_entry (bfd *abfd, bfd *ibfd, struct bfd_link_info *info, g = mips_elf_got_info (elf_hash_table (info)->dynobj, &sgot); entry = mips_elf_create_local_got_entry (abfd, info, ibfd, g, sgot, - input_section, value, 0, - NULL, R_MIPS_GOT16); + value, 0, NULL, R_MIPS_GOT16); if (entry) return entry->gotidx; else @@ -2626,8 +2620,8 @@ mips_elf_got_offset_from_index (bfd *dynobj, bfd *output_bfd, static struct mips_got_entry * mips_elf_create_local_got_entry (bfd *abfd, struct bfd_link_info *info, bfd *ibfd, struct mips_got_info *gg, - asection *sgot, asection *input_section, - bfd_vma value, unsigned long r_symndx, + asection *sgot, bfd_vma value, + unsigned long r_symndx, struct mips_elf_link_hash_entry *h, int r_type) { @@ -2708,30 +2702,23 @@ mips_elf_create_local_got_entry (bfd *abfd, struct bfd_link_info *info, MIPS_ELF_PUT_WORD (abfd, value, (sgot->contents + entry.gotidx)); - /* These GOT entries need a dynamic relocation on VxWorks. Because - the offset between segments is not fixed, the relocation must be - against a symbol in the same segment as the original symbol. - The easiest way to do this is to take INPUT_SECTION's output - section and emit a relocation against its section symbol. */ + /* These GOT entries need a dynamic relocation on VxWorks. */ if (htab->is_vxworks) { Elf_Internal_Rela outrel; - asection *s, *output_section; + asection *s; bfd_byte *loc; bfd_vma got_address; - int dynindx; s = mips_elf_rel_dyn_section (info, FALSE); - output_section = input_section->output_section; - dynindx = elf_section_data (output_section)->dynindx; got_address = (sgot->output_section->vma + sgot->output_offset + entry.gotidx); loc = s->contents + (s->reloc_count++ * sizeof (Elf32_External_Rela)); outrel.r_offset = got_address; - outrel.r_info = ELF32_R_INFO (dynindx, R_MIPS_32); - outrel.r_addend = value - output_section->vma; + outrel.r_info = ELF32_R_INFO (STN_UNDEF, R_MIPS_32); + outrel.r_addend = value; bfd_elf32_swap_reloca_out (abfd, &outrel, loc); } @@ -3201,6 +3188,7 @@ mips_elf_initialize_tls_index (void **entryp, void *p) struct mips_got_entry *entry = (struct mips_got_entry *)*entryp; struct mips_got_info *g = p; bfd_vma next_index; + unsigned char tls_type; /* We're only interested in TLS symbols. */ if (entry->tls_type == 0) @@ -3216,6 +3204,7 @@ mips_elf_initialize_tls_index (void **entryp, void *p) return 1; entry->d.h->tls_type |= GOT_TLS_OFFSET_DONE; entry->d.h->tls_got_offset = next_index; + tls_type = entry->d.h->tls_type; } else { @@ -3232,12 +3221,13 @@ mips_elf_initialize_tls_index (void **entryp, void *p) g->tls_ldm_offset = next_index; } entry->gotidx = next_index; + tls_type = entry->tls_type; } /* Account for the entries we've just allocated. */ - if (entry->tls_type & (GOT_TLS_GD | GOT_TLS_LDM)) + if (tls_type & (GOT_TLS_GD | GOT_TLS_LDM)) g->tls_assigned_gotno += 2; - if (entry->tls_type & GOT_TLS_IE) + if (tls_type & GOT_TLS_IE) g->tls_assigned_gotno += 1; return 1; @@ -4104,8 +4094,7 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd, /* If this is a 16-bit call to a 32- or 64-bit function with a stub, we need to redirect the call to the stub. */ else if (r_type == R_MIPS16_26 && !info->relocatable - && h != NULL - && ((h->call_stub != NULL || h->call_fp_stub != NULL) + && ((h != NULL && (h->call_stub != NULL || h->call_fp_stub != NULL)) || (local_p && elf_tdata (input_bfd)->local_call_stubs != NULL && elf_tdata (input_bfd)->local_call_stubs[r_symndx] != NULL)) @@ -4180,7 +4169,7 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd, if (r_type == R_MIPS_TLS_LDM) { g = mips_elf_local_got_index (abfd, input_bfd, info, - sec, 0, 0, NULL, r_type); + 0, 0, NULL, r_type); if (g == MINUS_ONE) return bfd_reloc_outofrange; } @@ -4226,7 +4215,7 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd, break; else { - g = mips_elf_local_got_index (abfd, input_bfd, info, sec, + g = mips_elf_local_got_index (abfd, input_bfd, info, symbol + addend, r_symndx, h, r_type); if (g == MINUS_ONE) return bfd_reloc_outofrange; @@ -4368,6 +4357,8 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd, break; case R_MIPS_TLS_DTPREL_LO16: + case R_MIPS_TLS_DTPREL32: + case R_MIPS_TLS_DTPREL64: value = (symbol + addend - dtprel_base (info)) & howto->dst_mask; break; @@ -4477,7 +4468,7 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd, forced = ! mips_elf_local_relocation_p (input_bfd, relocation, local_sections, FALSE); - value = mips_elf_got16_entry (abfd, input_bfd, info, sec, + value = mips_elf_got16_entry (abfd, input_bfd, info, symbol + addend, forced); if (value == MINUS_ONE) return bfd_reloc_outofrange; @@ -4533,8 +4524,7 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd, 0. */ if (! local_p) goto got_disp; - value = mips_elf_got_page (abfd, input_bfd, info, sec, - symbol + addend, NULL); + value = mips_elf_got_page (abfd, input_bfd, info, symbol + addend, NULL); if (value == MINUS_ONE) return bfd_reloc_outofrange; value = mips_elf_got_offset_from_index (dynobj, abfd, input_bfd, value); @@ -4543,8 +4533,7 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd, case R_MIPS_GOT_OFST: if (local_p) - mips_elf_got_page (abfd, input_bfd, info, sec, - symbol + addend, &value); + mips_elf_got_page (abfd, input_bfd, info, symbol + addend, &value); else value = addend; overflowed_p = mips_elf_overflow_p (value, 16); @@ -4786,10 +4775,13 @@ mips_elf_create_dynamic_relocation (bfd *output_bfd, outrel[0].r_offset = _bfd_elf_section_offset (output_bfd, info, input_section, rel[0].r_offset); - outrel[1].r_offset = - _bfd_elf_section_offset (output_bfd, info, input_section, rel[1].r_offset); - outrel[2].r_offset = - _bfd_elf_section_offset (output_bfd, info, input_section, rel[2].r_offset); + if (ABI_64_P (output_bfd)) + { + outrel[1].r_offset = + _bfd_elf_section_offset (output_bfd, info, input_section, rel[1].r_offset); + outrel[2].r_offset = + _bfd_elf_section_offset (output_bfd, info, input_section, rel[2].r_offset); + } if (outrel[0].r_offset == MINUS_ONE) /* The relocation field has been deleted. */ @@ -5590,11 +5582,7 @@ _bfd_mips_elf_section_from_shdr (bfd *abfd, bfd_boolean _bfd_mips_elf_fake_sections (bfd *abfd, Elf_Internal_Shdr *hdr, asection *sec) { - register const char *name; - unsigned int sh_type; - - name = bfd_get_section_name (abfd, sec); - sh_type = hdr->sh_type; + const char *name = bfd_get_section_name (abfd, sec); if (strcmp (name, ".liblist") == 0) { @@ -5695,12 +5683,6 @@ _bfd_mips_elf_fake_sections (bfd *abfd, Elf_Internal_Shdr *hdr, asection *sec) hdr->sh_entsize = 8; } - /* In the unlikely event a special section is empty it has to lose its - special meaning. This may happen e.g. when using `strip' with the - "--only-keep-debug" option. */ - if (sec->size > 0 && !(sec->flags & SEC_HAS_CONTENTS)) - hdr->sh_type = sh_type; - /* The generic elf_fake_sections will set up REL_HDR using the default kind of relocations. We used to set up a second header for the non-default kind of relocations here, but only NewABI would use @@ -7042,7 +7024,6 @@ _bfd_mips_vxworks_adjust_dynamic_symbol (struct bfd_link_info *info, bfd *dynobj; struct mips_elf_link_hash_entry *hmips; struct mips_elf_link_hash_table *htab; - unsigned int power_of_two; htab = mips_elf_hash_table (info); dynobj = elf_hash_table (info)->dynobj; @@ -7165,26 +7146,7 @@ _bfd_mips_vxworks_adjust_dynamic_symbol (struct bfd_link_info *info, h->needs_copy = 1; } - /* We need to figure out the alignment required for this symbol. */ - power_of_two = bfd_log2 (h->size); - if (power_of_two > 4) - power_of_two = 4; - - /* Apply the required alignment. */ - htab->sdynbss->size = BFD_ALIGN (htab->sdynbss->size, - (bfd_size_type) 1 << power_of_two); - if (power_of_two > bfd_get_section_alignment (dynobj, htab->sdynbss) - && !bfd_set_section_alignment (dynobj, htab->sdynbss, power_of_two)) - return FALSE; - - /* Define the symbol as being at this point in the section. */ - h->root.u.def.section = htab->sdynbss; - h->root.u.def.value = htab->sdynbss->size; - - /* Increment the section size to make room for the symbol. */ - htab->sdynbss->size += h->size; - - return TRUE; + return _bfd_elf_adjust_dynamic_copy (h, htab->sdynbss); } /* Return the number of dynamic section symbols required by OUTPUT_BFD. @@ -7584,19 +7546,23 @@ _bfd_mips_elf_size_dynamic_sections (bfd *output_bfd, /* Add some entries to the .dynamic section. We fill in the values later, in _bfd_mips_elf_finish_dynamic_sections, but we must add the entries now so that we get the correct size for - the .dynamic section. The DT_DEBUG entry is filled in by the - dynamic linker and used by the debugger. */ - if (info->executable - && !SGI_COMPAT (output_bfd) - && !MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_DEBUG, 0)) - return FALSE; + the .dynamic section. */ /* SGI object has the equivalence of DT_DEBUG in the - DT_MIPS_RLD_MAP entry. */ + DT_MIPS_RLD_MAP entry. This must come first because glibc + only fills in DT_MIPS_RLD_MAP (not DT_DEBUG) and GDB only + looks at the first one it sees. */ if (!info->shared && !MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_RLD_MAP, 0)) return FALSE; + /* The DT_DEBUG entry may be filled in by the dynamic linker and + used by the debugger. */ + if (info->executable + && !SGI_COMPAT (output_bfd) + && !MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_DEBUG, 0)) + return FALSE; + if (reltext && (SGI_COMPAT (output_bfd) || htab->is_vxworks)) info->flags |= DF_TEXTREL; @@ -10998,6 +10964,112 @@ mips_32bit_flags_p (flagword flags) } +/* Merge object attributes from IBFD into OBFD. Raise an error if + there are conflicting attributes. */ +static bfd_boolean +mips_elf_merge_obj_attributes (bfd *ibfd, bfd *obfd) +{ + obj_attribute *in_attr; + obj_attribute *out_attr; + + if (!elf_known_obj_attributes_proc (obfd)[0].i) + { + /* This is the first object. Copy the attributes. */ + _bfd_elf_copy_obj_attributes (ibfd, obfd); + + /* Use the Tag_null value to indicate the attributes have been + initialized. */ + elf_known_obj_attributes_proc (obfd)[0].i = 1; + + return TRUE; + } + + /* Check for conflicting Tag_GNU_MIPS_ABI_FP attributes and merge + non-conflicting ones. */ + in_attr = elf_known_obj_attributes (ibfd)[OBJ_ATTR_GNU]; + out_attr = elf_known_obj_attributes (obfd)[OBJ_ATTR_GNU]; + if (in_attr[Tag_GNU_MIPS_ABI_FP].i != out_attr[Tag_GNU_MIPS_ABI_FP].i) + { + out_attr[Tag_GNU_MIPS_ABI_FP].type = 1; + if (out_attr[Tag_GNU_MIPS_ABI_FP].i == 0) + out_attr[Tag_GNU_MIPS_ABI_FP].i = in_attr[Tag_GNU_MIPS_ABI_FP].i; + else if (in_attr[Tag_GNU_MIPS_ABI_FP].i == 0) + ; + else if (in_attr[Tag_GNU_MIPS_ABI_FP].i > 3) + _bfd_error_handler + (_("Warning: %B uses unknown floating point ABI %d"), ibfd, + in_attr[Tag_GNU_MIPS_ABI_FP].i); + else if (out_attr[Tag_GNU_MIPS_ABI_FP].i > 3) + _bfd_error_handler + (_("Warning: %B uses unknown floating point ABI %d"), obfd, + out_attr[Tag_GNU_MIPS_ABI_FP].i); + else + switch (out_attr[Tag_GNU_MIPS_ABI_FP].i) + { + case 1: + switch (in_attr[Tag_GNU_MIPS_ABI_FP].i) + { + case 2: + _bfd_error_handler + (_("Warning: %B uses -msingle-float, %B uses -mdouble-float"), + obfd, ibfd); + + case 3: + _bfd_error_handler + (_("Warning: %B uses hard float, %B uses soft float"), + obfd, ibfd); + break; + + default: + abort (); + } + break; + + case 2: + switch (in_attr[Tag_GNU_MIPS_ABI_FP].i) + { + case 1: + _bfd_error_handler + (_("Warning: %B uses -msingle-float, %B uses -mdouble-float"), + ibfd, obfd); + + case 3: + _bfd_error_handler + (_("Warning: %B uses hard float, %B uses soft float"), + obfd, ibfd); + break; + + default: + abort (); + } + break; + + case 3: + switch (in_attr[Tag_GNU_MIPS_ABI_FP].i) + { + case 1: + case 2: + _bfd_error_handler + (_("Warning: %B uses hard float, %B uses soft float"), + ibfd, obfd); + break; + + default: + abort (); + } + break; + + default: + abort (); + } + } + + /* Merge Tag_compatibility attributes and any common GNU ones. */ + _bfd_elf_merge_object_attributes (ibfd, obfd); + + return TRUE; +} + /* Merge backend specific data from an object file to the output object file when linking. */ @@ -11031,6 +11103,9 @@ _bfd_mips_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd) return FALSE; } + if (!mips_elf_merge_obj_attributes (ibfd, obfd)) + return FALSE; + new_flags = elf_elfheader (ibfd)->e_flags; elf_elfheader (obfd)->e_flags |= new_flags & EF_MIPS_NOREORDER; old_flags = elf_elfheader (obfd)->e_flags;