From 625af618e73144b15dcb1ff188ce91439ec4bd5b Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Tue, 26 Feb 2008 08:36:03 +0000 Subject: [PATCH] * elf32-ppc.c (ppc_elf_check_relocs): Set pointer_equality_needed for R_PPC_REL32 syms. Don't set non_got_ref on branch reloc syms, and assume branch relocs are not dynamic when non-shared. (readonly_dynrelocs): New function, split out from.. (maybe_set_textrel): ..here, renamed from old readonly_dynrelocs. (ppc_elf_adjust_dynamic_symbol): For symbols generating plt entries, clear non_got_ref.. (allocate_dynrelocs): ..and don't set u.def for undefined weak. Do allow dynamic relocs on undefined symbols. (ppc_elf_adjust_dynamic_symbol): Use readonly_dynrelocs. (ppc_elf_relocate_section): Mirror dynamic reloc changes in check_relocs. (ppc_elf_finish_dynamic_symbol): Don't give a warning on weak plt symbols needing pointer_equality_needed. --- bfd/ChangeLog | 17 +++++ bfd/elf32-ppc.c | 167 ++++++++++++++++++++++++++---------------------- 2 files changed, 109 insertions(+), 75 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 9a182a4eb9..1b54ff76e8 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,20 @@ +2008-02-26 Alan Modra + + * elf32-ppc.c (ppc_elf_check_relocs): Set pointer_equality_needed + for R_PPC_REL32 syms. Don't set non_got_ref on branch reloc syms, + and assume branch relocs are not dynamic when non-shared. + (readonly_dynrelocs): New function, split out from.. + (maybe_set_textrel): ..here, renamed from old readonly_dynrelocs. + (ppc_elf_adjust_dynamic_symbol): For symbols generating plt entries, + clear non_got_ref.. + (allocate_dynrelocs): ..and don't set u.def for undefined weak. + Do allow dynamic relocs on undefined symbols. + (ppc_elf_adjust_dynamic_symbol): Use readonly_dynrelocs. + (ppc_elf_relocate_section): Mirror dynamic reloc changes in + check_relocs. + (ppc_elf_finish_dynamic_symbol): Don't give a warning on weak + plt symbols needing pointer_equality_needed. + 2008-02-23 Alan Modra * elf32-ppc.c (ppc_elf_check_relocs): Revert non_got_ref change. diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c index 147efe2fc9..5e81a2f20e 100644 --- a/bfd/elf32-ppc.c +++ b/bfd/elf32-ppc.c @@ -3389,26 +3389,6 @@ ppc_elf_check_relocs (bfd *abfd, info->flags |= DF_STATIC_TLS; goto dodyn; - case R_PPC_ADDR32: - case R_PPC_ADDR16: - case R_PPC_ADDR16_LO: - case R_PPC_ADDR16_HI: - case R_PPC_ADDR16_HA: - case R_PPC_UADDR32: - case R_PPC_UADDR16: - if (h != NULL && !info->shared) - { - /* We may need a plt entry if the symbol turns out to be - a function defined in a dynamic object. */ - if (!update_plt_info (abfd, h, NULL, 0)) - return FALSE; - - /* We may need a copy reloc too. */ - h->non_got_ref = 1; - h->pointer_equality_needed = 1; - } - goto dodyn; - case R_PPC_REL32: if (h == NULL && got2 != NULL @@ -3434,7 +3414,27 @@ ppc_elf_check_relocs (bfd *abfd, } if (h == NULL || h == htab->elf.hgot) break; - goto dodyn1; + /* fall through */ + + case R_PPC_ADDR32: + case R_PPC_ADDR16: + case R_PPC_ADDR16_LO: + case R_PPC_ADDR16_HI: + case R_PPC_ADDR16_HA: + case R_PPC_UADDR32: + case R_PPC_UADDR16: + if (h != NULL && !info->shared) + { + /* We may need a plt entry if the symbol turns out to be + a function defined in a dynamic object. */ + if (!update_plt_info (abfd, h, NULL, 0)) + return FALSE; + + /* We may need a copy reloc too. */ + h->non_got_ref = 1; + h->pointer_equality_needed = 1; + } + goto dodyn; case R_PPC_REL24: case R_PPC_REL14: @@ -3457,16 +3457,13 @@ ppc_elf_check_relocs (bfd *abfd, case R_PPC_ADDR14: case R_PPC_ADDR14_BRTAKEN: case R_PPC_ADDR14_BRNTAKEN: - dodyn1: if (h != NULL && !info->shared) { /* We may need a plt entry if the symbol turns out to be a function defined in a dynamic object. */ if (!update_plt_info (abfd, h, NULL, 0)) return FALSE; - - /* We may need a copy reloc too. */ - h->non_got_ref = 1; + break; } dodyn: @@ -4289,6 +4286,25 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, return TRUE; } +/* Return true if we have dynamic relocs that apply to read-only sections. */ + +static bfd_boolean +readonly_dynrelocs (struct elf_link_hash_entry *h) +{ + struct ppc_elf_dyn_relocs *p; + + for (p = ppc_elf_hash_entry (h)->dyn_relocs; p != NULL; p = p->next) + { + asection *s = p->sec->output_section; + + if (s != NULL + && ((s->flags & (SEC_READONLY | SEC_ALLOC)) + == (SEC_READONLY | SEC_ALLOC))) + return TRUE; + } + return FALSE; +} + /* Adjust a symbol defined by a dynamic object and referenced by a regular object. The current definition is in some section of the dynamic object, but we're not including those sections. We have to @@ -4344,6 +4360,22 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info, h->plt.plist = NULL; h->needs_plt = 0; } + else + { + /* After adjust_dynamic_symbol, non_got_ref set means that + dyn_relocs for this symbol should be discarded. + If we get here we know we are making a PLT entry for this + symbol, and in an executable we'd normally resolve + relocations against this symbol to the PLT entry. Allow + dynamic relocs if the reference is weak, and the dynamic + relocs will not cause text relocation. */ + if (!h->ref_regular_nonweak + && h->non_got_ref + && !htab->is_vxworks + && !ppc_elf_hash_entry (h)->has_sda_refs + && !readonly_dynrelocs (h)) + h->non_got_ref = 0; + } return TRUE; } else @@ -4386,21 +4418,12 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info, executable. */ if (ELIMINATE_COPY_RELOCS && !ppc_elf_hash_entry (h)->has_sda_refs - && !htab->is_vxworks) + && !htab->is_vxworks + && !h->def_regular + && !readonly_dynrelocs (h)) { - struct ppc_elf_dyn_relocs *p; - for (p = ppc_elf_hash_entry (h)->dyn_relocs; p != NULL; p = p->next) - { - s = p->sec->output_section; - if (s != NULL && (s->flags & SEC_READONLY) != 0) - break; - } - - if (p == NULL) - { - h->non_got_ref = 0; - return TRUE; - } + h->non_got_ref = 0; + return TRUE; } if (h->size == 0) @@ -4597,6 +4620,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) } if (!doneone && !info->shared + && h->def_dynamic && !h->def_regular) { h->root.u.def.section = s; @@ -4634,6 +4658,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) function pointers compare as equal between the normal executable and the shared library. */ if (! info->shared + && h->def_dynamic && !h->def_regular) { h->root.u.def.section = s; @@ -4811,7 +4836,6 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) dynamic. */ if (!h->non_got_ref - && h->def_dynamic && !h->def_regular) { /* Make sure this symbol is output as a dynamic symbol. @@ -4844,32 +4868,24 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) return TRUE; } -/* Find any dynamic relocs that apply to read-only sections. */ +/* Set DF_TEXTREL if we find any dynamic relocs that apply to + read-only sections. */ static bfd_boolean -readonly_dynrelocs (struct elf_link_hash_entry *h, void *info) +maybe_set_textrel (struct elf_link_hash_entry *h, void *info) { - struct ppc_elf_dyn_relocs *p; - if (h->root.type == bfd_link_hash_indirect) return TRUE; if (h->root.type == bfd_link_hash_warning) h = (struct elf_link_hash_entry *) h->root.u.i.link; - for (p = ppc_elf_hash_entry (h)->dyn_relocs; p != NULL; p = p->next) + if (readonly_dynrelocs (h)) { - asection *s = p->sec->output_section; + ((struct bfd_link_info *) info)->flags |= DF_TEXTREL; - if (s != NULL - && ((s->flags & (SEC_READONLY | SEC_ALLOC)) - == (SEC_READONLY | SEC_ALLOC))) - { - ((struct bfd_link_info *) info)->flags |= DF_TEXTREL; - - /* Not an error, just cut short the traversal. */ - return FALSE; - } + /* Not an error, just cut short the traversal. */ + return FALSE; } return TRUE; } @@ -5184,7 +5200,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, /* If any dynamic relocs apply to a read-only section, then we need a DT_TEXTREL entry. */ if ((info->flags & DF_TEXTREL) == 0) - elf_link_hash_traverse (elf_hash_table (info), readonly_dynrelocs, + elf_link_hash_traverse (elf_hash_table (info), maybe_set_textrel, info); if ((info->flags & DF_TEXTREL) != 0) @@ -6404,8 +6420,21 @@ ppc_elf_relocate_section (bfd *output_bfd, case R_PPC_REL16_HA: break; - case R_PPC_REL24: case R_PPC_REL32: + if (h == NULL || h == htab->elf.hgot) + break; + /* fall through */ + + case R_PPC_ADDR32: + case R_PPC_ADDR16: + case R_PPC_ADDR16_LO: + case R_PPC_ADDR16_HI: + case R_PPC_ADDR16_HA: + case R_PPC_UADDR32: + case R_PPC_UADDR16: + goto dodyn; + + case R_PPC_REL24: case R_PPC_REL14: case R_PPC_REL14_BRTAKEN: case R_PPC_REL14_BRNTAKEN: @@ -6416,23 +6445,17 @@ ppc_elf_relocate_section (bfd *output_bfd, break; /* fall through */ - /* Relocations that always need to be propagated if this is a shared - object. */ - case R_PPC_ADDR32: case R_PPC_ADDR24: - case R_PPC_ADDR16: - case R_PPC_ADDR16_LO: - case R_PPC_ADDR16_HI: - case R_PPC_ADDR16_HA: case R_PPC_ADDR14: case R_PPC_ADDR14_BRTAKEN: case R_PPC_ADDR14_BRNTAKEN: - case R_PPC_UADDR32: - case R_PPC_UADDR16: + if (h != NULL && !info->shared) + break; + /* fall through */ + dodyn: if ((input_section->flags & SEC_ALLOC) == 0) break; - /* Fall thru. */ if ((info->shared && (h == NULL @@ -6445,7 +6468,6 @@ ppc_elf_relocate_section (bfd *output_bfd, && h != NULL && h->dynindx != -1 && !h->non_got_ref - && h->def_dynamic && !h->def_regular)) { int skip; @@ -7167,14 +7189,9 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd, sym->st_value = 0; else if (!h->ref_regular_nonweak) { - /* Choose your poison. We must have either text - dynamic relocations, broken function pointer - comparisons, or broken tests for a NULL + /* This breaks function pointer comparisons, but + that is better than breaking tests for a NULL function pointer. */ - (*_bfd_error_handler) - (_("weak reference to %s in non-pic code" - " will break function pointer comparisons"), - h->root.root.string); sym->st_value = 0; } } -- 2.34.1