+/* 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);
+}
+