diff options
author | Richard Sandiford <rdsandiford@googlemail.com> | 2010-09-19 10:26:28 +0000 |
---|---|---|
committer | Richard Sandiford <rdsandiford@googlemail.com> | 2010-09-19 10:26:28 +0000 |
commit | 020d7251584c7ac86ab48a9eaa9bdefc53935d09 (patch) | |
tree | 7da3adaef886606b7da697a049b37a548fa8913d /bfd/elfxx-mips.c | |
parent | f7ff11061f3278dce60be909b9f63d94cbd38afd (diff) | |
download | fsf-binutils-gdb-020d7251584c7ac86ab48a9eaa9bdefc53935d09.zip fsf-binutils-gdb-020d7251584c7ac86ab48a9eaa9bdefc53935d09.tar.gz fsf-binutils-gdb-020d7251584c7ac86ab48a9eaa9bdefc53935d09.tar.bz2 |
bfd/
* elfxx-mips.c (mips_got_entry): Adjust commentary.
(mips_elf_create_local_got_entry): If given a symbol, check that it
has been assigned to the local part of the GOT.
(mips_elf_count_got_symbols): Take the bfd_link_info as argument
instead of the master GOT. Put all locally-binding symbols in
the local area.
(mips_elf_make_got_per_bfd): Use global_got_area to decide whether
a symbol lives in the local or global area.
(mips_elf_local_relocation_p): Remove check_forced argument and
retain only the !check_forced behavior.
(mips_elf_calculate_relocation): Adjust call accordingly.
Use global_got_area to decide whether an output relocation
should be local or global. Explicitly decay R_MIPS_GOT_PAGE
into R_MIPS_GOT_DISP where appropriate. Fix selection of
local vs. global semantics for R_MIPS*_26. Remove redundant
reevaluation of what is stored in was_local_p.
(mips_elf_create_dynamic_relocation): Use global_got_area to decide
whether the relocation should be against a global or local symbol.
(mips_elf_lay_out_got): Update the GOT traversal after the above
change to mips_elf_count_got_symbols.
(mips_elf_adjust_addend): Adjust call to mips_elf_local_relocation_p.
(_bfd_mips_elf_relocate_section): Likewise.
(_bfd_mips_elf_finish_dynamic_symbol): Use global_got_area to decide
whether the symbol has a global got entry.
(_bfd_mips_vxworks_finish_dynamic_symbol): Likewise.
ld/testsuite/
* ld-mips-elf/elf-rel-got-n32.d: Swap two local GOT entries
and remove some duplication between the global and local GOT
entries. Adjust GP offsets accordingly.
* ld-mips-elf/elf-rel-got-n64-linux.d: Likewise.
* ld-mips-elf/elf-rel-xgot-n32.d: Reorder GOT entries and update
GP offsets accordingly.
* ld-mips-elf/elf-rel-xgot-n64-linux.d: Likewise.
* ld-mips-elf/mips16-pic-1.gd: Move all global GOT entries to
the local GOT.
* ld-mips-elf/mips16-pic-1.dd: Update GP offsets accordingly.
* ld-mips-elf/multi-got-no-shared.d: Adjust GP setup for
smaller GOT sizes.
Diffstat (limited to 'bfd/elfxx-mips.c')
-rw-r--r-- | bfd/elfxx-mips.c | 135 |
1 files changed, 55 insertions, 80 deletions
diff --git a/bfd/elfxx-mips.c b/bfd/elfxx-mips.c index 6b30f11..804a7d4 100644 --- a/bfd/elfxx-mips.c +++ b/bfd/elfxx-mips.c @@ -53,7 +53,7 @@ (abfd == NULL) (2) SYMBOL + OFFSET addresses, where SYMBOL is local to an input bfd (abfd != NULL, symndx >= 0) - (3) global and forced-local symbols + (3) SYMBOL addresses, where SYMBOL is not local to an input bfd (abfd != NULL, symndx == -1) Type (3) entries are treated differently for different types of GOT. @@ -94,8 +94,9 @@ struct mips_got_entry that should be added to the symbol value. */ bfd_vma addend; /* If abfd != NULL && symndx == -1, the hash table entry - corresponding to a global symbol in the got (or, local, if - h->forced_local). */ + corresponding to symbol in the GOT. The symbol's entry + is in the local area if h->global_got_area is GGA_NONE, + otherwise it is in the global area. */ struct mips_elf_link_hash_entry *h; } d; @@ -3202,8 +3203,8 @@ mips_elf_got_page (bfd *abfd, bfd *ibfd, struct bfd_link_info *info, } /* 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. */ + EXTERNAL is true if the relocation was originally against a global + symbol that binds locally. */ static bfd_vma mips_elf_got16_entry (bfd *abfd, bfd *ibfd, struct bfd_link_info *info, @@ -3281,11 +3282,9 @@ mips_elf_create_local_got_entry (bfd *abfd, struct bfd_link_info *info, BFD_ASSERT (g != NULL); } - /* We might have a symbol, H, if it has been forced local. Use the - global entry then. It doesn't matter whether an entry is local - or global for TLS, since the dynamic linker does not - automatically relocate TLS GOT entries. */ - BFD_ASSERT (h == NULL || h->root.forced_local); + /* This function shouldn't be called for symbols that live in the global + area of the GOT. */ + BFD_ASSERT (h == NULL || h->global_got_area == GGA_NONE); if (TLS_RELOC_P (r_type)) { struct mips_got_entry *p; @@ -3850,21 +3849,33 @@ mips_elf_resolve_final_got_entries (struct mips_got_info *g) } /* A mips_elf_link_hash_traverse callback for which DATA points - to a mips_got_info. Count the number of type (3) entries. */ + to the link_info structure. Count the number of type (3) entries + in the master GOT. */ static int mips_elf_count_got_symbols (struct mips_elf_link_hash_entry *h, void *data) { + struct bfd_link_info *info; struct mips_got_info *g; - g = (struct mips_got_info *) data; + info = (struct bfd_link_info *) data; + g = mips_elf_hash_table (info)->got_info; if (h->global_got_area != GGA_NONE) { - if (h->root.forced_local || h->root.dynindx == -1) + /* Make a final decision about whether the symbol belongs in the + local or global GOT. Symbols that bind locally can (and in the + case of forced-local symbols, must) live in the local GOT. + Those that are aren't in the dynamic symbol table must also + live in the local GOT. + + Note that the former condition does not always imply the + latter: symbols do not bind locally if they are completely + undefined. We'll report undefined symbols later if appropriate. */ + if (h->root.dynindx == -1 || SYMBOL_REFERENCES_LOCAL (info, &h->root)) { - /* We no longer need this entry if it was only used for - relocations; those relocations will be against the - null or section symbol instead of H. */ + /* The symbol belongs in the local GOT. We no longer need this + entry if it was only used for relocations; those relocations + will be against the null or section symbol instead of H. */ if (h->global_got_area != GGA_RELOC_ONLY) g->local_gotno++; h->global_got_area = GGA_NONE; @@ -4010,7 +4021,7 @@ mips_elf_make_got_per_bfd (void **entryp, void *p) if (entry->tls_type & GOT_TLS_IE) g->tls_gotno += 1; } - else if (entry->symndx >= 0 || entry->d.h->root.forced_local) + else if (entry->symndx >= 0 || entry->d.h->global_got_area == GGA_NONE) ++g->local_gotno; else ++g->global_gotno; @@ -4557,17 +4568,15 @@ mips_elf_next_relocation (bfd *abfd ATTRIBUTE_UNUSED, unsigned int r_type, return NULL; } -/* Return whether a relocation is against a local symbol. */ +/* Return whether an input relocation is against a local symbol. */ static bfd_boolean mips_elf_local_relocation_p (bfd *input_bfd, const Elf_Internal_Rela *relocation, - asection **local_sections, - bfd_boolean check_forced) + asection **local_sections) { unsigned long r_symndx; Elf_Internal_Shdr *symtab_hdr; - struct mips_elf_link_hash_entry *h; size_t extsymoff; r_symndx = ELF_R_SYM (input_bfd, relocation->r_info); @@ -4579,20 +4588,6 @@ mips_elf_local_relocation_p (bfd *input_bfd, if (elf_bad_symtab (input_bfd) && local_sections[r_symndx] != NULL) return TRUE; - if (check_forced) - { - /* Look up the hash table to check whether the symbol - was forced local. */ - h = (struct mips_elf_link_hash_entry *) - elf_sym_hashes (input_bfd) [r_symndx - extsymoff]; - /* Find the real hash-table entry for this symbol. */ - while (h->root.root.type == bfd_link_hash_indirect - || h->root.root.type == bfd_link_hash_warning) - h = (struct mips_elf_link_hash_entry *) h->root.root.u.i.link; - if (h->root.forced_local) - return TRUE; - } - return FALSE; } @@ -4900,7 +4895,7 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd, used in the array of hash table entries. */ symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; local_p = mips_elf_local_relocation_p (input_bfd, relocation, - local_sections, FALSE); + local_sections); was_local_p = local_p; if (! elf_bad_symtab (input_bfd)) extsymoff = symtab_hdr->sh_info; @@ -5134,8 +5129,7 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd, || ((r_type == R_MIPS_26 || r_type == R_MIPS_JALR) && target_is_16_bit_code_p)); - local_p = mips_elf_local_relocation_p (input_bfd, relocation, - local_sections, TRUE); + local_p = h == NULL || SYMBOL_REFERENCES_LOCAL (info, &h->root); gp0 = _bfd_get_gp_value (input_bfd); gp = _bfd_get_gp_value (abfd); @@ -5145,19 +5139,18 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd, if (gnu_local_gp_p) symbol = gp; + /* Global R_MIPS_GOT_PAGE relocations are equivalent to R_MIPS_GOT_DISP. + The addend is applied by the corresponding R_MIPS_GOT_OFST. */ + if (r_type == R_MIPS_GOT_PAGE && !local_p) + { + r_type = R_MIPS_GOT_DISP; + addend = 0; + } + /* If we haven't already determined the GOT offset, oand we're going to need it, get it now. */ switch (r_type) { - case R_MIPS_GOT_PAGE: - case R_MIPS_GOT_OFST: - /* We need to decay to GOT_DISP/addend if the symbol doesn't - bind locally. */ - local_p = local_p || _bfd_elf_symbol_refs_local_p (&h->root, info, 1); - if (local_p || r_type == R_MIPS_GOT_OFST) - break; - /* Fall through. */ - case R_MIPS16_CALL16: case R_MIPS16_GOT16: case R_MIPS_CALL16: @@ -5193,21 +5186,12 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd, } else { - /* GOT_PAGE may take a non-zero addend, that is ignored in a - GOT_PAGE relocation that decays to GOT_DISP because the - symbol turns out to be global. The addend is then added - as GOT_OFST. */ - BFD_ASSERT (addend == 0 || r_type == R_MIPS_GOT_PAGE); + BFD_ASSERT (addend == 0); g = mips_elf_global_got_index (dynobj, input_bfd, &h->root, r_type, info); if (h->tls_type == GOT_NORMAL - && (! elf_hash_table(info)->dynamic_sections_created - || (info->shared - && (info->symbolic || h->root.forced_local) - && h->root.def_regular))) - /* This is a static link or a -Bsymbolic link. The - symbol is defined locally, or was forced to be local. - We must initialize this entry in the GOT. */ + && !elf_hash_table (info)->dynamic_sections_created) + /* This is a static link. We must initialize the GOT entry. */ MIPS_ELF_PUT_WORD (dynobj, symbol, htab->sgot->contents + g); } } @@ -5321,7 +5305,7 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd, mips_elf_perform_relocation. So, we just fall through to the R_MIPS_26 case here. */ case R_MIPS_26: - if (local_p) + if (was_local_p) value = ((addend | ((p + 4) & 0xf0000000)) + symbol) >> 2; else { @@ -5447,12 +5431,8 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd, R_MIPS*_GOT16; every relocation evaluates to "G". */ if (!htab->is_vxworks && local_p) { - bfd_boolean forced; - - forced = ! mips_elf_local_relocation_p (input_bfd, relocation, - local_sections, FALSE); value = mips_elf_got16_entry (abfd, input_bfd, info, - symbol + addend, forced); + symbol + addend, !was_local_p); if (value == MINUS_ONE) return bfd_reloc_outofrange; value @@ -5467,7 +5447,6 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd, case R_MIPS_TLS_GOTTPREL: case R_MIPS_TLS_LDM: case R_MIPS_GOT_DISP: - got_disp: value = g; overflowed_p = mips_elf_overflow_p (value, 16); break; @@ -5502,11 +5481,6 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd, break; case R_MIPS_GOT_PAGE: - /* GOT_PAGE relocations that reference non-local symbols decay - to GOT_DISP. The corresponding GOT_OFST relocation decays to - 0. */ - if (! local_p) - goto got_disp; value = mips_elf_got_page (abfd, input_bfd, info, symbol + addend, NULL); if (value == MINUS_ONE) return bfd_reloc_outofrange; @@ -5757,6 +5731,7 @@ mips_elf_create_dynamic_relocation (bfd *output_bfd, in the relocation. */ if (h != NULL && ! SYMBOL_REFERENCES_LOCAL (info, &h->root)) { + BFD_ASSERT (htab->is_vxworks || h->global_got_area != GGA_NONE); indx = h->root.dynindx; if (SGI_COMPAT (output_bfd)) defined_p = h->root.def_regular; @@ -8463,7 +8438,7 @@ mips_elf_lay_out_got (bfd *output_bfd, struct bfd_link_info *info) return FALSE; /* Count the number of GOT symbols. */ - mips_elf_link_hash_traverse (htab, mips_elf_count_got_symbols, g); + mips_elf_link_hash_traverse (htab, mips_elf_count_got_symbols, info); /* Calculate the total loadable size of the output. That will give us the maximum number of GOT_PAGE entries @@ -8922,7 +8897,7 @@ mips_elf_adjust_addend (bfd *output_bfd, struct bfd_link_info *info, Elf_Internal_Sym *sym; asection *sec; - if (mips_elf_local_relocation_p (input_bfd, rel, local_sections, FALSE)) + if (mips_elf_local_relocation_p (input_bfd, rel, local_sections)) { r_type = ELF_R_TYPE (output_bfd, rel->r_info); if (r_type == R_MIPS16_GPREL @@ -8992,7 +8967,7 @@ _bfd_mips_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, r_symndx = ELF_R_SYM (input_bfd, rel->r_info); symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - if (mips_elf_local_relocation_p (input_bfd, rel, local_sections, FALSE)) + if (mips_elf_local_relocation_p (input_bfd, rel, local_sections)) { sec = local_sections[r_symndx]; h = NULL; @@ -9057,7 +9032,7 @@ _bfd_mips_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, if (hi16_reloc_p (r_type) || (got16_reloc_p (r_type) && mips_elf_local_relocation_p (input_bfd, rel, - local_sections, FALSE))) + local_sections))) { if (!mips_elf_add_lo16_rel_addend (input_bfd, rel, relend, contents, &addend)) @@ -9583,8 +9558,7 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd, /* Run through the global symbol table, creating GOT entries for all the symbols that need them. */ - if (g->global_gotsym != NULL - && h->dynindx >= g->global_gotsym->dynindx) + if (hmips->global_got_area != GGA_NONE) { bfd_vma offset; bfd_vma value; @@ -9595,7 +9569,7 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd, MIPS_ELF_PUT_WORD (output_bfd, value, sgot->contents + offset); } - if (g->next && h->dynindx != -1 && h->type != STT_TLS) + if (hmips->global_got_area != GGA_NONE && g->next && h->type != STT_TLS) { struct mips_got_entry e, *p; bfd_vma entry; @@ -9761,10 +9735,12 @@ _bfd_mips_vxworks_finish_dynamic_symbol (bfd *output_bfd, asection *sgot; struct mips_got_info *g; struct mips_elf_link_hash_table *htab; + struct mips_elf_link_hash_entry *hmips; htab = mips_elf_hash_table (info); BFD_ASSERT (htab != NULL); dynobj = elf_hash_table (info)->dynobj; + hmips = (struct mips_elf_link_hash_entry *) h; if (h->plt.offset != (bfd_vma) -1) { @@ -9870,8 +9846,7 @@ _bfd_mips_vxworks_finish_dynamic_symbol (bfd *output_bfd, BFD_ASSERT (g != NULL); /* See if this symbol has an entry in the GOT. */ - if (g->global_gotsym != NULL - && h->dynindx >= g->global_gotsym->dynindx) + if (hmips->global_got_area != GGA_NONE) { bfd_vma offset; Elf_Internal_Rela outrel; |