From eeb2f20a764bee3a6a1edb9872467d044aaad848 Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Fri, 1 Sep 2017 13:03:40 -0700 Subject: x86: Add _bfd_x86_elf_adjust_dynamic_symbol Share _bfd_x86_elf_adjust_dynamic_symbol in elf32-i386.c and elf64-x86-64.c. * elf32-i386.c (elf_i386_adjust_dynamic_symbol): Removed. (elf_backend_adjust_dynamic_symbol): Likewise. * elf64-x86-64.c (elf_x86_64_adjust_dynamic_symbol): Likewise. (elf_backend_adjust_dynamic_symbol): Likewise. * elfxx-x86.c (_bfd_x86_elf_adjust_dynamic_symbol): New function. (_bfd_x86_elf_link_setup_gnu_properties): Copy is_vxworks. * elfxx-x86.h (elf_x86_link_hash_table): Add is_vxworks. (_bfd_x86_elf_adjust_dynamic_symbol): New. (elf_backend_adjust_dynamic_symbol): Likewise. --- bfd/elfxx-x86.c | 209 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 208 insertions(+), 1 deletion(-) (limited to 'bfd/elfxx-x86.c') diff --git a/bfd/elfxx-x86.c b/bfd/elfxx-x86.c index 91bd61557e..cb5f6142c3 100644 --- a/bfd/elfxx-x86.c +++ b/bfd/elfxx-x86.c @@ -539,6 +539,211 @@ _bfd_x86_elf_hash_symbol (struct elf_link_hash_entry *h) return _bfd_elf_hash_symbol (h); } +/* 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 + change the definition to something the rest of the link can + understand. */ + +bfd_boolean +_bfd_x86_elf_adjust_dynamic_symbol (struct bfd_link_info *info, + struct elf_link_hash_entry *h) +{ + struct elf_x86_link_hash_table *htab; + asection *s, *srel; + struct elf_x86_link_hash_entry *eh; + struct elf_dyn_relocs *p; + const struct elf_backend_data *bed + = get_elf_backend_data (info->output_bfd); + + /* STT_GNU_IFUNC symbol must go through PLT. */ + if (h->type == STT_GNU_IFUNC) + { + /* All local STT_GNU_IFUNC references must be treate as local + calls via local PLT. */ + if (h->ref_regular + && SYMBOL_CALLS_LOCAL (info, h)) + { + bfd_size_type pc_count = 0, count = 0; + struct elf_dyn_relocs **pp; + + eh = (struct elf_x86_link_hash_entry *) h; + for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) + { + pc_count += p->pc_count; + p->count -= p->pc_count; + p->pc_count = 0; + count += p->count; + if (p->count == 0) + *pp = p->next; + else + pp = &p->next; + } + + if (pc_count || count) + { + h->non_got_ref = 1; + if (pc_count) + { + /* Increment PLT reference count only for PC-relative + references. */ + h->needs_plt = 1; + if (h->plt.refcount <= 0) + h->plt.refcount = 1; + else + h->plt.refcount += 1; + } + } + } + + if (h->plt.refcount <= 0) + { + h->plt.offset = (bfd_vma) -1; + h->needs_plt = 0; + } + return TRUE; + } + + /* If this is a function, put it in the procedure linkage table. We + will fill in the contents of the procedure linkage table later, + when we know the address of the .got section. */ + if (h->type == STT_FUNC + || h->needs_plt) + { + if (h->plt.refcount <= 0 + || SYMBOL_CALLS_LOCAL (info, h) + || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT + && h->root.type == bfd_link_hash_undefweak)) + { + /* This case can occur if we saw a PLT32 reloc in an input + file, but the symbol was never referred to by a dynamic + object, or if all references were garbage collected. In + such a case, we don't actually need to build a procedure + linkage table, and we can just do a PC32 reloc instead. */ + h->plt.offset = (bfd_vma) -1; + h->needs_plt = 0; + } + + return TRUE; + } + else + /* It's possible that we incorrectly decided a .plt reloc was needed + * for an R_386_PC32/R_X86_64_PC32 reloc to a non-function sym in + check_relocs. We can't decide accurately between function and + non-function syms in check-relocs; Objects loaded later in + the link may change h->type. So fix it now. */ + h->plt.offset = (bfd_vma) -1; + + eh = (struct elf_x86_link_hash_entry *) h; + + /* If this is a weak symbol, and there is a real definition, the + processor independent code will have arranged for us to see the + real definition first, and we can just use the same value. */ + if (h->u.weakdef != NULL) + { + BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined + || h->u.weakdef->root.type == bfd_link_hash_defweak); + h->root.u.def.section = h->u.weakdef->root.u.def.section; + h->root.u.def.value = h->u.weakdef->root.u.def.value; + if (ELIMINATE_COPY_RELOCS + || info->nocopyreloc + || SYMBOL_NO_COPYRELOC (info, eh)) + { + /* NB: needs_copy is always 0 for i386. */ + h->non_got_ref = h->u.weakdef->non_got_ref; + eh->needs_copy = h->u.weakdef->needs_copy; + } + return TRUE; + } + + /* This is a reference to a symbol defined by a dynamic object which + is not a function. */ + + /* If we are creating a shared library, we must presume that the + only references to the symbol are via the global offset table. + For such cases we need not do anything here; the relocations will + be handled correctly by relocate_section. */ + if (!bfd_link_executable (info)) + return TRUE; + + /* If there are no references to this symbol that do not use the + GOT nor R_386_GOTOFF relocation, we don't need to generate a copy + reloc. NB: gotoff_ref is always 0 for x86-64. */ + if (!h->non_got_ref && !eh->gotoff_ref) + return TRUE; + + /* If -z nocopyreloc was given, we won't generate them either. */ + if (info->nocopyreloc || SYMBOL_NO_COPYRELOC (info, eh)) + { + h->non_got_ref = 0; + return TRUE; + } + + htab = elf_x86_hash_table (info, bed->target_id); + if (htab == NULL) + return FALSE; + + /* If there aren't any dynamic relocs in read-only sections nor + R_386_GOTOFF relocation, then we can keep the dynamic relocs and + avoid the copy reloc. This doesn't work on VxWorks, where we can + not have dynamic relocations (other than copy and jump slot + relocations) in an executable. */ + if (ELIMINATE_COPY_RELOCS + && (bed->target_id == X86_64_ELF_DATA + || (!eh->gotoff_ref + && !htab->is_vxworks))) + { + for (p = eh->dyn_relocs; p != NULL; p = p->next) + { + s = p->sec->output_section; + if (s != NULL && (s->flags & SEC_READONLY) != 0) + break; + } + + /* If we didn't find any dynamic relocs in read-only sections, + then we'll be keeping the dynamic relocs and avoiding the copy + reloc. */ + if (p == NULL) + { + h->non_got_ref = 0; + return TRUE; + } + } + + /* We must allocate the symbol in our .dynbss section, which will + become part of the .bss section of the executable. There will be + an entry for this symbol in the .dynsym section. The dynamic + object will contain position independent code, so all references + from the dynamic object to this symbol will go through the global + offset table. The dynamic linker will use the .dynsym entry to + determine the address it must put in the global offset table, so + both the dynamic object and the regular object will refer to the + same memory location for the variable. */ + + /* We must generate a R_386_COPY/R_X86_64_COPY reloc to tell the + dynamic linker to copy the initial value out of the dynamic object + and into the runtime process image. */ + if ((h->root.u.def.section->flags & SEC_READONLY) != 0) + { + s = htab->elf.sdynrelro; + srel = htab->elf.sreldynrelro; + } + else + { + s = htab->elf.sdynbss; + srel = htab->elf.srelbss; + } + if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0) + { + srel->size += ((bed->target_id == I386_ELF_DATA) + ? sizeof (Elf32_External_Rel) + : bed->s->sizeof_rela); + h->needs_copy = 1; + } + + return _bfd_elf_adjust_dynamic_copy (info, h, s); +} + static bfd_vma elf_i386_get_plt_got_vma (struct elf_x86_plt *plt_p ATTRIBUTE_UNUSED, bfd_vma off, @@ -997,6 +1202,8 @@ error_alignment: if (htab == NULL) return pbfd; + htab->is_vxworks = plt_layout->is_vxworks; + use_ibt_plt = info->ibtplt || info->ibt; if (!use_ibt_plt && pbfd != NULL) { @@ -1119,7 +1326,7 @@ error_alignment: if (dynobj == NULL) return pbfd; - if (plt_layout->is_vxworks + if (htab->is_vxworks && !elf_vxworks_create_dynamic_sections (dynobj, info, &htab->srelplt2)) { -- cgit v1.2.3