-/* Create an entry in an x86-64 ELF linker hash table. */
-
-static struct bfd_hash_entry *
-elf_x86_64_link_hash_newfunc (struct bfd_hash_entry *entry,
- struct bfd_hash_table *table,
- const char *string)
-{
- /* Allocate the structure if it has not already been allocated by a
- subclass. */
- if (entry == NULL)
- {
- entry = (struct bfd_hash_entry *)
- bfd_hash_allocate (table,
- sizeof (struct elf_x86_64_link_hash_entry));
- if (entry == NULL)
- return entry;
- }
-
- /* Call the allocation method of the superclass. */
- entry = _bfd_elf_link_hash_newfunc (entry, table, string);
- if (entry != NULL)
- {
- struct elf_x86_64_link_hash_entry *eh;
-
- eh = (struct elf_x86_64_link_hash_entry *) entry;
- eh->dyn_relocs = NULL;
- eh->tls_type = GOT_UNKNOWN;
- eh->needs_copy = 0;
- eh->has_bnd_reloc = 0;
- eh->has_got_reloc = 0;
- eh->has_non_got_reloc = 0;
- eh->tls_get_addr = 2;
- eh->func_pointer_refcount = 0;
- eh->plt_bnd.offset = (bfd_vma) -1;
- eh->plt_got.offset = (bfd_vma) -1;
- eh->tlsdesc_got = (bfd_vma) -1;
- }
-
- return entry;
-}
-
-/* Compute a hash of a local hash entry. We use elf_link_hash_entry
- for local symbol so that we can handle local STT_GNU_IFUNC symbols
- as global symbol. We reuse indx and dynstr_index for local symbol
- hash since they aren't used by global symbols in this backend. */
-
-static hashval_t
-elf_x86_64_local_htab_hash (const void *ptr)
-{
- struct elf_link_hash_entry *h
- = (struct elf_link_hash_entry *) ptr;
- return ELF_LOCAL_SYMBOL_HASH (h->indx, h->dynstr_index);
-}
-
-/* Compare local hash entries. */
-
-static int
-elf_x86_64_local_htab_eq (const void *ptr1, const void *ptr2)
-{
- struct elf_link_hash_entry *h1
- = (struct elf_link_hash_entry *) ptr1;
- struct elf_link_hash_entry *h2
- = (struct elf_link_hash_entry *) ptr2;
-
- return h1->indx == h2->indx && h1->dynstr_index == h2->dynstr_index;
-}
-
-/* Find and/or create a hash entry for local symbol. */
-
-static struct elf_link_hash_entry *
-elf_x86_64_get_local_sym_hash (struct elf_x86_64_link_hash_table *htab,
- bfd *abfd, const Elf_Internal_Rela *rel,
- bfd_boolean create)
-{
- struct elf_x86_64_link_hash_entry e, *ret;
- asection *sec = abfd->sections;
- hashval_t h = ELF_LOCAL_SYMBOL_HASH (sec->id,
- htab->r_sym (rel->r_info));
- void **slot;
-
- e.elf.indx = sec->id;
- e.elf.dynstr_index = htab->r_sym (rel->r_info);
- slot = htab_find_slot_with_hash (htab->loc_hash_table, &e, h,
- create ? INSERT : NO_INSERT);
-
- if (!slot)
- return NULL;
-
- if (*slot)
- {
- ret = (struct elf_x86_64_link_hash_entry *) *slot;
- return &ret->elf;
- }
-
- ret = (struct elf_x86_64_link_hash_entry *)
- objalloc_alloc ((struct objalloc *) htab->loc_hash_memory,
- sizeof (struct elf_x86_64_link_hash_entry));
- if (ret)
- {
- memset (ret, 0, sizeof (*ret));
- ret->elf.indx = sec->id;
- ret->elf.dynstr_index = htab->r_sym (rel->r_info);
- ret->elf.dynindx = -1;
- ret->func_pointer_refcount = 0;
- ret->plt_got.offset = (bfd_vma) -1;
- *slot = ret;
- }
- return &ret->elf;
-}
-
-/* Destroy an X86-64 ELF linker hash table. */
-
-static void
-elf_x86_64_link_hash_table_free (bfd *obfd)
-{
- struct elf_x86_64_link_hash_table *htab
- = (struct elf_x86_64_link_hash_table *) obfd->link.hash;
-
- if (htab->loc_hash_table)
- htab_delete (htab->loc_hash_table);
- if (htab->loc_hash_memory)
- objalloc_free ((struct objalloc *) htab->loc_hash_memory);
- _bfd_elf_link_hash_table_free (obfd);
-}
-
-/* Create an X86-64 ELF linker hash table. */
-
-static struct bfd_link_hash_table *
-elf_x86_64_link_hash_table_create (bfd *abfd)
-{
- struct elf_x86_64_link_hash_table *ret;
- bfd_size_type amt = sizeof (struct elf_x86_64_link_hash_table);
-
- ret = (struct elf_x86_64_link_hash_table *) bfd_zmalloc (amt);
- if (ret == NULL)
- return NULL;
-
- if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd,
- elf_x86_64_link_hash_newfunc,
- sizeof (struct elf_x86_64_link_hash_entry),
- X86_64_ELF_DATA))
- {
- free (ret);
- return NULL;
- }
-
- if (ABI_64_P (abfd))
- {
- ret->r_info = elf64_r_info;
- ret->r_sym = elf64_r_sym;
- ret->pointer_r_type = R_X86_64_64;
- ret->dynamic_interpreter = ELF64_DYNAMIC_INTERPRETER;
- ret->dynamic_interpreter_size = sizeof ELF64_DYNAMIC_INTERPRETER;
- }
- else
- {
- ret->r_info = elf32_r_info;
- ret->r_sym = elf32_r_sym;
- ret->pointer_r_type = R_X86_64_32;
- ret->dynamic_interpreter = ELF32_DYNAMIC_INTERPRETER;
- ret->dynamic_interpreter_size = sizeof ELF32_DYNAMIC_INTERPRETER;
- }
-
- ret->loc_hash_table = htab_try_create (1024,
- elf_x86_64_local_htab_hash,
- elf_x86_64_local_htab_eq,
- NULL);
- ret->loc_hash_memory = objalloc_create ();
- if (!ret->loc_hash_table || !ret->loc_hash_memory)
- {
- elf_x86_64_link_hash_table_free (abfd);
- return NULL;
- }
- ret->elf.root.hash_table_free = elf_x86_64_link_hash_table_free;
-
- return &ret->elf.root;
-}
-
-/* Create .plt, .rela.plt, .got, .got.plt, .rela.got, .dynbss, and
- .rela.bss sections in DYNOBJ, and set up shortcuts to them in our
- hash table. */
-
-static bfd_boolean
-elf_x86_64_create_dynamic_sections (bfd *dynobj,
- struct bfd_link_info *info)
-{
- struct elf_x86_64_link_hash_table *htab;
-
- if (!_bfd_elf_create_dynamic_sections (dynobj, info))
- return FALSE;
-
- htab = elf_x86_64_hash_table (info);
- if (htab == NULL)
- return FALSE;
-
- /* Set the contents of the .interp section to the interpreter. */
- if (bfd_link_executable (info) && !info->nointerp)
- {
- asection *s = bfd_get_linker_section (dynobj, ".interp");
- if (s == NULL)
- abort ();
- s->size = htab->dynamic_interpreter_size;
- s->contents = (unsigned char *) htab->dynamic_interpreter;
- htab->interp = s;
- }
-
- if (!info->no_ld_generated_unwind_info
- && htab->plt_eh_frame == NULL
- && htab->elf.splt != NULL)
- {
- flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
- | SEC_HAS_CONTENTS | SEC_IN_MEMORY
- | SEC_LINKER_CREATED);
- htab->plt_eh_frame
- = bfd_make_section_anyway_with_flags (dynobj, ".eh_frame", flags);
- if (htab->plt_eh_frame == NULL
- || !bfd_set_section_alignment (dynobj, htab->plt_eh_frame, 3))
- return FALSE;
- }
-
- /* Align .got section to its entry size. */
- if (htab->elf.sgot != NULL
- && !bfd_set_section_alignment (dynobj, htab->elf.sgot, 3))
- return FALSE;
-
- /* Align .got.plt section to its entry size. */
- if (htab->elf.sgotplt != NULL
- && !bfd_set_section_alignment (dynobj, htab->elf.sgotplt, 3))
- return FALSE;
-
- return TRUE;
-}
-
-/* Copy the extra info we tack onto an elf_link_hash_entry. */
-
-static void
-elf_x86_64_copy_indirect_symbol (struct bfd_link_info *info,
- struct elf_link_hash_entry *dir,
- struct elf_link_hash_entry *ind)
-{
- struct elf_x86_64_link_hash_entry *edir, *eind;
-
- edir = (struct elf_x86_64_link_hash_entry *) dir;
- eind = (struct elf_x86_64_link_hash_entry *) ind;
-
- edir->has_bnd_reloc |= eind->has_bnd_reloc;
- edir->has_got_reloc |= eind->has_got_reloc;
- edir->has_non_got_reloc |= eind->has_non_got_reloc;
-
- if (eind->dyn_relocs != NULL)
- {
- if (edir->dyn_relocs != NULL)
- {
- struct elf_dyn_relocs **pp;
- struct elf_dyn_relocs *p;
-
- /* Add reloc counts against the indirect sym to the direct sym
- list. Merge any entries against the same section. */
- for (pp = &eind->dyn_relocs; (p = *pp) != NULL; )
- {
- struct elf_dyn_relocs *q;
-
- for (q = edir->dyn_relocs; q != NULL; q = q->next)
- if (q->sec == p->sec)
- {
- q->pc_count += p->pc_count;
- q->count += p->count;
- *pp = p->next;
- break;
- }
- if (q == NULL)
- pp = &p->next;
- }
- *pp = edir->dyn_relocs;
- }
-
- edir->dyn_relocs = eind->dyn_relocs;
- eind->dyn_relocs = NULL;
- }
-
- if (ind->root.type == bfd_link_hash_indirect
- && dir->got.refcount <= 0)
- {
- edir->tls_type = eind->tls_type;
- eind->tls_type = GOT_UNKNOWN;
- }
-
- if (ELIMINATE_COPY_RELOCS
- && ind->root.type != bfd_link_hash_indirect
- && dir->dynamic_adjusted)
- {
- /* If called to transfer flags for a weakdef during processing
- of elf_adjust_dynamic_symbol, don't copy non_got_ref.
- We clear it ourselves for ELIMINATE_COPY_RELOCS. */
- if (dir->versioned != versioned_hidden)
- dir->ref_dynamic |= ind->ref_dynamic;
- dir->ref_regular |= ind->ref_regular;
- dir->ref_regular_nonweak |= ind->ref_regular_nonweak;
- dir->needs_plt |= ind->needs_plt;
- dir->pointer_equality_needed |= ind->pointer_equality_needed;
- }
- else
- {
- if (eind->func_pointer_refcount > 0)
- {
- edir->func_pointer_refcount += eind->func_pointer_refcount;
- eind->func_pointer_refcount = 0;
- }
-
- _bfd_elf_link_hash_copy_indirect (info, dir, ind);
- }
-}
-