OpenCores
URL https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [gnu-src/] [gdb-6.8/] [bfd/] [elf64-x86-64.c] - Diff between revs 157 and 225

Show entire file | Details | Blame | View Log

Rev 157 Rev 225
Line 1... Line 1...
/* X86-64 specific support for 64-bit ELF
/* X86-64 specific support for 64-bit ELF
   Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
   Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
   Free Software Foundation, Inc.
   Free Software Foundation, Inc.
   Contributed by Jan Hubicka <jh@suse.cz>.
   Contributed by Jan Hubicka <jh@suse.cz>.
 
 
   This file is part of BFD, the Binary File Descriptor library.
   This file is part of BFD, the Binary File Descriptor library.
 
 
Line 24... Line 24...
#include "bfd.h"
#include "bfd.h"
#include "bfdlink.h"
#include "bfdlink.h"
#include "libbfd.h"
#include "libbfd.h"
#include "elf-bfd.h"
#include "elf-bfd.h"
#include "bfd_stdint.h"
#include "bfd_stdint.h"
 
#include "objalloc.h"
 
#include "hashtab.h"
 
 
#include "elf/x86-64.h"
#include "elf/x86-64.h"
 
 
/* In case we're on a 32-bit machine, construct a 64-bit "-1" value.  */
/* In case we're on a 32-bit machine, construct a 64-bit "-1" value.  */
#define MINUS_ONE (~ (bfd_vma) 0)
#define MINUS_ONE (~ (bfd_vma) 0)
Line 141... Line 143...
        FALSE, 0, 0, FALSE),
        FALSE, 0, 0, FALSE),
  HOWTO(R_X86_64_TLSDESC, 0, 4, 64, FALSE, 0,
  HOWTO(R_X86_64_TLSDESC, 0, 4, 64, FALSE, 0,
        complain_overflow_bitfield, bfd_elf_generic_reloc,
        complain_overflow_bitfield, bfd_elf_generic_reloc,
        "R_X86_64_TLSDESC",
        "R_X86_64_TLSDESC",
        FALSE, MINUS_ONE, MINUS_ONE, FALSE),
        FALSE, MINUS_ONE, MINUS_ONE, FALSE),
 
  HOWTO(R_X86_64_IRELATIVE, 0, 4, 64, FALSE, 0, complain_overflow_bitfield,
 
        bfd_elf_generic_reloc, "R_X86_64_IRELATIVE", FALSE, MINUS_ONE,
 
        MINUS_ONE, FALSE),
 
 
  /* We have a gap in the reloc numbers here.
  /* We have a gap in the reloc numbers here.
     R_X86_64_standard counts the number up to this point, and
     R_X86_64_standard counts the number up to this point, and
     R_X86_64_vt_offset is the value to subtract from a reloc type of
     R_X86_64_vt_offset is the value to subtract from a reloc type of
     R_X86_64_GNU_VT* to form an index into this table.  */
     R_X86_64_GNU_VT* to form an index into this table.  */
#define R_X86_64_standard (R_X86_64_TLSDESC + 1)
#define R_X86_64_standard (R_X86_64_IRELATIVE + 1)
#define R_X86_64_vt_offset (R_X86_64_GNU_VTINHERIT - R_X86_64_standard)
#define R_X86_64_vt_offset (R_X86_64_GNU_VTINHERIT - R_X86_64_standard)
 
 
/* GNU extension to record C++ vtable hierarchy.  */
/* GNU extension to record C++ vtable hierarchy.  */
  HOWTO (R_X86_64_GNU_VTINHERIT, 0, 4, 0, FALSE, 0, complain_overflow_dont,
  HOWTO (R_X86_64_GNU_VTINHERIT, 0, 4, 0, FALSE, 0, complain_overflow_dont,
         NULL, "R_X86_64_GNU_VTINHERIT", FALSE, 0, 0, FALSE),
         NULL, "R_X86_64_GNU_VTINHERIT", FALSE, 0, 0, FALSE),
Line 159... Line 164...
  HOWTO (R_X86_64_GNU_VTENTRY, 0, 4, 0, FALSE, 0, complain_overflow_dont,
  HOWTO (R_X86_64_GNU_VTENTRY, 0, 4, 0, FALSE, 0, complain_overflow_dont,
         _bfd_elf_rel_vtable_reloc_fn, "R_X86_64_GNU_VTENTRY", FALSE, 0, 0,
         _bfd_elf_rel_vtable_reloc_fn, "R_X86_64_GNU_VTENTRY", FALSE, 0, 0,
         FALSE)
         FALSE)
};
};
 
 
 
#define IS_X86_64_PCREL_TYPE(TYPE)      \
 
  (   ((TYPE) == R_X86_64_PC8)          \
 
   || ((TYPE) == R_X86_64_PC16)         \
 
   || ((TYPE) == R_X86_64_PC32)         \
 
   || ((TYPE) == R_X86_64_PC64))
 
 
/* Map BFD relocs to the x86_64 elf relocs.  */
/* Map BFD relocs to the x86_64 elf relocs.  */
struct elf_reloc_map
struct elf_reloc_map
{
{
  bfd_reloc_code_real_type bfd_reloc_val;
  bfd_reloc_code_real_type bfd_reloc_val;
  unsigned char elf_reloc_val;
  unsigned char elf_reloc_val;
Line 203... Line 214...
  { BFD_RELOC_X86_64_GOTPLT64,  R_X86_64_GOTPLT64, },
  { BFD_RELOC_X86_64_GOTPLT64,  R_X86_64_GOTPLT64, },
  { BFD_RELOC_X86_64_PLTOFF64,  R_X86_64_PLTOFF64, },
  { BFD_RELOC_X86_64_PLTOFF64,  R_X86_64_PLTOFF64, },
  { BFD_RELOC_X86_64_GOTPC32_TLSDESC, R_X86_64_GOTPC32_TLSDESC, },
  { BFD_RELOC_X86_64_GOTPC32_TLSDESC, R_X86_64_GOTPC32_TLSDESC, },
  { BFD_RELOC_X86_64_TLSDESC_CALL, R_X86_64_TLSDESC_CALL, },
  { BFD_RELOC_X86_64_TLSDESC_CALL, R_X86_64_TLSDESC_CALL, },
  { BFD_RELOC_X86_64_TLSDESC,   R_X86_64_TLSDESC, },
  { BFD_RELOC_X86_64_TLSDESC,   R_X86_64_TLSDESC, },
 
  { BFD_RELOC_X86_64_IRELATIVE, R_X86_64_IRELATIVE, },
  { BFD_RELOC_VTABLE_INHERIT,   R_X86_64_GNU_VTINHERIT, },
  { BFD_RELOC_VTABLE_INHERIT,   R_X86_64_GNU_VTINHERIT, },
  { BFD_RELOC_VTABLE_ENTRY,     R_X86_64_GNU_VTENTRY, },
  { BFD_RELOC_VTABLE_ENTRY,     R_X86_64_GNU_VTENTRY, },
};
};
 
 
static reloc_howto_type *
static reloc_howto_type *
Line 382... Line 394...
  0, 0, 0, 0,       /* replaced with index into relocation table.  */
  0, 0, 0, 0,       /* replaced with index into relocation table.  */
  0xe9,         /* jmp relative */
  0xe9,         /* jmp relative */
  0, 0, 0, 0        /* replaced with offset to start of .plt0.  */
  0, 0, 0, 0        /* replaced with offset to start of .plt0.  */
};
};
 
 
/* The x86-64 linker needs to keep track of the number of relocs that
 
   it decides to copy as dynamic relocs in check_relocs for each symbol.
 
   This is so that it can later discard them if they are found to be
 
   unnecessary.  We store the information in a field extending the
 
   regular ELF linker hash table.  */
 
 
 
struct elf64_x86_64_dyn_relocs
 
{
 
  /* Next section.  */
 
  struct elf64_x86_64_dyn_relocs *next;
 
 
 
  /* The input section of the reloc.  */
 
  asection *sec;
 
 
 
  /* Total number of relocs copied for the input section.  */
 
  bfd_size_type count;
 
 
 
  /* Number of pc-relative relocs copied for the input section.  */
 
  bfd_size_type pc_count;
 
};
 
 
 
/* x86-64 ELF linker hash entry.  */
/* x86-64 ELF linker hash entry.  */
 
 
struct elf64_x86_64_link_hash_entry
struct elf64_x86_64_link_hash_entry
{
{
  struct elf_link_hash_entry elf;
  struct elf_link_hash_entry elf;
 
 
  /* Track dynamic relocs copied for this symbol.  */
  /* Track dynamic relocs copied for this symbol.  */
  struct elf64_x86_64_dyn_relocs *dyn_relocs;
  struct elf_dyn_relocs *dyn_relocs;
 
 
#define GOT_UNKNOWN     0
#define GOT_UNKNOWN     0
#define GOT_NORMAL      1
#define GOT_NORMAL      1
#define GOT_TLS_GD      2
#define GOT_TLS_GD      2
#define GOT_TLS_IE      3
#define GOT_TLS_IE      3
Line 474... Line 465...
struct elf64_x86_64_link_hash_table
struct elf64_x86_64_link_hash_table
{
{
  struct elf_link_hash_table elf;
  struct elf_link_hash_table elf;
 
 
  /* Short-cuts to get to dynamic linker sections.  */
  /* Short-cuts to get to dynamic linker sections.  */
  asection *sgot;
 
  asection *sgotplt;
 
  asection *srelgot;
 
  asection *splt;
 
  asection *srelplt;
 
  asection *sdynbss;
  asection *sdynbss;
  asection *srelbss;
  asection *srelbss;
 
 
  /* The offset into splt of the PLT entry for the TLS descriptor
  /* The offset into splt of the PLT entry for the TLS descriptor
     resolver.  Special values are 0, if not necessary (or not found
     resolver.  Special values are 0, if not necessary (or not found
Line 499... Line 485...
  } tls_ld_got;
  } tls_ld_got;
 
 
  /* The amount of space used by the jump slots in the GOT.  */
  /* The amount of space used by the jump slots in the GOT.  */
  bfd_vma sgotplt_jump_table_size;
  bfd_vma sgotplt_jump_table_size;
 
 
  /* Small local sym to section mapping cache.  */
  /* Small local sym cache.  */
  struct sym_sec_cache sym_sec;
  struct sym_cache sym_cache;
 
 
 
  /* _TLS_MODULE_BASE_ symbol.  */
 
  struct bfd_link_hash_entry *tls_module_base;
 
 
 
  /* Used by local STT_GNU_IFUNC symbols.  */
 
  htab_t loc_hash_table;
 
  void *loc_hash_memory;
};
};
 
 
/* Get the x86-64 ELF linker hash table from a link_info structure.  */
/* Get the x86-64 ELF linker hash table from a link_info structure.  */
 
 
#define elf64_x86_64_hash_table(p) \
#define elf64_x86_64_hash_table(p) \
  ((struct elf64_x86_64_link_hash_table *) ((p)->hash))
  ((struct elf64_x86_64_link_hash_table *) ((p)->hash))
 
 
#define elf64_x86_64_compute_jump_table_size(htab) \
#define elf64_x86_64_compute_jump_table_size(htab) \
  ((htab)->srelplt->reloc_count * GOT_ENTRY_SIZE)
  ((htab)->elf.srelplt->reloc_count * GOT_ENTRY_SIZE)
 
 
/* Create an entry in an x86-64 ELF linker hash table.  */
/* Create an entry in an x86-64 ELF linker hash table.  */
 
 
static struct bfd_hash_entry *
static struct bfd_hash_entry *
link_hash_newfunc (struct bfd_hash_entry *entry, struct bfd_hash_table *table,
elf64_x86_64_link_hash_newfunc (struct bfd_hash_entry *entry,
 
                                struct bfd_hash_table *table,
                   const char *string)
                   const char *string)
{
{
  /* Allocate the structure if it has not already been allocated by a
  /* Allocate the structure if it has not already been allocated by a
     subclass.  */
     subclass.  */
  if (entry == NULL)
  if (entry == NULL)
    {
    {
      entry = bfd_hash_allocate (table,
      entry = (struct bfd_hash_entry *)
 
          bfd_hash_allocate (table,
                                 sizeof (struct elf64_x86_64_link_hash_entry));
                                 sizeof (struct elf64_x86_64_link_hash_entry));
      if (entry == NULL)
      if (entry == NULL)
        return entry;
        return entry;
    }
    }
 
 
Line 542... Line 537...
    }
    }
 
 
  return entry;
  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
 
elf64_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
 
elf64_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 *
 
elf64_x86_64_get_local_sym_hash (struct elf64_x86_64_link_hash_table *htab,
 
                                 bfd *abfd, const Elf_Internal_Rela *rel,
 
                                 bfd_boolean create)
 
{
 
  struct elf64_x86_64_link_hash_entry e, *ret;
 
  asection *sec = abfd->sections;
 
  hashval_t h = ELF_LOCAL_SYMBOL_HASH (sec->id,
 
                                       ELF64_R_SYM (rel->r_info));
 
  void **slot;
 
 
 
  e.elf.indx = sec->id;
 
  e.elf.dynstr_index = ELF64_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 elf64_x86_64_link_hash_entry *) *slot;
 
      return &ret->elf;
 
    }
 
 
 
  ret = (struct elf64_x86_64_link_hash_entry *)
 
        objalloc_alloc ((struct objalloc *) htab->loc_hash_memory,
 
                        sizeof (struct elf64_x86_64_link_hash_entry));
 
  if (ret)
 
    {
 
      memset (ret, 0, sizeof (*ret));
 
      ret->elf.indx = sec->id;
 
      ret->elf.dynstr_index = ELF64_R_SYM (rel->r_info);
 
      ret->elf.dynindx = -1;
 
      ret->elf.plt.offset = (bfd_vma) -1;
 
      ret->elf.got.offset = (bfd_vma) -1;
 
      *slot = ret;
 
    }
 
  return &ret->elf;
 
}
 
 
/* Create an X86-64 ELF linker hash table.  */
/* Create an X86-64 ELF linker hash table.  */
 
 
static struct bfd_link_hash_table *
static struct bfd_link_hash_table *
elf64_x86_64_link_hash_table_create (bfd *abfd)
elf64_x86_64_link_hash_table_create (bfd *abfd)
{
{
Line 554... Line 618...
 
 
  ret = (struct elf64_x86_64_link_hash_table *) bfd_malloc (amt);
  ret = (struct elf64_x86_64_link_hash_table *) bfd_malloc (amt);
  if (ret == NULL)
  if (ret == NULL)
    return NULL;
    return NULL;
 
 
  if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd, link_hash_newfunc,
  if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd,
 
                                      elf64_x86_64_link_hash_newfunc,
                                      sizeof (struct elf64_x86_64_link_hash_entry)))
                                      sizeof (struct elf64_x86_64_link_hash_entry)))
    {
    {
      free (ret);
      free (ret);
      return NULL;
      return NULL;
    }
    }
 
 
  ret->sgot = NULL;
 
  ret->sgotplt = NULL;
 
  ret->srelgot = NULL;
 
  ret->splt = NULL;
 
  ret->srelplt = NULL;
 
  ret->sdynbss = NULL;
  ret->sdynbss = NULL;
  ret->srelbss = NULL;
  ret->srelbss = NULL;
  ret->sym_sec.abfd = NULL;
  ret->sym_cache.abfd = NULL;
  ret->tlsdesc_plt = 0;
  ret->tlsdesc_plt = 0;
  ret->tlsdesc_got = 0;
  ret->tlsdesc_got = 0;
  ret->tls_ld_got.refcount = 0;
  ret->tls_ld_got.refcount = 0;
  ret->sgotplt_jump_table_size = 0;
  ret->sgotplt_jump_table_size = 0;
 
  ret->tls_module_base = NULL;
 
 
 
  ret->loc_hash_table = htab_try_create (1024,
 
                                         elf64_x86_64_local_htab_hash,
 
                                         elf64_x86_64_local_htab_eq,
 
                                         NULL);
 
  ret->loc_hash_memory = objalloc_create ();
 
  if (!ret->loc_hash_table || !ret->loc_hash_memory)
 
    {
 
      free (ret);
 
      return NULL;
 
    }
 
 
  return &ret->elf.root;
  return &ret->elf.root;
}
}
 
 
/* Create .got, .gotplt, and .rela.got sections in DYNOBJ, and set up
/* Destroy an X86-64 ELF linker hash table.  */
   shortcuts to them in our hash table.  */
 
 
 
static bfd_boolean
static void
create_got_section (bfd *dynobj, struct bfd_link_info *info)
elf64_x86_64_link_hash_table_free (struct bfd_link_hash_table *hash)
{
{
  struct elf64_x86_64_link_hash_table *htab;
  struct elf64_x86_64_link_hash_table *htab
 
    = (struct elf64_x86_64_link_hash_table *) hash;
  if (! _bfd_elf_create_got_section (dynobj, info))
 
    return FALSE;
 
 
 
  htab = elf64_x86_64_hash_table (info);
  if (htab->loc_hash_table)
  htab->sgot = bfd_get_section_by_name (dynobj, ".got");
    htab_delete (htab->loc_hash_table);
  htab->sgotplt = bfd_get_section_by_name (dynobj, ".got.plt");
  if (htab->loc_hash_memory)
  if (!htab->sgot || !htab->sgotplt)
    objalloc_free ((struct objalloc *) htab->loc_hash_memory);
    abort ();
  _bfd_generic_link_hash_table_free (hash);
 
 
  htab->srelgot = bfd_make_section_with_flags (dynobj, ".rela.got",
 
                                               (SEC_ALLOC | SEC_LOAD
 
                                                | SEC_HAS_CONTENTS
 
                                                | SEC_IN_MEMORY
 
                                                | SEC_LINKER_CREATED
 
                                                | SEC_READONLY));
 
  if (htab->srelgot == NULL
 
      || ! bfd_set_section_alignment (dynobj, htab->srelgot, 3))
 
    return FALSE;
 
  return TRUE;
 
}
}
 
 
/* Create .plt, .rela.plt, .got, .got.plt, .rela.got, .dynbss, and
/* Create .plt, .rela.plt, .got, .got.plt, .rela.got, .dynbss, and
   .rela.bss sections in DYNOBJ, and set up shortcuts to them in our
   .rela.bss sections in DYNOBJ, and set up shortcuts to them in our
   hash table.  */
   hash table.  */
Line 615... Line 673...
static bfd_boolean
static bfd_boolean
elf64_x86_64_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info)
elf64_x86_64_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info)
{
{
  struct elf64_x86_64_link_hash_table *htab;
  struct elf64_x86_64_link_hash_table *htab;
 
 
  htab = elf64_x86_64_hash_table (info);
 
  if (!htab->sgot && !create_got_section (dynobj, info))
 
    return FALSE;
 
 
 
  if (!_bfd_elf_create_dynamic_sections (dynobj, info))
  if (!_bfd_elf_create_dynamic_sections (dynobj, info))
    return FALSE;
    return FALSE;
 
 
  htab->splt = bfd_get_section_by_name (dynobj, ".plt");
  htab = elf64_x86_64_hash_table (info);
  htab->srelplt = bfd_get_section_by_name (dynobj, ".rela.plt");
 
  htab->sdynbss = bfd_get_section_by_name (dynobj, ".dynbss");
  htab->sdynbss = bfd_get_section_by_name (dynobj, ".dynbss");
  if (!info->shared)
  if (!info->shared)
    htab->srelbss = bfd_get_section_by_name (dynobj, ".rela.bss");
    htab->srelbss = bfd_get_section_by_name (dynobj, ".rela.bss");
 
 
  if (!htab->splt || !htab->srelplt || !htab->sdynbss
  if (!htab->sdynbss
      || (!info->shared && !htab->srelbss))
      || (!info->shared && !htab->srelbss))
    abort ();
    abort ();
 
 
  return TRUE;
  return TRUE;
}
}
Line 651... Line 704...
 
 
  if (eind->dyn_relocs != NULL)
  if (eind->dyn_relocs != NULL)
    {
    {
      if (edir->dyn_relocs != NULL)
      if (edir->dyn_relocs != NULL)
        {
        {
          struct elf64_x86_64_dyn_relocs **pp;
          struct elf_dyn_relocs **pp;
          struct elf64_x86_64_dyn_relocs *p;
          struct elf_dyn_relocs *p;
 
 
          /* Add reloc counts against the indirect sym to the direct sym
          /* Add reloc counts against the indirect sym to the direct sym
             list.  Merge any entries against the same section.  */
             list.  Merge any entries against the same section.  */
          for (pp = &eind->dyn_relocs; (p = *pp) != NULL; )
          for (pp = &eind->dyn_relocs; (p = *pp) != NULL; )
            {
            {
              struct elf64_x86_64_dyn_relocs *q;
              struct elf_dyn_relocs *q;
 
 
              for (q = edir->dyn_relocs; q != NULL; q = q->next)
              for (q = edir->dyn_relocs; q != NULL; q = q->next)
                if (q->sec == p->sec)
                if (q->sec == p->sec)
                  {
                  {
                    q->pc_count += p->pc_count;
                    q->pc_count += p->pc_count;
Line 804... Line 857...
      r_symndx = ELF64_R_SYM (rel[1].r_info);
      r_symndx = ELF64_R_SYM (rel[1].r_info);
      if (r_symndx < symtab_hdr->sh_info)
      if (r_symndx < symtab_hdr->sh_info)
        return FALSE;
        return FALSE;
 
 
      h = sym_hashes[r_symndx - symtab_hdr->sh_info];
      h = sym_hashes[r_symndx - symtab_hdr->sh_info];
 
      /* Use strncmp to check __tls_get_addr since __tls_get_addr
 
         may be versioned.  */
      return (h != NULL
      return (h != NULL
              && h->root.root.string != NULL
              && h->root.root.string != NULL
              && (ELF64_R_TYPE (rel[1].r_info) == R_X86_64_PC32
              && (ELF64_R_TYPE (rel[1].r_info) == R_X86_64_PC32
                  || ELF64_R_TYPE (rel[1].r_info) == R_X86_64_PLT32)
                  || ELF64_R_TYPE (rel[1].r_info) == R_X86_64_PLT32)
              && (strcmp (h->root.root.string, "__tls_get_addr") == 0));
              && (strncmp (h->root.root.string,
 
                           "__tls_get_addr", 14) == 0));
 
 
    case R_X86_64_GOTTPOFF:
    case R_X86_64_GOTTPOFF:
      /* Check transition from IE access model:
      /* Check transition from IE access model:
                movq foo@gottpoff(%rip), %reg
                movq foo@gottpoff(%rip), %reg
                addq foo@gottpoff(%rip), %reg
                addq foo@gottpoff(%rip), %reg
Line 880... Line 936...
                             Elf_Internal_Shdr *symtab_hdr,
                             Elf_Internal_Shdr *symtab_hdr,
                             struct elf_link_hash_entry **sym_hashes,
                             struct elf_link_hash_entry **sym_hashes,
                             unsigned int *r_type, int tls_type,
                             unsigned int *r_type, int tls_type,
                             const Elf_Internal_Rela *rel,
                             const Elf_Internal_Rela *rel,
                             const Elf_Internal_Rela *relend,
                             const Elf_Internal_Rela *relend,
                             struct elf_link_hash_entry *h)
                             struct elf_link_hash_entry *h,
 
                             unsigned long r_symndx)
{
{
  unsigned int from_type = *r_type;
  unsigned int from_type = *r_type;
  unsigned int to_type = from_type;
  unsigned int to_type = from_type;
  bfd_boolean check = TRUE;
  bfd_boolean check = TRUE;
 
 
Line 892... Line 949...
    {
    {
    case R_X86_64_TLSGD:
    case R_X86_64_TLSGD:
    case R_X86_64_GOTPC32_TLSDESC:
    case R_X86_64_GOTPC32_TLSDESC:
    case R_X86_64_TLSDESC_CALL:
    case R_X86_64_TLSDESC_CALL:
    case R_X86_64_GOTTPOFF:
    case R_X86_64_GOTTPOFF:
      if (!info->shared)
      if (info->executable)
        {
        {
          if (h == NULL)
          if (h == NULL)
            to_type = R_X86_64_TPOFF32;
            to_type = R_X86_64_TPOFF32;
          else
          else
            to_type = R_X86_64_GOTTPOFF;
            to_type = R_X86_64_GOTTPOFF;
Line 907... Line 964...
         based on TLS_TYPE.  */
         based on TLS_TYPE.  */
      if (contents != NULL)
      if (contents != NULL)
        {
        {
          unsigned int new_to_type = to_type;
          unsigned int new_to_type = to_type;
 
 
          if (!info->shared
          if (info->executable
              && h != NULL
              && h != NULL
              && h->dynindx == -1
              && h->dynindx == -1
              && tls_type == GOT_TLS_IE)
              && tls_type == GOT_TLS_IE)
            new_to_type = R_X86_64_TPOFF32;
            new_to_type = R_X86_64_TPOFF32;
 
 
Line 931... Line 988...
        }
        }
 
 
      break;
      break;
 
 
    case R_X86_64_TLSLD:
    case R_X86_64_TLSLD:
      if (!info->shared)
      if (info->executable)
        to_type = R_X86_64_TPOFF32;
        to_type = R_X86_64_TPOFF32;
      break;
      break;
 
 
    default:
    default:
      return TRUE;
      return TRUE;
Line 950... Line 1007...
      && ! elf64_x86_64_check_tls_transition (abfd, sec, contents,
      && ! elf64_x86_64_check_tls_transition (abfd, sec, contents,
                                              symtab_hdr, sym_hashes,
                                              symtab_hdr, sym_hashes,
                                              from_type, rel, relend))
                                              from_type, rel, relend))
    {
    {
      reloc_howto_type *from, *to;
      reloc_howto_type *from, *to;
 
      const char *name;
 
 
      from = elf64_x86_64_rtype_to_howto (abfd, from_type);
      from = elf64_x86_64_rtype_to_howto (abfd, from_type);
      to = elf64_x86_64_rtype_to_howto (abfd, to_type);
      to = elf64_x86_64_rtype_to_howto (abfd, to_type);
 
 
 
      if (h)
 
        name = h->root.root.string;
 
      else
 
        {
 
          Elf_Internal_Sym *isym;
 
          struct elf64_x86_64_link_hash_table *htab;
 
          htab = elf64_x86_64_hash_table (info);
 
          isym = bfd_sym_from_r_symndx (&htab->sym_cache,
 
                                        abfd, r_symndx);
 
          name = bfd_elf_sym_name (abfd, symtab_hdr, isym, NULL);
 
        }
 
 
      (*_bfd_error_handler)
      (*_bfd_error_handler)
        (_("%B: TLS transition from %s to %s against `%s' at 0x%lx "
        (_("%B: TLS transition from %s to %s against `%s' at 0x%lx "
           "in section `%A' failed"),
           "in section `%A' failed"),
         abfd, sec, from->name, to->name,
         abfd, sec, from->name, to->name, name,
         h ? h->root.root.string : "a local symbol",
 
         (unsigned long) rel->r_offset);
         (unsigned long) rel->r_offset);
      bfd_set_error (bfd_error_bad_value);
      bfd_set_error (bfd_error_bad_value);
      return FALSE;
      return FALSE;
    }
    }
 
 
Line 1001... Line 1070...
  for (rel = relocs; rel < rel_end; rel++)
  for (rel = relocs; rel < rel_end; rel++)
    {
    {
      unsigned int r_type;
      unsigned int r_type;
      unsigned long r_symndx;
      unsigned long r_symndx;
      struct elf_link_hash_entry *h;
      struct elf_link_hash_entry *h;
 
      Elf_Internal_Sym *isym;
 
      const char *name;
 
 
      r_symndx = ELF64_R_SYM (rel->r_info);
      r_symndx = ELF64_R_SYM (rel->r_info);
      r_type = ELF64_R_TYPE (rel->r_info);
      r_type = ELF64_R_TYPE (rel->r_info);
 
 
      if (r_symndx >= NUM_SHDR_ENTRIES (symtab_hdr))
      if (r_symndx >= NUM_SHDR_ENTRIES (symtab_hdr))
Line 1013... Line 1084...
                                 abfd, r_symndx);
                                 abfd, r_symndx);
          return FALSE;
          return FALSE;
        }
        }
 
 
      if (r_symndx < symtab_hdr->sh_info)
      if (r_symndx < symtab_hdr->sh_info)
 
        {
 
          /* A local symbol.  */
 
          isym = bfd_sym_from_r_symndx (&htab->sym_cache,
 
                                        abfd, r_symndx);
 
          if (isym == NULL)
 
            return FALSE;
 
 
 
          /* Check relocation against local STT_GNU_IFUNC symbol.  */
 
          if (ELF64_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
 
            {
 
              h = elf64_x86_64_get_local_sym_hash (htab, abfd, rel,
 
                                                   TRUE);
 
              if (h == NULL)
 
                return FALSE;
 
 
 
              /* Fake a STT_GNU_IFUNC symbol.  */
 
              h->type = STT_GNU_IFUNC;
 
              h->def_regular = 1;
 
              h->ref_regular = 1;
 
              h->forced_local = 1;
 
              h->root.type = bfd_link_hash_defined;
 
            }
 
          else
        h = NULL;
        h = NULL;
 
        }
      else
      else
        {
        {
 
          isym = NULL;
          h = sym_hashes[r_symndx - symtab_hdr->sh_info];
          h = sym_hashes[r_symndx - symtab_hdr->sh_info];
          while (h->root.type == bfd_link_hash_indirect
          while (h->root.type == bfd_link_hash_indirect
                 || h->root.type == bfd_link_hash_warning)
                 || h->root.type == bfd_link_hash_warning)
            h = (struct elf_link_hash_entry *) h->root.u.i.link;
            h = (struct elf_link_hash_entry *) h->root.u.i.link;
        }
        }
 
 
 
      if (h != NULL)
 
        {
 
          /* Create the ifunc sections for static executables.  If we
 
             never see an indirect function symbol nor we are building
 
             a static executable, those sections will be empty and
 
             won't appear in output.  */
 
          switch (r_type)
 
            {
 
            default:
 
              break;
 
 
 
            case R_X86_64_32S:
 
            case R_X86_64_32:
 
            case R_X86_64_64:
 
            case R_X86_64_PC32:
 
            case R_X86_64_PC64:
 
            case R_X86_64_PLT32:
 
            case R_X86_64_GOTPCREL:
 
            case R_X86_64_GOTPCREL64:
 
              if (!_bfd_elf_create_ifunc_sections (abfd, info))
 
                return FALSE;
 
              break;
 
            }
 
 
 
          /* Since STT_GNU_IFUNC symbol must go through PLT, we handle
 
             it here if it is defined in a non-shared object.  */
 
          if (h->type == STT_GNU_IFUNC
 
              && h->def_regular)
 
            {
 
              /* It is referenced by a non-shared object. */
 
              h->ref_regular = 1;
 
              h->needs_plt = 1;
 
 
 
              /* STT_GNU_IFUNC symbol must go through PLT.  */
 
              h->plt.refcount += 1;
 
 
 
              /* STT_GNU_IFUNC needs dynamic sections.  */
 
              if (htab->elf.dynobj == NULL)
 
                htab->elf.dynobj = abfd;
 
 
 
              switch (r_type)
 
                {
 
                default:
 
                  if (h->root.root.string)
 
                    name = h->root.root.string;
 
                  else
 
                    name = bfd_elf_sym_name (abfd, symtab_hdr, isym,
 
                                             NULL);
 
                  (*_bfd_error_handler)
 
                    (_("%B: relocation %s against STT_GNU_IFUNC "
 
                       "symbol `%s' isn't handled by %s"), abfd,
 
                     x86_64_elf_howto_table[r_type].name,
 
                     name, __FUNCTION__);
 
                  bfd_set_error (bfd_error_bad_value);
 
                  return FALSE;
 
 
 
                case R_X86_64_64:
 
                  h->non_got_ref = 1;
 
                  h->pointer_equality_needed = 1;
 
                  if (info->shared)
 
                    {
 
                      /* We must copy these reloc types into the output
 
                         file.  Create a reloc section in dynobj and
 
                         make room for this reloc.  */
 
                      sreloc = _bfd_elf_create_ifunc_dyn_reloc
 
                        (abfd, info, sec, sreloc,
 
                         &((struct elf64_x86_64_link_hash_entry *) h)->dyn_relocs);
 
                      if (sreloc == NULL)
 
                        return FALSE;
 
                    }
 
                  break;
 
 
 
                case R_X86_64_32S:
 
                case R_X86_64_32:
 
                case R_X86_64_PC32:
 
                case R_X86_64_PC64:
 
                  h->non_got_ref = 1;
 
                  if (r_type != R_X86_64_PC32
 
                      && r_type != R_X86_64_PC64)
 
                    h->pointer_equality_needed = 1;
 
                  break;
 
 
 
                case R_X86_64_PLT32:
 
                  break;
 
 
 
                case R_X86_64_GOTPCREL:
 
                case R_X86_64_GOTPCREL64:
 
                  h->got.refcount += 1;
 
                  if (htab->elf.sgot == NULL
 
                      && !_bfd_elf_create_got_section (htab->elf.dynobj,
 
                                                       info))
 
                    return FALSE;
 
                  break;
 
                }
 
 
 
              continue;
 
            }
 
        }
 
 
      if (! elf64_x86_64_tls_transition (info, abfd, sec, NULL,
      if (! elf64_x86_64_tls_transition (info, abfd, sec, NULL,
                                         symtab_hdr, sym_hashes,
                                         symtab_hdr, sym_hashes,
                                         &r_type, GOT_UNKNOWN,
                                         &r_type, GOT_UNKNOWN,
                                         rel, rel_end, h))
                                         rel, rel_end, h, r_symndx))
        return FALSE;
        return FALSE;
 
 
      switch (r_type)
      switch (r_type)
        {
        {
        case R_X86_64_TLSLD:
        case R_X86_64_TLSLD:
          htab->tls_ld_got.refcount += 1;
          htab->tls_ld_got.refcount += 1;
          goto create_got;
          goto create_got;
 
 
        case R_X86_64_TPOFF32:
        case R_X86_64_TPOFF32:
          if (info->shared)
          if (!info->executable)
            {
            {
 
              if (h)
 
                name = h->root.root.string;
 
              else
 
                name = bfd_elf_sym_name (abfd, symtab_hdr, isym,
 
                                         NULL);
              (*_bfd_error_handler)
              (*_bfd_error_handler)
                (_("%B: relocation %s against `%s' can not be used when making a shared object; recompile with -fPIC"),
                (_("%B: relocation %s against `%s' can not be used when making a shared object; recompile with -fPIC"),
                 abfd,
                 abfd,
                 x86_64_elf_howto_table[r_type].name,
                 x86_64_elf_howto_table[r_type].name, name);
                 (h) ? h->root.root.string : "a local symbol");
 
              bfd_set_error (bfd_error_bad_value);
              bfd_set_error (bfd_error_bad_value);
              return FALSE;
              return FALSE;
            }
            }
          break;
          break;
 
 
        case R_X86_64_GOTTPOFF:
        case R_X86_64_GOTTPOFF:
          if (info->shared)
          if (!info->executable)
            info->flags |= DF_STATIC_TLS;
            info->flags |= DF_STATIC_TLS;
          /* Fall through */
          /* Fall through */
 
 
        case R_X86_64_GOT32:
        case R_X86_64_GOT32:
        case R_X86_64_GOTPCREL:
        case R_X86_64_GOTPCREL:
Line 1128... Line 1327...
                else if (GOT_TLS_GD_ANY_P (old_tls_type)
                else if (GOT_TLS_GD_ANY_P (old_tls_type)
                         && GOT_TLS_GD_ANY_P (tls_type))
                         && GOT_TLS_GD_ANY_P (tls_type))
                  tls_type |= old_tls_type;
                  tls_type |= old_tls_type;
                else
                else
                  {
                  {
 
                    if (h)
 
                      name = h->root.root.string;
 
                    else
 
                      name = bfd_elf_sym_name (abfd, symtab_hdr,
 
                                               isym, NULL);
                    (*_bfd_error_handler)
                    (*_bfd_error_handler)
                      (_("%B: '%s' accessed both as normal and thread local symbol"),
                      (_("%B: '%s' accessed both as normal and thread local symbol"),
                       abfd, h ? h->root.root.string : "<local>");
                       abfd, name);
                    return FALSE;
                    return FALSE;
                  }
                  }
              }
              }
 
 
            if (old_tls_type != tls_type)
            if (old_tls_type != tls_type)
Line 1149... Line 1353...
 
 
        case R_X86_64_GOTOFF64:
        case R_X86_64_GOTOFF64:
        case R_X86_64_GOTPC32:
        case R_X86_64_GOTPC32:
        case R_X86_64_GOTPC64:
        case R_X86_64_GOTPC64:
        create_got:
        create_got:
          if (htab->sgot == NULL)
          if (htab->elf.sgot == NULL)
            {
            {
              if (htab->elf.dynobj == NULL)
              if (htab->elf.dynobj == NULL)
                htab->elf.dynobj = abfd;
                htab->elf.dynobj = abfd;
              if (!create_got_section (htab->elf.dynobj, info))
              if (!_bfd_elf_create_got_section (htab->elf.dynobj,
 
                                                info))
                return FALSE;
                return FALSE;
            }
            }
          break;
          break;
 
 
        case R_X86_64_PLT32:
        case R_X86_64_PLT32:
Line 1197... Line 1402...
             non-constant sections.  */
             non-constant sections.  */
          if (info->shared
          if (info->shared
              && (sec->flags & SEC_ALLOC) != 0
              && (sec->flags & SEC_ALLOC) != 0
              && (sec->flags & SEC_READONLY) != 0)
              && (sec->flags & SEC_READONLY) != 0)
            {
            {
 
              if (h)
 
                name = h->root.root.string;
 
              else
 
                name = bfd_elf_sym_name (abfd, symtab_hdr, isym, NULL);
              (*_bfd_error_handler)
              (*_bfd_error_handler)
                (_("%B: relocation %s against `%s' can not be used when making a shared object; recompile with -fPIC"),
                (_("%B: relocation %s against `%s' can not be used when making a shared object; recompile with -fPIC"),
                 abfd,
                 abfd, x86_64_elf_howto_table[r_type].name, name);
                 x86_64_elf_howto_table[r_type].name,
 
                 (h) ? h->root.root.string : "a local symbol");
 
              bfd_set_error (bfd_error_bad_value);
              bfd_set_error (bfd_error_bad_value);
              return FALSE;
              return FALSE;
            }
            }
          /* Fall through.  */
          /* Fall through.  */
 
 
        case R_X86_64_PC8:
        case R_X86_64_PC8:
        case R_X86_64_PC16:
        case R_X86_64_PC16:
        case R_X86_64_PC32:
        case R_X86_64_PC32:
        case R_X86_64_PC64:
        case R_X86_64_PC64:
        case R_X86_64_64:
        case R_X86_64_64:
          if (h != NULL && !info->shared)
          if (h != NULL && info->executable)
            {
            {
              /* If this reloc is in a read-only section, we might
              /* If this reloc is in a read-only section, we might
                 need a copy reloc.  We can't check reliably at this
                 need a copy reloc.  We can't check reliably at this
                 stage whether the section is read-only, as input
                 stage whether the section is read-only, as input
                 sections have not yet been mapped to output sections.
                 sections have not yet been mapped to output sections.
Line 1252... Line 1459...
             may need to keep relocations for symbols satisfied by a
             may need to keep relocations for symbols satisfied by a
             dynamic library if we manage to avoid copy relocs for the
             dynamic library if we manage to avoid copy relocs for the
             symbol.  */
             symbol.  */
          if ((info->shared
          if ((info->shared
               && (sec->flags & SEC_ALLOC) != 0
               && (sec->flags & SEC_ALLOC) != 0
               && (((r_type != R_X86_64_PC8)
               && (! IS_X86_64_PCREL_TYPE (r_type)
                    && (r_type != R_X86_64_PC16)
 
                    && (r_type != R_X86_64_PC32)
 
                    && (r_type != R_X86_64_PC64))
 
                   || (h != NULL
                   || (h != NULL
                       && (! SYMBOLIC_BIND (info, h)
                       && (! SYMBOLIC_BIND (info, h)
                           || h->root.type == bfd_link_hash_defweak
                           || h->root.type == bfd_link_hash_defweak
                           || !h->def_regular))))
                           || !h->def_regular))))
              || (ELIMINATE_COPY_RELOCS
              || (ELIMINATE_COPY_RELOCS
Line 1267... Line 1471...
                  && (sec->flags & SEC_ALLOC) != 0
                  && (sec->flags & SEC_ALLOC) != 0
                  && h != NULL
                  && h != NULL
                  && (h->root.type == bfd_link_hash_defweak
                  && (h->root.type == bfd_link_hash_defweak
                      || !h->def_regular)))
                      || !h->def_regular)))
            {
            {
              struct elf64_x86_64_dyn_relocs *p;
              struct elf_dyn_relocs *p;
              struct elf64_x86_64_dyn_relocs **head;
              struct elf_dyn_relocs **head;
 
 
              /* We must copy these reloc types into the output file.
              /* We must copy these reloc types into the output file.
                 Create a reloc section in dynobj and make room for
                 Create a reloc section in dynobj and make room for
                 this reloc.  */
                 this reloc.  */
              if (sreloc == NULL)
              if (sreloc == NULL)
                {
                {
                  const char *name;
 
                  bfd *dynobj;
 
 
 
                  name = (bfd_elf_string_from_elf_section
 
                          (abfd,
 
                           elf_elfheader (abfd)->e_shstrndx,
 
                           elf_section_data (sec)->rel_hdr.sh_name));
 
                  if (name == NULL)
 
                    return FALSE;
 
 
 
                  if (! CONST_STRNEQ (name, ".rela")
 
                      || strcmp (bfd_get_section_name (abfd, sec),
 
                                 name + 5) != 0)
 
                    {
 
                      (*_bfd_error_handler)
 
                        (_("%B: bad relocation section name `%s\'"),
 
                         abfd, name);
 
                    }
 
 
 
                  if (htab->elf.dynobj == NULL)
                  if (htab->elf.dynobj == NULL)
                    htab->elf.dynobj = abfd;
                    htab->elf.dynobj = abfd;
 
 
                  dynobj = htab->elf.dynobj;
                  sreloc = _bfd_elf_make_dynamic_reloc_section
 
                    (sec, htab->elf.dynobj, 3, abfd, /*rela?*/ TRUE);
 
 
                  sreloc = bfd_get_section_by_name (dynobj, name);
 
                  if (sreloc == NULL)
                  if (sreloc == NULL)
                    {
 
                      flagword flags;
 
 
 
                      flags = (SEC_HAS_CONTENTS | SEC_READONLY
 
                               | SEC_IN_MEMORY | SEC_LINKER_CREATED);
 
                      if ((sec->flags & SEC_ALLOC) != 0)
 
                        flags |= SEC_ALLOC | SEC_LOAD;
 
                      sreloc = bfd_make_section_with_flags (dynobj,
 
                                                            name,
 
                                                            flags);
 
                      if (sreloc == NULL
 
                          || ! bfd_set_section_alignment (dynobj, sreloc, 3))
 
                        return FALSE;
                        return FALSE;
                    }
                    }
                  elf_section_data (sec)->sreloc = sreloc;
 
                }
 
 
 
              /* If this is a global symbol, we count the number of
              /* If this is a global symbol, we count the number of
                 relocations we need for this symbol.  */
                 relocations we need for this symbol.  */
              if (h != NULL)
              if (h != NULL)
                {
                {
                  head = &((struct elf64_x86_64_link_hash_entry *) h)->dyn_relocs;
                  head = &((struct elf64_x86_64_link_hash_entry *) h)->dyn_relocs;
                }
                }
              else
              else
                {
                {
                  void **vpp;
 
                  /* Track dynamic relocs needed for local syms too.
                  /* Track dynamic relocs needed for local syms too.
                     We really need local syms available to do this
                     We really need local syms available to do this
                     easily.  Oh well.  */
                     easily.  Oh well.  */
 
 
                  asection *s;
                  asection *s;
                  s = bfd_section_from_r_symndx (abfd, &htab->sym_sec,
                  void **vpp;
                                                 sec, r_symndx);
                  Elf_Internal_Sym *isym;
                  if (s == NULL)
 
 
                  isym = bfd_sym_from_r_symndx (&htab->sym_cache,
 
                                                abfd, r_symndx);
 
                  if (isym == NULL)
                    return FALSE;
                    return FALSE;
 
 
 
                  s = bfd_section_from_elf_index (abfd, isym->st_shndx);
 
                  if (s == NULL)
 
                    s = sec;
 
 
                  /* Beware of type punned pointers vs strict aliasing
                  /* Beware of type punned pointers vs strict aliasing
                     rules.  */
                     rules.  */
                  vpp = &(elf_section_data (s)->local_dynrel);
                  vpp = &(elf_section_data (s)->local_dynrel);
                  head = (struct elf64_x86_64_dyn_relocs **)vpp;
                  head = (struct elf_dyn_relocs **)vpp;
                }
                }
 
 
              p = *head;
              p = *head;
              if (p == NULL || p->sec != sec)
              if (p == NULL || p->sec != sec)
                {
                {
                  bfd_size_type amt = sizeof *p;
                  bfd_size_type amt = sizeof *p;
                  p = ((struct elf64_x86_64_dyn_relocs *)
 
 
                  p = ((struct elf_dyn_relocs *)
                       bfd_alloc (htab->elf.dynobj, amt));
                       bfd_alloc (htab->elf.dynobj, amt));
                  if (p == NULL)
                  if (p == NULL)
                    return FALSE;
                    return FALSE;
                  p->next = *head;
                  p->next = *head;
                  *head = p;
                  *head = p;
Line 1359... Line 1536...
                  p->count = 0;
                  p->count = 0;
                  p->pc_count = 0;
                  p->pc_count = 0;
                }
                }
 
 
              p->count += 1;
              p->count += 1;
              if (r_type == R_X86_64_PC8
              if (IS_X86_64_PCREL_TYPE (r_type))
                  || r_type == R_X86_64_PC16
 
                  || r_type == R_X86_64_PC32
 
                  || r_type == R_X86_64_PC64)
 
                p->pc_count += 1;
                p->pc_count += 1;
            }
            }
          break;
          break;
 
 
          /* This relocation describes the C++ object vtable hierarchy.
          /* This relocation describes the C++ object vtable hierarchy.
Line 1444... Line 1618...
 
 
      r_symndx = ELF64_R_SYM (rel->r_info);
      r_symndx = ELF64_R_SYM (rel->r_info);
      if (r_symndx >= symtab_hdr->sh_info)
      if (r_symndx >= symtab_hdr->sh_info)
        {
        {
          struct elf64_x86_64_link_hash_entry *eh;
          struct elf64_x86_64_link_hash_entry *eh;
          struct elf64_x86_64_dyn_relocs **pp;
          struct elf_dyn_relocs **pp;
          struct elf64_x86_64_dyn_relocs *p;
          struct elf_dyn_relocs *p;
 
 
          h = sym_hashes[r_symndx - symtab_hdr->sh_info];
          h = sym_hashes[r_symndx - symtab_hdr->sh_info];
          while (h->root.type == bfd_link_hash_indirect
          while (h->root.type == bfd_link_hash_indirect
                 || h->root.type == bfd_link_hash_warning)
                 || h->root.type == bfd_link_hash_warning)
            h = (struct elf_link_hash_entry *) h->root.u.i.link;
            h = (struct elf_link_hash_entry *) h->root.u.i.link;
Line 1466... Line 1640...
 
 
      r_type = ELF64_R_TYPE (rel->r_info);
      r_type = ELF64_R_TYPE (rel->r_info);
      if (! elf64_x86_64_tls_transition (info, abfd, sec, NULL,
      if (! elf64_x86_64_tls_transition (info, abfd, sec, NULL,
                                         symtab_hdr, sym_hashes,
                                         symtab_hdr, sym_hashes,
                                         &r_type, GOT_UNKNOWN,
                                         &r_type, GOT_UNKNOWN,
                                         rel, relend, h))
                                         rel, relend, h, r_symndx))
        return FALSE;
        return FALSE;
 
 
      switch (r_type)
      switch (r_type)
        {
        {
        case R_X86_64_TLSLD:
        case R_X86_64_TLSLD:
Line 1542... Line 1716...
                                    struct elf_link_hash_entry *h)
                                    struct elf_link_hash_entry *h)
{
{
  struct elf64_x86_64_link_hash_table *htab;
  struct elf64_x86_64_link_hash_table *htab;
  asection *s;
  asection *s;
 
 
 
  /* STT_GNU_IFUNC symbol must go through PLT. */
 
  if (h->type == STT_GNU_IFUNC)
 
    {
 
      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
  /* If this is a function, put it in the procedure linkage table.  We
     will fill in the contents of the procedure linkage table later,
     will fill in the contents of the procedure linkage table later,
     when we know the address of the .got section.  */
     when we know the address of the .got section.  */
  if (h->type == STT_FUNC
  if (h->type == STT_FUNC
      || h->needs_plt)
      || h->needs_plt)
Line 1611... Line 1796...
    }
    }
 
 
  if (ELIMINATE_COPY_RELOCS)
  if (ELIMINATE_COPY_RELOCS)
    {
    {
      struct elf64_x86_64_link_hash_entry * eh;
      struct elf64_x86_64_link_hash_entry * eh;
      struct elf64_x86_64_dyn_relocs *p;
      struct elf_dyn_relocs *p;
 
 
      eh = (struct elf64_x86_64_link_hash_entry *) h;
      eh = (struct elf64_x86_64_link_hash_entry *) h;
      for (p = eh->dyn_relocs; p != NULL; p = p->next)
      for (p = eh->dyn_relocs; p != NULL; p = p->next)
        {
        {
          s = p->sec->output_section;
          s = p->sec->output_section;
Line 1667... Line 1852...
 
 
/* Allocate space in .plt, .got and associated reloc sections for
/* Allocate space in .plt, .got and associated reloc sections for
   dynamic relocs.  */
   dynamic relocs.  */
 
 
static bfd_boolean
static bfd_boolean
allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
elf64_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
{
{
  struct bfd_link_info *info;
  struct bfd_link_info *info;
  struct elf64_x86_64_link_hash_table *htab;
  struct elf64_x86_64_link_hash_table *htab;
  struct elf64_x86_64_link_hash_entry *eh;
  struct elf64_x86_64_link_hash_entry *eh;
  struct elf64_x86_64_dyn_relocs *p;
  struct elf_dyn_relocs *p;
 
 
  if (h->root.type == bfd_link_hash_indirect)
  if (h->root.type == bfd_link_hash_indirect)
    return TRUE;
    return TRUE;
 
 
  if (h->root.type == bfd_link_hash_warning)
  if (h->root.type == bfd_link_hash_warning)
    h = (struct elf_link_hash_entry *) h->root.u.i.link;
    h = (struct elf_link_hash_entry *) h->root.u.i.link;
 
  eh = (struct elf64_x86_64_link_hash_entry *) h;
 
 
  info = (struct bfd_link_info *) inf;
  info = (struct bfd_link_info *) inf;
  htab = elf64_x86_64_hash_table (info);
  htab = elf64_x86_64_hash_table (info);
 
 
  if (htab->elf.dynamic_sections_created
  /* Since STT_GNU_IFUNC symbol must go through PLT, we handle it
 
     here if it is defined and referenced in a non-shared object.  */
 
  if (h->type == STT_GNU_IFUNC
 
      && h->def_regular)
 
    return _bfd_elf_allocate_ifunc_dyn_relocs (info, h,
 
                                               &eh->dyn_relocs,
 
                                               PLT_ENTRY_SIZE,
 
                                               GOT_ENTRY_SIZE);
 
  else if (htab->elf.dynamic_sections_created
      && h->plt.refcount > 0)
      && h->plt.refcount > 0)
    {
    {
      /* Make sure this symbol is output as a dynamic symbol.
      /* Make sure this symbol is output as a dynamic symbol.
         Undefined weak syms won't yet be marked as dynamic.  */
         Undefined weak syms won't yet be marked as dynamic.  */
      if (h->dynindx == -1
      if (h->dynindx == -1
Line 1698... Line 1892...
        }
        }
 
 
      if (info->shared
      if (info->shared
          || WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, 0, h))
          || WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, 0, h))
        {
        {
          asection *s = htab->splt;
          asection *s = htab->elf.splt;
 
 
          /* If this is the first .plt entry, make room for the special
          /* If this is the first .plt entry, make room for the special
             first entry.  */
             first entry.  */
          if (s->size == 0)
          if (s->size == 0)
            s->size += PLT_ENTRY_SIZE;
            s->size += PLT_ENTRY_SIZE;
Line 1724... Line 1918...
          /* Make room for this entry.  */
          /* Make room for this entry.  */
          s->size += PLT_ENTRY_SIZE;
          s->size += PLT_ENTRY_SIZE;
 
 
          /* We also need to make an entry in the .got.plt section, which
          /* We also need to make an entry in the .got.plt section, which
             will be placed in the .got section by the linker script.  */
             will be placed in the .got section by the linker script.  */
          htab->sgotplt->size += GOT_ENTRY_SIZE;
          htab->elf.sgotplt->size += GOT_ENTRY_SIZE;
 
 
          /* We also need to make an entry in the .rela.plt section.  */
          /* We also need to make an entry in the .rela.plt section.  */
          htab->srelplt->size += sizeof (Elf64_External_Rela);
          htab->elf.srelplt->size += sizeof (Elf64_External_Rela);
          htab->srelplt->reloc_count++;
          htab->elf.srelplt->reloc_count++;
        }
        }
      else
      else
        {
        {
          h->plt.offset = (bfd_vma) -1;
          h->plt.offset = (bfd_vma) -1;
          h->needs_plt = 0;
          h->needs_plt = 0;
Line 1742... Line 1936...
    {
    {
      h->plt.offset = (bfd_vma) -1;
      h->plt.offset = (bfd_vma) -1;
      h->needs_plt = 0;
      h->needs_plt = 0;
    }
    }
 
 
  eh = (struct elf64_x86_64_link_hash_entry *) h;
 
  eh->tlsdesc_got = (bfd_vma) -1;
  eh->tlsdesc_got = (bfd_vma) -1;
 
 
  /* If R_X86_64_GOTTPOFF symbol is now local to the binary,
  /* If R_X86_64_GOTTPOFF symbol is now local to the binary,
     make it a R_X86_64_TPOFF32 requiring no GOT entry.  */
     make it a R_X86_64_TPOFF32 requiring no GOT entry.  */
  if (h->got.refcount > 0
  if (h->got.refcount > 0
      && !info->shared
      && info->executable
      && h->dynindx == -1
      && h->dynindx == -1
      && elf64_x86_64_hash_entry (h)->tls_type == GOT_TLS_IE)
      && elf64_x86_64_hash_entry (h)->tls_type == GOT_TLS_IE)
 
    {
    h->got.offset = (bfd_vma) -1;
    h->got.offset = (bfd_vma) -1;
 
    }
  else if (h->got.refcount > 0)
  else if (h->got.refcount > 0)
    {
    {
      asection *s;
      asection *s;
      bfd_boolean dyn;
      bfd_boolean dyn;
      int tls_type = elf64_x86_64_hash_entry (h)->tls_type;
      int tls_type = elf64_x86_64_hash_entry (h)->tls_type;
Line 1769... Line 1964...
            return FALSE;
            return FALSE;
        }
        }
 
 
      if (GOT_TLS_GDESC_P (tls_type))
      if (GOT_TLS_GDESC_P (tls_type))
        {
        {
          eh->tlsdesc_got = htab->sgotplt->size
          eh->tlsdesc_got = htab->elf.sgotplt->size
            - elf64_x86_64_compute_jump_table_size (htab);
            - elf64_x86_64_compute_jump_table_size (htab);
          htab->sgotplt->size += 2 * GOT_ENTRY_SIZE;
          htab->elf.sgotplt->size += 2 * GOT_ENTRY_SIZE;
          h->got.offset = (bfd_vma) -2;
          h->got.offset = (bfd_vma) -2;
        }
        }
      if (! GOT_TLS_GDESC_P (tls_type)
      if (! GOT_TLS_GDESC_P (tls_type)
          || GOT_TLS_GD_P (tls_type))
          || GOT_TLS_GD_P (tls_type))
        {
        {
          s = htab->sgot;
          s = htab->elf.sgot;
          h->got.offset = s->size;
          h->got.offset = s->size;
          s->size += GOT_ENTRY_SIZE;
          s->size += GOT_ENTRY_SIZE;
          if (GOT_TLS_GD_P (tls_type))
          if (GOT_TLS_GD_P (tls_type))
            s->size += GOT_ENTRY_SIZE;
            s->size += GOT_ENTRY_SIZE;
        }
        }
Line 1789... Line 1984...
      /* R_X86_64_TLSGD needs one dynamic relocation if local symbol
      /* R_X86_64_TLSGD needs one dynamic relocation if local symbol
         and two if global.
         and two if global.
         R_X86_64_GOTTPOFF needs one dynamic relocation.  */
         R_X86_64_GOTTPOFF needs one dynamic relocation.  */
      if ((GOT_TLS_GD_P (tls_type) && h->dynindx == -1)
      if ((GOT_TLS_GD_P (tls_type) && h->dynindx == -1)
          || tls_type == GOT_TLS_IE)
          || tls_type == GOT_TLS_IE)
        htab->srelgot->size += sizeof (Elf64_External_Rela);
        htab->elf.srelgot->size += sizeof (Elf64_External_Rela);
      else if (GOT_TLS_GD_P (tls_type))
      else if (GOT_TLS_GD_P (tls_type))
        htab->srelgot->size += 2 * sizeof (Elf64_External_Rela);
        htab->elf.srelgot->size += 2 * sizeof (Elf64_External_Rela);
      else if (! GOT_TLS_GDESC_P (tls_type)
      else if (! GOT_TLS_GDESC_P (tls_type)
               && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
               && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
                   || h->root.type != bfd_link_hash_undefweak)
                   || h->root.type != bfd_link_hash_undefweak)
               && (info->shared
               && (info->shared
                   || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h)))
                   || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h)))
        htab->srelgot->size += sizeof (Elf64_External_Rela);
        htab->elf.srelgot->size += sizeof (Elf64_External_Rela);
      if (GOT_TLS_GDESC_P (tls_type))
      if (GOT_TLS_GDESC_P (tls_type))
        {
        {
          htab->srelplt->size += sizeof (Elf64_External_Rela);
          htab->elf.srelplt->size += sizeof (Elf64_External_Rela);
          htab->tlsdesc_plt = (bfd_vma) -1;
          htab->tlsdesc_plt = (bfd_vma) -1;
        }
        }
    }
    }
  else
  else
    h->got.offset = (bfd_vma) -1;
    h->got.offset = (bfd_vma) -1;
Line 1826... Line 2021...
         function rather than going via the plt.  If people want
         function rather than going via the plt.  If people want
         function pointer comparisons to work as expected then they
         function pointer comparisons to work as expected then they
         should avoid writing weird assembly.  */
         should avoid writing weird assembly.  */
      if (SYMBOL_CALLS_LOCAL (info, h))
      if (SYMBOL_CALLS_LOCAL (info, h))
        {
        {
          struct elf64_x86_64_dyn_relocs **pp;
          struct elf_dyn_relocs **pp;
 
 
          for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
          for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
            {
            {
              p->count -= p->pc_count;
              p->count -= p->pc_count;
              p->pc_count = 0;
              p->pc_count = 0;
Line 1850... Line 2045...
            eh->dyn_relocs = NULL;
            eh->dyn_relocs = NULL;
 
 
          /* Make sure undefined weak symbols are output as a dynamic
          /* Make sure undefined weak symbols are output as a dynamic
             symbol in PIEs.  */
             symbol in PIEs.  */
          else if (h->dynindx == -1
          else if (h->dynindx == -1
                   && !h->forced_local)
                   && ! h->forced_local
            {
                   && ! bfd_elf_link_record_dynamic_symbol (info, h))
              if (! bfd_elf_link_record_dynamic_symbol (info, h))
 
                return FALSE;
                return FALSE;
            }
            }
        }
 
    }
    }
  else if (ELIMINATE_COPY_RELOCS)
  else if (ELIMINATE_COPY_RELOCS)
    {
    {
      /* For the non-shared case, discard space for relocs against
      /* For the non-shared case, discard space for relocs against
         symbols which turn out to need copy relocs or are not
         symbols which turn out to need copy relocs or are not
Line 1873... Line 2067...
                      || h->root.type == bfd_link_hash_undefined))))
                      || h->root.type == bfd_link_hash_undefined))))
        {
        {
          /* Make sure this symbol is output as a dynamic symbol.
          /* Make sure this symbol is output as a dynamic symbol.
             Undefined weak syms won't yet be marked as dynamic.  */
             Undefined weak syms won't yet be marked as dynamic.  */
          if (h->dynindx == -1
          if (h->dynindx == -1
              && !h->forced_local)
              && ! h->forced_local
            {
              && ! bfd_elf_link_record_dynamic_symbol (info, h))
              if (! bfd_elf_link_record_dynamic_symbol (info, h))
 
                return FALSE;
                return FALSE;
            }
 
 
 
          /* If that succeeded, we know we'll be keeping all the
          /* If that succeeded, we know we'll be keeping all the
             relocs.  */
             relocs.  */
          if (h->dynindx != -1)
          if (h->dynindx != -1)
            goto keep;
            goto keep;
Line 1893... Line 2085...
    }
    }
 
 
  /* Finally, allocate space.  */
  /* Finally, allocate space.  */
  for (p = eh->dyn_relocs; p != NULL; p = p->next)
  for (p = eh->dyn_relocs; p != NULL; p = p->next)
    {
    {
      asection *sreloc = elf_section_data (p->sec)->sreloc;
      asection * sreloc;
 
 
 
      sreloc = elf_section_data (p->sec)->sreloc;
 
 
 
      BFD_ASSERT (sreloc != NULL);
 
 
      sreloc->size += p->count * sizeof (Elf64_External_Rela);
      sreloc->size += p->count * sizeof (Elf64_External_Rela);
    }
    }
 
 
  return TRUE;
  return TRUE;
}
}
 
 
 
/* Allocate space in .plt, .got and associated reloc sections for
 
   local dynamic relocs.  */
 
 
 
static bfd_boolean
 
elf64_x86_64_allocate_local_dynrelocs (void **slot, void *inf)
 
{
 
  struct elf_link_hash_entry *h
 
    = (struct elf_link_hash_entry *) *slot;
 
 
 
  if (h->type != STT_GNU_IFUNC
 
      || !h->def_regular
 
      || !h->ref_regular
 
      || !h->forced_local
 
      || h->root.type != bfd_link_hash_defined)
 
    abort ();
 
 
 
  return elf64_x86_64_allocate_dynrelocs (h, inf);
 
}
 
 
/* Find any dynamic relocs that apply to read-only sections.  */
/* Find any dynamic relocs that apply to read-only sections.  */
 
 
static bfd_boolean
static bfd_boolean
readonly_dynrelocs (struct elf_link_hash_entry *h, void * inf)
elf64_x86_64_readonly_dynrelocs (struct elf_link_hash_entry *h, void * inf)
{
{
  struct elf64_x86_64_link_hash_entry *eh;
  struct elf64_x86_64_link_hash_entry *eh;
  struct elf64_x86_64_dyn_relocs *p;
  struct elf_dyn_relocs *p;
 
 
  if (h->root.type == bfd_link_hash_warning)
  if (h->root.type == bfd_link_hash_warning)
    h = (struct elf_link_hash_entry *) h->root.u.i.link;
    h = (struct elf_link_hash_entry *) h->root.u.i.link;
 
 
  eh = (struct elf64_x86_64_link_hash_entry *) h;
  eh = (struct elf64_x86_64_link_hash_entry *) h;
Line 1976... Line 2192...
      if (! is_x86_64_elf (ibfd))
      if (! is_x86_64_elf (ibfd))
        continue;
        continue;
 
 
      for (s = ibfd->sections; s != NULL; s = s->next)
      for (s = ibfd->sections; s != NULL; s = s->next)
        {
        {
          struct elf64_x86_64_dyn_relocs *p;
          struct elf_dyn_relocs *p;
 
 
          for (p = (struct elf64_x86_64_dyn_relocs *)
          for (p = (struct elf_dyn_relocs *)
                    (elf_section_data (s)->local_dynrel);
                    (elf_section_data (s)->local_dynrel);
               p != NULL;
               p != NULL;
               p = p->next)
               p = p->next)
            {
            {
              if (!bfd_is_abs_section (p->sec)
              if (!bfd_is_abs_section (p->sec)
Line 1997... Line 2213...
                {
                {
                  srel = elf_section_data (p->sec)->sreloc;
                  srel = elf_section_data (p->sec)->sreloc;
                  srel->size += p->count * sizeof (Elf64_External_Rela);
                  srel->size += p->count * sizeof (Elf64_External_Rela);
                  if ((p->sec->output_section->flags & SEC_READONLY) != 0)
                  if ((p->sec->output_section->flags & SEC_READONLY) != 0)
                    info->flags |= DF_TEXTREL;
                    info->flags |= DF_TEXTREL;
 
 
                }
                }
            }
            }
        }
        }
 
 
      local_got = elf_local_got_refcounts (ibfd);
      local_got = elf_local_got_refcounts (ibfd);
Line 2011... Line 2226...
      symtab_hdr = &elf_symtab_hdr (ibfd);
      symtab_hdr = &elf_symtab_hdr (ibfd);
      locsymcount = symtab_hdr->sh_info;
      locsymcount = symtab_hdr->sh_info;
      end_local_got = local_got + locsymcount;
      end_local_got = local_got + locsymcount;
      local_tls_type = elf64_x86_64_local_got_tls_type (ibfd);
      local_tls_type = elf64_x86_64_local_got_tls_type (ibfd);
      local_tlsdesc_gotent = elf64_x86_64_local_tlsdesc_gotent (ibfd);
      local_tlsdesc_gotent = elf64_x86_64_local_tlsdesc_gotent (ibfd);
      s = htab->sgot;
      s = htab->elf.sgot;
      srel = htab->srelgot;
      srel = htab->elf.srelgot;
      for (; local_got < end_local_got;
      for (; local_got < end_local_got;
           ++local_got, ++local_tls_type, ++local_tlsdesc_gotent)
           ++local_got, ++local_tls_type, ++local_tlsdesc_gotent)
        {
        {
          *local_tlsdesc_gotent = (bfd_vma) -1;
          *local_tlsdesc_gotent = (bfd_vma) -1;
          if (*local_got > 0)
          if (*local_got > 0)
            {
            {
              if (GOT_TLS_GDESC_P (*local_tls_type))
              if (GOT_TLS_GDESC_P (*local_tls_type))
                {
                {
                  *local_tlsdesc_gotent = htab->sgotplt->size
                  *local_tlsdesc_gotent = htab->elf.sgotplt->size
                    - elf64_x86_64_compute_jump_table_size (htab);
                    - elf64_x86_64_compute_jump_table_size (htab);
                  htab->sgotplt->size += 2 * GOT_ENTRY_SIZE;
                  htab->elf.sgotplt->size += 2 * GOT_ENTRY_SIZE;
                  *local_got = (bfd_vma) -2;
                  *local_got = (bfd_vma) -2;
                }
                }
              if (! GOT_TLS_GDESC_P (*local_tls_type)
              if (! GOT_TLS_GDESC_P (*local_tls_type)
                  || GOT_TLS_GD_P (*local_tls_type))
                  || GOT_TLS_GD_P (*local_tls_type))
                {
                {
Line 2040... Line 2255...
                  || GOT_TLS_GD_ANY_P (*local_tls_type)
                  || GOT_TLS_GD_ANY_P (*local_tls_type)
                  || *local_tls_type == GOT_TLS_IE)
                  || *local_tls_type == GOT_TLS_IE)
                {
                {
                  if (GOT_TLS_GDESC_P (*local_tls_type))
                  if (GOT_TLS_GDESC_P (*local_tls_type))
                    {
                    {
                      htab->srelplt->size += sizeof (Elf64_External_Rela);
                      htab->elf.srelplt->size
 
                        += sizeof (Elf64_External_Rela);
                      htab->tlsdesc_plt = (bfd_vma) -1;
                      htab->tlsdesc_plt = (bfd_vma) -1;
                    }
                    }
                  if (! GOT_TLS_GDESC_P (*local_tls_type)
                  if (! GOT_TLS_GDESC_P (*local_tls_type)
                      || GOT_TLS_GD_P (*local_tls_type))
                      || GOT_TLS_GD_P (*local_tls_type))
                    srel->size += sizeof (Elf64_External_Rela);
                    srel->size += sizeof (Elf64_External_Rela);
Line 2057... Line 2273...
 
 
  if (htab->tls_ld_got.refcount > 0)
  if (htab->tls_ld_got.refcount > 0)
    {
    {
      /* Allocate 2 got entries and 1 dynamic reloc for R_X86_64_TLSLD
      /* Allocate 2 got entries and 1 dynamic reloc for R_X86_64_TLSLD
         relocs.  */
         relocs.  */
      htab->tls_ld_got.offset = htab->sgot->size;
      htab->tls_ld_got.offset = htab->elf.sgot->size;
      htab->sgot->size += 2 * GOT_ENTRY_SIZE;
      htab->elf.sgot->size += 2 * GOT_ENTRY_SIZE;
      htab->srelgot->size += sizeof (Elf64_External_Rela);
      htab->elf.srelgot->size += sizeof (Elf64_External_Rela);
    }
    }
  else
  else
    htab->tls_ld_got.offset = -1;
    htab->tls_ld_got.offset = -1;
 
 
  /* Allocate global sym .plt and .got entries, and space for global
  /* Allocate global sym .plt and .got entries, and space for global
     sym dynamic relocs.  */
     sym dynamic relocs.  */
  elf_link_hash_traverse (&htab->elf, allocate_dynrelocs, (PTR) info);
  elf_link_hash_traverse (&htab->elf, elf64_x86_64_allocate_dynrelocs,
 
                          info);
 
 
 
  /* Allocate .plt and .got entries, and space for local symbols.  */
 
  htab_traverse (htab->loc_hash_table,
 
                 elf64_x86_64_allocate_local_dynrelocs,
 
                 info);
 
 
  /* For every jump slot reserved in the sgotplt, reloc_count is
  /* For every jump slot reserved in the sgotplt, reloc_count is
     incremented.  However, when we reserve space for TLS descriptors,
     incremented.  However, when we reserve space for TLS descriptors,
     it's not incremented, so in order to compute the space reserved
     it's not incremented, so in order to compute the space reserved
     for them, it suffices to multiply the reloc count by the jump
     for them, it suffices to multiply the reloc count by the jump
     slot size.  */
     slot size.  */
  if (htab->srelplt)
  if (htab->elf.srelplt)
    htab->sgotplt_jump_table_size
    htab->sgotplt_jump_table_size
      = elf64_x86_64_compute_jump_table_size (htab);
      = elf64_x86_64_compute_jump_table_size (htab);
 
 
  if (htab->tlsdesc_plt)
  if (htab->tlsdesc_plt)
    {
    {
Line 2085... Line 2307...
         PLT and GOT entries they require.  */
         PLT and GOT entries they require.  */
      if ((info->flags & DF_BIND_NOW))
      if ((info->flags & DF_BIND_NOW))
        htab->tlsdesc_plt = 0;
        htab->tlsdesc_plt = 0;
      else
      else
        {
        {
          htab->tlsdesc_got = htab->sgot->size;
          htab->tlsdesc_got = htab->elf.sgot->size;
          htab->sgot->size += GOT_ENTRY_SIZE;
          htab->elf.sgot->size += GOT_ENTRY_SIZE;
          /* Reserve room for the initial entry.
          /* Reserve room for the initial entry.
             FIXME: we could probably do away with it in this case.  */
             FIXME: we could probably do away with it in this case.  */
          if (htab->splt->size == 0)
          if (htab->elf.splt->size == 0)
            htab->splt->size += PLT_ENTRY_SIZE;
            htab->elf.splt->size += PLT_ENTRY_SIZE;
          htab->tlsdesc_plt = htab->splt->size;
          htab->tlsdesc_plt = htab->elf.splt->size;
          htab->splt->size += PLT_ENTRY_SIZE;
          htab->elf.splt->size += PLT_ENTRY_SIZE;
        }
        }
    }
    }
 
 
  /* We now have determined the sizes of the various dynamic sections.
  /* We now have determined the sizes of the various dynamic sections.
     Allocate memory for them.  */
     Allocate memory for them.  */
Line 2104... Line 2326...
  for (s = dynobj->sections; s != NULL; s = s->next)
  for (s = dynobj->sections; s != NULL; s = s->next)
    {
    {
      if ((s->flags & SEC_LINKER_CREATED) == 0)
      if ((s->flags & SEC_LINKER_CREATED) == 0)
        continue;
        continue;
 
 
      if (s == htab->splt
      if (s == htab->elf.splt
          || s == htab->sgot
          || s == htab->elf.sgot
          || s == htab->sgotplt
          || s == htab->elf.sgotplt
 
          || s == htab->elf.iplt
 
          || s == htab->elf.igotplt
          || s == htab->sdynbss)
          || s == htab->sdynbss)
        {
        {
          /* Strip this section if we don't need it; see the
          /* Strip this section if we don't need it; see the
             comment below.  */
             comment below.  */
        }
        }
      else if (CONST_STRNEQ (bfd_get_section_name (dynobj, s), ".rela"))
      else if (CONST_STRNEQ (bfd_get_section_name (dynobj, s), ".rela"))
        {
        {
          if (s->size != 0 && s != htab->srelplt)
          if (s->size != 0 && s != htab->elf.srelplt)
            relocs = TRUE;
            relocs = TRUE;
 
 
          /* We use the reloc_count field as a counter if we need
          /* We use the reloc_count field as a counter if we need
             to copy relocs into the output file.  */
             to copy relocs into the output file.  */
          if (s != htab->srelplt)
          if (s != htab->elf.srelplt)
            s->reloc_count = 0;
            s->reloc_count = 0;
        }
        }
      else
      else
        {
        {
          /* It's not one of our sections, so don't allocate space.  */
          /* It's not one of our sections, so don't allocate space.  */
Line 2173... Line 2397...
        {
        {
          if (!add_dynamic_entry (DT_DEBUG, 0))
          if (!add_dynamic_entry (DT_DEBUG, 0))
            return FALSE;
            return FALSE;
        }
        }
 
 
      if (htab->splt->size != 0)
      if (htab->elf.splt->size != 0)
        {
        {
          if (!add_dynamic_entry (DT_PLTGOT, 0)
          if (!add_dynamic_entry (DT_PLTGOT, 0)
              || !add_dynamic_entry (DT_PLTRELSZ, 0)
              || !add_dynamic_entry (DT_PLTRELSZ, 0)
              || !add_dynamic_entry (DT_PLTREL, DT_RELA)
              || !add_dynamic_entry (DT_PLTREL, DT_RELA)
              || !add_dynamic_entry (DT_JMPREL, 0))
              || !add_dynamic_entry (DT_JMPREL, 0))
Line 2197... Line 2421...
            return FALSE;
            return FALSE;
 
 
          /* If any dynamic relocs apply to a read-only section,
          /* If any dynamic relocs apply to a read-only section,
             then we need a DT_TEXTREL entry.  */
             then we need a DT_TEXTREL entry.  */
          if ((info->flags & DF_TEXTREL) == 0)
          if ((info->flags & DF_TEXTREL) == 0)
            elf_link_hash_traverse (&htab->elf, readonly_dynrelocs,
            elf_link_hash_traverse (&htab->elf,
                                    (PTR) info);
                                    elf64_x86_64_readonly_dynrelocs,
 
                                    info);
 
 
          if ((info->flags & DF_TEXTREL) != 0)
          if ((info->flags & DF_TEXTREL) != 0)
            {
            {
              if (!add_dynamic_entry (DT_TEXTREL, 0))
              if (!add_dynamic_entry (DT_TEXTREL, 0))
                return FALSE;
                return FALSE;
Line 2237... Line 2462...
          if (!(_bfd_generic_link_add_one_symbol
          if (!(_bfd_generic_link_add_one_symbol
                (info, output_bfd, "_TLS_MODULE_BASE_", BSF_LOCAL,
                (info, output_bfd, "_TLS_MODULE_BASE_", BSF_LOCAL,
                 tls_sec, 0, NULL, FALSE,
                 tls_sec, 0, NULL, FALSE,
                 bed->collect, &bh)))
                 bed->collect, &bh)))
            return FALSE;
            return FALSE;
 
 
 
          elf64_x86_64_hash_table (info)->tls_module_base = bh;
 
 
          tlsbase = (struct elf_link_hash_entry *)bh;
          tlsbase = (struct elf_link_hash_entry *)bh;
          tlsbase->def_regular = 1;
          tlsbase->def_regular = 1;
          tlsbase->other = STV_HIDDEN;
          tlsbase->other = STV_HIDDEN;
          (*bed->elf_backend_hide_symbol) (info, tlsbase, TRUE);
          (*bed->elf_backend_hide_symbol) (info, tlsbase, TRUE);
        }
        }
    }
    }
 
 
  return TRUE;
  return TRUE;
}
}
 
 
 
/* _TLS_MODULE_BASE_ needs to be treated especially when linking
 
   executables.  Rather than setting it to the beginning of the TLS
 
   section, we have to set it to the end.  This function may be called
 
   multiple times, it is idempotent.  */
 
 
 
static void
 
elf64_x86_64_set_tls_module_base (struct bfd_link_info *info)
 
{
 
  struct bfd_link_hash_entry *base;
 
 
 
  if (!info->executable)
 
    return;
 
 
 
  base = elf64_x86_64_hash_table (info)->tls_module_base;
 
 
 
  if (!base)
 
    return;
 
 
 
  base->u.def.value = elf_hash_table (info)->tls_size;
 
}
 
 
/* Return the base VMA address which should be subtracted from real addresses
/* Return the base VMA address which should be subtracted from real addresses
   when resolving @dtpoff relocation.
   when resolving @dtpoff relocation.
   This is PT_TLS segment p_vaddr.  */
   This is PT_TLS segment p_vaddr.  */
 
 
static bfd_vma
static bfd_vma
dtpoff_base (struct bfd_link_info *info)
elf64_x86_64_dtpoff_base (struct bfd_link_info *info)
{
{
  /* If tls_sec is NULL, we should have signalled an error already.  */
  /* If tls_sec is NULL, we should have signalled an error already.  */
  if (elf_hash_table (info)->tls_sec == NULL)
  if (elf_hash_table (info)->tls_sec == NULL)
    return 0;
    return 0;
  return elf_hash_table (info)->tls_sec->vma;
  return elf_hash_table (info)->tls_sec->vma;
Line 2264... Line 2513...
 
 
/* Return the relocation value for @tpoff relocation
/* Return the relocation value for @tpoff relocation
   if STT_TLS virtual address is ADDRESS.  */
   if STT_TLS virtual address is ADDRESS.  */
 
 
static bfd_vma
static bfd_vma
tpoff (struct bfd_link_info *info, bfd_vma address)
elf64_x86_64_tpoff (struct bfd_link_info *info, bfd_vma address)
{
{
  struct elf_link_hash_table *htab = elf_hash_table (info);
  struct elf_link_hash_table *htab = elf_hash_table (info);
 
 
  /* If tls_segment is NULL, we should have signalled an error already.  */
  /* If tls_segment is NULL, we should have signalled an error already.  */
  if (htab->tls_sec == NULL)
  if (htab->tls_sec == NULL)
Line 2317... Line 2566...
  symtab_hdr = &elf_symtab_hdr (input_bfd);
  symtab_hdr = &elf_symtab_hdr (input_bfd);
  sym_hashes = elf_sym_hashes (input_bfd);
  sym_hashes = elf_sym_hashes (input_bfd);
  local_got_offsets = elf_local_got_offsets (input_bfd);
  local_got_offsets = elf_local_got_offsets (input_bfd);
  local_tlsdesc_gotents = elf64_x86_64_local_tlsdesc_gotent (input_bfd);
  local_tlsdesc_gotents = elf64_x86_64_local_tlsdesc_gotent (input_bfd);
 
 
 
  elf64_x86_64_set_tls_module_base (info);
 
 
  rel = relocs;
  rel = relocs;
  relend = relocs + input_section->reloc_count;
  relend = relocs + input_section->reloc_count;
  for (; rel < relend; rel++)
  for (; rel < relend; rel++)
    {
    {
      unsigned int r_type;
      unsigned int r_type;
Line 2332... Line 2583...
      bfd_vma off, offplt;
      bfd_vma off, offplt;
      bfd_vma relocation;
      bfd_vma relocation;
      bfd_boolean unresolved_reloc;
      bfd_boolean unresolved_reloc;
      bfd_reloc_status_type r;
      bfd_reloc_status_type r;
      int tls_type;
      int tls_type;
 
      asection *base_got;
 
 
      r_type = ELF64_R_TYPE (rel->r_info);
      r_type = ELF64_R_TYPE (rel->r_info);
      if (r_type == (int) R_X86_64_GNU_VTINHERIT
      if (r_type == (int) R_X86_64_GNU_VTINHERIT
          || r_type == (int) R_X86_64_GNU_VTENTRY)
          || r_type == (int) R_X86_64_GNU_VTENTRY)
        continue;
        continue;
Line 2355... Line 2607...
      if (r_symndx < symtab_hdr->sh_info)
      if (r_symndx < symtab_hdr->sh_info)
        {
        {
          sym = local_syms + r_symndx;
          sym = local_syms + r_symndx;
          sec = local_sections[r_symndx];
          sec = local_sections[r_symndx];
 
 
          relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
          relocation = _bfd_elf_rela_local_sym (output_bfd, sym,
 
                                                &sec, rel);
 
 
 
          /* Relocate against local STT_GNU_IFUNC symbol.  */
 
          if (!info->relocatable
 
              && ELF64_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
 
            {
 
              h = elf64_x86_64_get_local_sym_hash (htab, input_bfd,
 
                                                   rel, FALSE);
 
              if (h == NULL)
 
                abort ();
 
 
 
              /* Set STT_GNU_IFUNC symbol value.  */
 
              h->root.u.def.value = sym->st_value;
 
              h->root.u.def.section = sec;
 
            }
        }
        }
      else
      else
        {
        {
          bfd_boolean warned;
          bfd_boolean warned;
 
 
Line 2381... Line 2648...
        }
        }
 
 
      if (info->relocatable)
      if (info->relocatable)
        continue;
        continue;
 
 
 
      /* Since STT_GNU_IFUNC symbol must go through PLT, we handle
 
         it here if it is defined in a non-shared object.  */
 
      if (h != NULL
 
          && h->type == STT_GNU_IFUNC
 
          && h->def_regular)
 
        {
 
          asection *plt;
 
          bfd_vma plt_index;
 
          const char *name;
 
 
 
          if ((input_section->flags & SEC_ALLOC) == 0
 
              || h->plt.offset == (bfd_vma) -1)
 
            abort ();
 
 
 
          /* STT_GNU_IFUNC symbol must go through PLT.  */
 
          plt = htab->elf.splt ? htab->elf.splt : htab->elf.iplt;
 
          relocation = (plt->output_section->vma
 
                        + plt->output_offset + h->plt.offset);
 
 
 
          switch (r_type)
 
            {
 
            default:
 
              if (h->root.root.string)
 
                name = h->root.root.string;
 
              else
 
                name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym,
 
                                         NULL);
 
              (*_bfd_error_handler)
 
                (_("%B: relocation %s against STT_GNU_IFUNC "
 
                   "symbol `%s' isn't handled by %s"), input_bfd,
 
                 x86_64_elf_howto_table[r_type].name,
 
                 name, __FUNCTION__);
 
              bfd_set_error (bfd_error_bad_value);
 
              return FALSE;
 
 
 
            case R_X86_64_32S:
 
              if (info->shared)
 
                abort ();
 
              goto do_relocation;
 
 
 
            case R_X86_64_64:
 
              if (rel->r_addend != 0)
 
                {
 
                  if (h->root.root.string)
 
                    name = h->root.root.string;
 
                  else
 
                    name = bfd_elf_sym_name (input_bfd, symtab_hdr,
 
                                             sym, NULL);
 
                  (*_bfd_error_handler)
 
                    (_("%B: relocation %s against STT_GNU_IFUNC "
 
                       "symbol `%s' has non-zero addend: %d"),
 
                     input_bfd, x86_64_elf_howto_table[r_type].name,
 
                     name, rel->r_addend);
 
                  bfd_set_error (bfd_error_bad_value);
 
                  return FALSE;
 
                }
 
 
 
              /* Generate dynamic relcoation only when there is a
 
                 non-GOF reference in a shared object.  */
 
              if (info->shared && h->non_got_ref)
 
                {
 
                  Elf_Internal_Rela outrel;
 
                  bfd_byte *loc;
 
                  asection *sreloc;
 
 
 
                  /* Need a dynamic relocation to get the real function
 
                     address.  */
 
                  outrel.r_offset = _bfd_elf_section_offset (output_bfd,
 
                                                             info,
 
                                                             input_section,
 
                                                             rel->r_offset);
 
                  if (outrel.r_offset == (bfd_vma) -1
 
                      || outrel.r_offset == (bfd_vma) -2)
 
                    abort ();
 
 
 
                  outrel.r_offset += (input_section->output_section->vma
 
                                      + input_section->output_offset);
 
 
 
                  if (h->dynindx == -1
 
                      || h->forced_local
 
                      || info->executable)
 
                    {
 
                      /* This symbol is resolved locally.  */
 
                      outrel.r_info = ELF64_R_INFO (0, R_X86_64_IRELATIVE);
 
                      outrel.r_addend = (h->root.u.def.value
 
                                         + h->root.u.def.section->output_section->vma
 
                                         + h->root.u.def.section->output_offset);
 
                    }
 
                  else
 
                    {
 
                      outrel.r_info = ELF64_R_INFO (h->dynindx, r_type);
 
                      outrel.r_addend = 0;
 
                    }
 
 
 
                  sreloc = htab->elf.irelifunc;
 
                  loc = sreloc->contents;
 
                  loc += (sreloc->reloc_count++
 
                          * sizeof (Elf64_External_Rela));
 
                  bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc);
 
 
 
                  /* If this reloc is against an external symbol, we
 
                     do not want to fiddle with the addend.  Otherwise,
 
                     we need to include the symbol value so that it
 
                     becomes an addend for the dynamic reloc.  For an
 
                     internal symbol, we have updated addend.  */
 
                  continue;
 
                }
 
 
 
            case R_X86_64_32:
 
            case R_X86_64_PC32:
 
            case R_X86_64_PC64:
 
            case R_X86_64_PLT32:
 
              goto do_relocation;
 
 
 
            case R_X86_64_GOTPCREL:
 
            case R_X86_64_GOTPCREL64:
 
              base_got = htab->elf.sgot;
 
              off = h->got.offset;
 
 
 
              if (base_got == NULL)
 
                abort ();
 
 
 
              if (off == (bfd_vma) -1)
 
                {
 
                  /* We can't use h->got.offset here to save state, or
 
                     even just remember the offset, as finish_dynamic_symbol
 
                     would use that as offset into .got.  */
 
 
 
                  if (htab->elf.splt != NULL)
 
                    {
 
                      plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1;
 
                      off = (plt_index + 3) * GOT_ENTRY_SIZE;
 
                      base_got = htab->elf.sgotplt;
 
                    }
 
                  else
 
                    {
 
                      plt_index = h->plt.offset / PLT_ENTRY_SIZE;
 
                      off = plt_index * GOT_ENTRY_SIZE;
 
                      base_got = htab->elf.igotplt;
 
                    }
 
 
 
                  if (h->dynindx == -1
 
                      || h->forced_local
 
                      || info->symbolic)
 
                    {
 
                      /* This references the local defitionion.  We must
 
                         initialize this entry in the global offset table.
 
                         Since the offset must always be a multiple of 8,
 
                         we use the least significant bit to record
 
                         whether we have initialized it already.
 
 
 
                         When doing a dynamic link, we create a .rela.got
 
                         relocation entry to initialize the value.  This
 
                         is done in the finish_dynamic_symbol routine.   */
 
                      if ((off & 1) != 0)
 
                        off &= ~1;
 
                      else
 
                        {
 
                          bfd_put_64 (output_bfd, relocation,
 
                                      base_got->contents + off);
 
                          /* Note that this is harmless for the GOTPLT64
 
                             case, as -1 | 1 still is -1.  */
 
                          h->got.offset |= 1;
 
                        }
 
                    }
 
                }
 
 
 
              relocation = (base_got->output_section->vma
 
                            + base_got->output_offset + off);
 
 
 
              if (r_type != R_X86_64_GOTPCREL
 
                  && r_type != R_X86_64_GOTPCREL64)
 
                {
 
                  asection *gotplt;
 
                  if (htab->elf.splt != NULL)
 
                    gotplt = htab->elf.sgotplt;
 
                  else
 
                    gotplt = htab->elf.igotplt;
 
                  relocation -= (gotplt->output_section->vma
 
                                 - gotplt->output_offset);
 
                }
 
 
 
              goto do_relocation;
 
            }
 
        }
 
 
      /* When generating a shared object, the relocations handled here are
      /* When generating a shared object, the relocations handled here are
         copied into the output file to be resolved at run time.  */
         copied into the output file to be resolved at run time.  */
      switch (r_type)
      switch (r_type)
        {
        {
        asection *base_got;
 
        case R_X86_64_GOT32:
        case R_X86_64_GOT32:
        case R_X86_64_GOT64:
        case R_X86_64_GOT64:
          /* Relocation is to the entry for this symbol in the global
          /* Relocation is to the entry for this symbol in the global
             offset table.  */
             offset table.  */
        case R_X86_64_GOTPCREL:
        case R_X86_64_GOTPCREL:
Line 2400... Line 2852...
             indicates the existence of a PLT entry.  The difficulty is,
             indicates the existence of a PLT entry.  The difficulty is,
             that we must calculate the GOT slot offset from the PLT
             that we must calculate the GOT slot offset from the PLT
             offset, if this symbol got a PLT entry (it was global).
             offset, if this symbol got a PLT entry (it was global).
             Additionally if it's computed from the PLT entry, then that
             Additionally if it's computed from the PLT entry, then that
             GOT offset is relative to .got.plt, not to .got.  */
             GOT offset is relative to .got.plt, not to .got.  */
          base_got = htab->sgot;
          base_got = htab->elf.sgot;
 
 
          if (htab->sgot == NULL)
          if (htab->elf.sgot == NULL)
            abort ();
            abort ();
 
 
          if (h != NULL)
          if (h != NULL)
            {
            {
              bfd_boolean dyn;
              bfd_boolean dyn;
Line 2420... Line 2872...
                     state, or even just remember the offset, as
                     state, or even just remember the offset, as
                     finish_dynamic_symbol would use that as offset into
                     finish_dynamic_symbol would use that as offset into
                     .got.  */
                     .got.  */
                  bfd_vma plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1;
                  bfd_vma plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1;
                  off = (plt_index + 3) * GOT_ENTRY_SIZE;
                  off = (plt_index + 3) * GOT_ENTRY_SIZE;
                  base_got = htab->sgotplt;
                  base_got = htab->elf.sgotplt;
                }
                }
 
 
              dyn = htab->elf.dynamic_sections_created;
              dyn = htab->elf.dynamic_sections_created;
 
 
              if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h)
              if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h)
Line 2481... Line 2933...
                      Elf_Internal_Rela outrel;
                      Elf_Internal_Rela outrel;
                      bfd_byte *loc;
                      bfd_byte *loc;
 
 
                      /* We need to generate a R_X86_64_RELATIVE reloc
                      /* We need to generate a R_X86_64_RELATIVE reloc
                         for the dynamic linker.  */
                         for the dynamic linker.  */
                      s = htab->srelgot;
                      s = htab->elf.srelgot;
                      if (s == NULL)
                      if (s == NULL)
                        abort ();
                        abort ();
 
 
                      outrel.r_offset = (base_got->output_section->vma
                      outrel.r_offset = (base_got->output_section->vma
                                         + base_got->output_offset
                                         + base_got->output_offset
Line 2505... Line 2957...
            abort ();
            abort ();
 
 
          relocation = base_got->output_section->vma
          relocation = base_got->output_section->vma
                       + base_got->output_offset + off;
                       + base_got->output_offset + off;
          if (r_type != R_X86_64_GOTPCREL && r_type != R_X86_64_GOTPCREL64)
          if (r_type != R_X86_64_GOTPCREL && r_type != R_X86_64_GOTPCREL64)
            relocation -= htab->sgotplt->output_section->vma
            relocation -= htab->elf.sgotplt->output_section->vma
                          - htab->sgotplt->output_offset;
                          - htab->elf.sgotplt->output_offset;
 
 
          break;
          break;
 
 
        case R_X86_64_GOTOFF64:
        case R_X86_64_GOTOFF64:
          /* Relocation is relative to the start of the global offset
          /* Relocation is relative to the start of the global offset
Line 2535... Line 2987...
          /* Note that sgot is not involved in this
          /* Note that sgot is not involved in this
             calculation.  We always want the start of .got.plt.  If we
             calculation.  We always want the start of .got.plt.  If we
             defined _GLOBAL_OFFSET_TABLE_ in a different way, as is
             defined _GLOBAL_OFFSET_TABLE_ in a different way, as is
             permitted by the ABI, we might have to change this
             permitted by the ABI, we might have to change this
             calculation.  */
             calculation.  */
          relocation -= htab->sgotplt->output_section->vma
          relocation -= htab->elf.sgotplt->output_section->vma
                        + htab->sgotplt->output_offset;
                        + htab->elf.sgotplt->output_offset;
          break;
          break;
 
 
        case R_X86_64_GOTPC32:
        case R_X86_64_GOTPC32:
        case R_X86_64_GOTPC64:
        case R_X86_64_GOTPC64:
          /* Use global offset table as symbol value.  */
          /* Use global offset table as symbol value.  */
          relocation = htab->sgotplt->output_section->vma
          relocation = htab->elf.sgotplt->output_section->vma
                       + htab->sgotplt->output_offset;
                       + htab->elf.sgotplt->output_offset;
          unresolved_reloc = FALSE;
          unresolved_reloc = FALSE;
          break;
          break;
 
 
        case R_X86_64_PLTOFF64:
        case R_X86_64_PLTOFF64:
          /* Relocation is PLT entry relative to GOT.  For local
          /* Relocation is PLT entry relative to GOT.  For local
             symbols it's the symbol itself relative to GOT.  */
             symbols it's the symbol itself relative to GOT.  */
          if (h != NULL
          if (h != NULL
              /* See PLT32 handling.  */
              /* See PLT32 handling.  */
              && h->plt.offset != (bfd_vma) -1
              && h->plt.offset != (bfd_vma) -1
              && htab->splt != NULL)
              && htab->elf.splt != NULL)
            {
            {
              relocation = (htab->splt->output_section->vma
              relocation = (htab->elf.splt->output_section->vma
                            + htab->splt->output_offset
                            + htab->elf.splt->output_offset
                            + h->plt.offset);
                            + h->plt.offset);
              unresolved_reloc = FALSE;
              unresolved_reloc = FALSE;
            }
            }
 
 
          relocation -= htab->sgotplt->output_section->vma
          relocation -= htab->elf.sgotplt->output_section->vma
                        + htab->sgotplt->output_offset;
                        + htab->elf.sgotplt->output_offset;
          break;
          break;
 
 
        case R_X86_64_PLT32:
        case R_X86_64_PLT32:
          /* Relocation is to the entry for this symbol in the
          /* Relocation is to the entry for this symbol in the
             procedure linkage table.  */
             procedure linkage table.  */
Line 2575... Line 3027...
             without using the procedure linkage table.  */
             without using the procedure linkage table.  */
          if (h == NULL)
          if (h == NULL)
            break;
            break;
 
 
          if (h->plt.offset == (bfd_vma) -1
          if (h->plt.offset == (bfd_vma) -1
              || htab->splt == NULL)
              || htab->elf.splt == NULL)
            {
            {
              /* We didn't make a PLT entry for this symbol.  This
              /* We didn't make a PLT entry for this symbol.  This
                 happens when statically linking PIC code, or when
                 happens when statically linking PIC code, or when
                 using -Bsymbolic.  */
                 using -Bsymbolic.  */
              break;
              break;
            }
            }
 
 
          relocation = (htab->splt->output_section->vma
          relocation = (htab->elf.splt->output_section->vma
                        + htab->splt->output_offset
                        + htab->elf.splt->output_offset
                        + h->plt.offset);
                        + h->plt.offset);
          unresolved_reloc = FALSE;
          unresolved_reloc = FALSE;
          break;
          break;
 
 
        case R_X86_64_PC8:
        case R_X86_64_PC8:
        case R_X86_64_PC16:
        case R_X86_64_PC16:
        case R_X86_64_PC32:
        case R_X86_64_PC32:
          if (info->shared
          if (info->shared
              && !SYMBOL_REFERENCES_LOCAL (info, h)
 
              && (input_section->flags & SEC_ALLOC) != 0
              && (input_section->flags & SEC_ALLOC) != 0
              && (input_section->flags & SEC_READONLY) != 0
              && (input_section->flags & SEC_READONLY) != 0
              && (!h->def_regular
              && h != NULL)
                  || r_type != R_X86_64_PC32
 
                  || h->type != STT_FUNC
 
                  || ELF_ST_VISIBILITY (h->other) != STV_PROTECTED
 
                  || !is_32bit_relative_branch (contents,
 
                                                rel->r_offset)))
 
            {
            {
              if (h->def_regular
              bfd_boolean fail = FALSE;
                  && r_type == R_X86_64_PC32
              bfd_boolean branch
                  && h->type == STT_FUNC
                = (r_type == R_X86_64_PC32
                  && ELF_ST_VISIBILITY (h->other) == STV_PROTECTED)
                   && is_32bit_relative_branch (contents, rel->r_offset));
                (*_bfd_error_handler)
 
                   (_("%B: relocation R_X86_64_PC32 against protected function `%s' can not be used when making a shared object"),
              if (SYMBOL_REFERENCES_LOCAL (info, h))
                    input_bfd, h->root.root.string);
                {
 
                  /* Symbol is referenced locally.  Make sure it is
 
                     defined locally or for a branch.  */
 
                  fail = !h->def_regular && !branch;
 
                }
              else
              else
                (*_bfd_error_handler)
                {
                  (_("%B: relocation %s against `%s' can not be used when making a shared object; recompile with -fPIC"),
                  /* Symbol isn't referenced locally.  We only allow
                   input_bfd, x86_64_elf_howto_table[r_type].name,
                     branch to symbol with non-default visibility. */
                   h->root.root.string);
                  fail = (!branch
 
                          || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT);
 
                }
 
 
 
              if (fail)
 
                {
 
                  const char *fmt;
 
                  const char *v;
 
                  const char *pic = "";
 
 
 
                  switch (ELF_ST_VISIBILITY (h->other))
 
                    {
 
                    case STV_HIDDEN:
 
                      v = _("hidden symbol");
 
                      break;
 
                    case STV_INTERNAL:
 
                      v = _("internal symbol");
 
                      break;
 
                    case STV_PROTECTED:
 
                      v = _("protected symbol");
 
                      break;
 
                    default:
 
                      v = _("symbol");
 
                      pic = _("; recompile with -fPIC");
 
                      break;
 
                    }
 
 
 
                  if (h->def_regular)
 
                    fmt = _("%B: relocation %s against %s `%s' can not be used when making a shared object%s");
 
                  else
 
                    fmt = _("%B: relocation %s against undefined %s `%s' can not be used when making a shared object%s");
 
 
 
                  (*_bfd_error_handler) (fmt, input_bfd,
 
                                         x86_64_elf_howto_table[r_type].name,
 
                                         v,  h->root.root.string, pic);
              bfd_set_error (bfd_error_bad_value);
              bfd_set_error (bfd_error_bad_value);
              return FALSE;
              return FALSE;
            }
            }
 
            }
          /* Fall through.  */
          /* Fall through.  */
 
 
        case R_X86_64_8:
        case R_X86_64_8:
        case R_X86_64_16:
        case R_X86_64_16:
        case R_X86_64_32:
        case R_X86_64_32:
Line 2635... Line 3120...
 
 
          if ((info->shared
          if ((info->shared
               && (h == NULL
               && (h == NULL
                   || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
                   || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
                   || h->root.type != bfd_link_hash_undefweak)
                   || h->root.type != bfd_link_hash_undefweak)
               && ((r_type != R_X86_64_PC8
               && (! IS_X86_64_PCREL_TYPE (r_type)
                    && r_type != R_X86_64_PC16
 
                    && r_type != R_X86_64_PC32
 
                    && r_type != R_X86_64_PC64)
 
                   || !SYMBOL_CALLS_LOCAL (info, h)))
                   || !SYMBOL_CALLS_LOCAL (info, h)))
              || (ELIMINATE_COPY_RELOCS
              || (ELIMINATE_COPY_RELOCS
                  && !info->shared
                  && !info->shared
                  && h != NULL
                  && h != NULL
                  && h->dynindx != -1
                  && h->dynindx != -1
Line 2679... Line 3161...
 
 
              /* h->dynindx may be -1 if this symbol was marked to
              /* h->dynindx may be -1 if this symbol was marked to
                 become local.  */
                 become local.  */
              else if (h != NULL
              else if (h != NULL
                       && h->dynindx != -1
                       && h->dynindx != -1
                       && (r_type == R_X86_64_PC8
                       && (IS_X86_64_PCREL_TYPE (r_type)
                           || r_type == R_X86_64_PC16
 
                           || r_type == R_X86_64_PC32
 
                           || r_type == R_X86_64_PC64
 
                           || !info->shared
                           || !info->shared
                           || !SYMBOLIC_BIND (info, h)
                           || !SYMBOLIC_BIND (info, h)
                           || !h->def_regular))
                           || !h->def_regular))
                {
                {
                  outrel.r_info = ELF64_R_INFO (h->dynindx, r_type);
                  outrel.r_info = ELF64_R_INFO (h->dynindx, r_type);
Line 2735... Line 3214...
                      outrel.r_addend = relocation + rel->r_addend;
                      outrel.r_addend = relocation + rel->r_addend;
                    }
                    }
                }
                }
 
 
              sreloc = elf_section_data (input_section)->sreloc;
              sreloc = elf_section_data (input_section)->sreloc;
              if (sreloc == NULL)
 
                abort ();
              BFD_ASSERT (sreloc != NULL && sreloc->contents != NULL);
 
 
              loc = sreloc->contents;
              loc = sreloc->contents;
              loc += sreloc->reloc_count++ * sizeof (Elf64_External_Rela);
              loc += sreloc->reloc_count++ * sizeof (Elf64_External_Rela);
              bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc);
              bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc);
 
 
Line 2766... Line 3245...
 
 
          if (! elf64_x86_64_tls_transition (info, input_bfd,
          if (! elf64_x86_64_tls_transition (info, input_bfd,
                                             input_section, contents,
                                             input_section, contents,
                                             symtab_hdr, sym_hashes,
                                             symtab_hdr, sym_hashes,
                                             &r_type, tls_type, rel,
                                             &r_type, tls_type, rel,
                                             relend, h))
                                             relend, h, r_symndx))
            return FALSE;
            return FALSE;
 
 
          if (r_type == R_X86_64_TPOFF32)
          if (r_type == R_X86_64_TPOFF32)
            {
            {
              bfd_vma roff = rel->r_offset;
              bfd_vma roff = rel->r_offset;
Line 2786... Line 3265...
                     movq %fs:0, %rax
                     movq %fs:0, %rax
                     leaq foo@tpoff(%rax), %rax */
                     leaq foo@tpoff(%rax), %rax */
                  memcpy (contents + roff - 4,
                  memcpy (contents + roff - 4,
                          "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x8d\x80\0\0\0",
                          "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x8d\x80\0\0\0",
                          16);
                          16);
                  bfd_put_32 (output_bfd, tpoff (info, relocation),
                  bfd_put_32 (output_bfd,
 
                              elf64_x86_64_tpoff (info, relocation),
                              contents + roff + 8);
                              contents + roff + 8);
                  /* Skip R_X86_64_PC32/R_X86_64_PLT32.  */
                  /* Skip R_X86_64_PC32/R_X86_64_PLT32.  */
                  rel++;
                  rel++;
                  continue;
                  continue;
                }
                }
Line 2812... Line 3292...
                  bfd_put_8 (output_bfd, 0x48 | ((type >> 2) & 1),
                  bfd_put_8 (output_bfd, 0x48 | ((type >> 2) & 1),
                             contents + roff - 3);
                             contents + roff - 3);
                  bfd_put_8 (output_bfd, 0xc7, contents + roff - 2);
                  bfd_put_8 (output_bfd, 0xc7, contents + roff - 2);
                  bfd_put_8 (output_bfd, 0xc0 | ((val >> 3) & 7),
                  bfd_put_8 (output_bfd, 0xc0 | ((val >> 3) & 7),
                             contents + roff - 1);
                             contents + roff - 1);
                  bfd_put_32 (output_bfd, tpoff (info, relocation),
                  bfd_put_32 (output_bfd,
 
                              elf64_x86_64_tpoff (info, relocation),
                              contents + roff);
                              contents + roff);
                  continue;
                  continue;
                }
                }
              else if (ELF64_R_TYPE (rel->r_info) == R_X86_64_TLSDESC_CALL)
              else if (ELF64_R_TYPE (rel->r_info) == R_X86_64_TLSDESC_CALL)
                {
                {
Line 2878... Line 3359...
                      bfd_put_8 (output_bfd, 0x8d,
                      bfd_put_8 (output_bfd, 0x8d,
                                 contents + roff - 2);
                                 contents + roff - 2);
                      bfd_put_8 (output_bfd, 0x80 | reg | (reg << 3),
                      bfd_put_8 (output_bfd, 0x80 | reg | (reg << 3),
                                 contents + roff - 1);
                                 contents + roff - 1);
                    }
                    }
                  bfd_put_32 (output_bfd, tpoff (info, relocation),
                  bfd_put_32 (output_bfd,
 
                              elf64_x86_64_tpoff (info, relocation),
                              contents + roff);
                              contents + roff);
                  continue;
                  continue;
                }
                }
              else
              else
                BFD_ASSERT (FALSE);
                BFD_ASSERT (FALSE);
            }
            }
 
 
          if (htab->sgot == NULL)
          if (htab->elf.sgot == NULL)
            abort ();
            abort ();
 
 
          if (h != NULL)
          if (h != NULL)
            {
            {
              off = h->got.offset;
              off = h->got.offset;
Line 2912... Line 3394...
              Elf_Internal_Rela outrel;
              Elf_Internal_Rela outrel;
              bfd_byte *loc;
              bfd_byte *loc;
              int dr_type, indx;
              int dr_type, indx;
              asection *sreloc;
              asection *sreloc;
 
 
              if (htab->srelgot == NULL)
              if (htab->elf.srelgot == NULL)
                abort ();
                abort ();
 
 
              indx = h && h->dynindx != -1 ? h->dynindx : 0;
              indx = h && h->dynindx != -1 ? h->dynindx : 0;
 
 
              if (GOT_TLS_GDESC_P (tls_type))
              if (GOT_TLS_GDESC_P (tls_type))
                {
                {
                  outrel.r_info = ELF64_R_INFO (indx, R_X86_64_TLSDESC);
                  outrel.r_info = ELF64_R_INFO (indx, R_X86_64_TLSDESC);
                  BFD_ASSERT (htab->sgotplt_jump_table_size + offplt
                  BFD_ASSERT (htab->sgotplt_jump_table_size + offplt
                              + 2 * GOT_ENTRY_SIZE <= htab->sgotplt->size);
                              + 2 * GOT_ENTRY_SIZE <= htab->elf.sgotplt->size);
                  outrel.r_offset = (htab->sgotplt->output_section->vma
                  outrel.r_offset = (htab->elf.sgotplt->output_section->vma
                                     + htab->sgotplt->output_offset
                                     + htab->elf.sgotplt->output_offset
                                     + offplt
                                     + offplt
                                     + htab->sgotplt_jump_table_size);
                                     + htab->sgotplt_jump_table_size);
                  sreloc = htab->srelplt;
                  sreloc = htab->elf.srelplt;
                  loc = sreloc->contents;
                  loc = sreloc->contents;
                  loc += sreloc->reloc_count++
                  loc += sreloc->reloc_count++
                    * sizeof (Elf64_External_Rela);
                    * sizeof (Elf64_External_Rela);
                  BFD_ASSERT (loc + sizeof (Elf64_External_Rela)
                  BFD_ASSERT (loc + sizeof (Elf64_External_Rela)
                              <= sreloc->contents + sreloc->size);
                              <= sreloc->contents + sreloc->size);
                  if (indx == 0)
                  if (indx == 0)
                    outrel.r_addend = relocation - dtpoff_base (info);
                    outrel.r_addend = relocation - elf64_x86_64_dtpoff_base (info);
                  else
                  else
                    outrel.r_addend = 0;
                    outrel.r_addend = 0;
                  bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc);
                  bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc);
                }
                }
 
 
              sreloc = htab->srelgot;
              sreloc = htab->elf.srelgot;
 
 
              outrel.r_offset = (htab->sgot->output_section->vma
              outrel.r_offset = (htab->elf.sgot->output_section->vma
                                 + htab->sgot->output_offset + off);
                                 + htab->elf.sgot->output_offset + off);
 
 
              if (GOT_TLS_GD_P (tls_type))
              if (GOT_TLS_GD_P (tls_type))
                dr_type = R_X86_64_DTPMOD64;
                dr_type = R_X86_64_DTPMOD64;
              else if (GOT_TLS_GDESC_P (tls_type))
              else if (GOT_TLS_GDESC_P (tls_type))
                goto dr_done;
                goto dr_done;
              else
              else
                dr_type = R_X86_64_TPOFF64;
                dr_type = R_X86_64_TPOFF64;
 
 
              bfd_put_64 (output_bfd, 0, htab->sgot->contents + off);
              bfd_put_64 (output_bfd, 0, htab->elf.sgot->contents + off);
              outrel.r_addend = 0;
              outrel.r_addend = 0;
              if ((dr_type == R_X86_64_TPOFF64
              if ((dr_type == R_X86_64_TPOFF64
                   || dr_type == R_X86_64_TLSDESC) && indx == 0)
                   || dr_type == R_X86_64_TLSDESC) && indx == 0)
                outrel.r_addend = relocation - dtpoff_base (info);
                outrel.r_addend = relocation - elf64_x86_64_dtpoff_base (info);
              outrel.r_info = ELF64_R_INFO (indx, dr_type);
              outrel.r_info = ELF64_R_INFO (indx, dr_type);
 
 
              loc = sreloc->contents;
              loc = sreloc->contents;
              loc += sreloc->reloc_count++ * sizeof (Elf64_External_Rela);
              loc += sreloc->reloc_count++ * sizeof (Elf64_External_Rela);
              BFD_ASSERT (loc + sizeof (Elf64_External_Rela)
              BFD_ASSERT (loc + sizeof (Elf64_External_Rela)
Line 2970... Line 3452...
                {
                {
                  if (indx == 0)
                  if (indx == 0)
                    {
                    {
                      BFD_ASSERT (! unresolved_reloc);
                      BFD_ASSERT (! unresolved_reloc);
                      bfd_put_64 (output_bfd,
                      bfd_put_64 (output_bfd,
                                  relocation - dtpoff_base (info),
                                  relocation - elf64_x86_64_dtpoff_base (info),
                                  htab->sgot->contents + off + GOT_ENTRY_SIZE);
                                  htab->elf.sgot->contents + off + GOT_ENTRY_SIZE);
                    }
                    }
                  else
                  else
                    {
                    {
                      bfd_put_64 (output_bfd, 0,
                      bfd_put_64 (output_bfd, 0,
                                  htab->sgot->contents + off + GOT_ENTRY_SIZE);
                                  htab->elf.sgot->contents + off + GOT_ENTRY_SIZE);
                      outrel.r_info = ELF64_R_INFO (indx,
                      outrel.r_info = ELF64_R_INFO (indx,
                                                    R_X86_64_DTPOFF64);
                                                    R_X86_64_DTPOFF64);
                      outrel.r_offset += GOT_ENTRY_SIZE;
                      outrel.r_offset += GOT_ENTRY_SIZE;
                      sreloc->reloc_count++;
                      sreloc->reloc_count++;
                      loc += sizeof (Elf64_External_Rela);
                      loc += sizeof (Elf64_External_Rela);
Line 3002... Line 3484...
            abort ();
            abort ();
          if (r_type == ELF64_R_TYPE (rel->r_info))
          if (r_type == ELF64_R_TYPE (rel->r_info))
            {
            {
              if (r_type == R_X86_64_GOTPC32_TLSDESC
              if (r_type == R_X86_64_GOTPC32_TLSDESC
                  || r_type == R_X86_64_TLSDESC_CALL)
                  || r_type == R_X86_64_TLSDESC_CALL)
                relocation = htab->sgotplt->output_section->vma
                relocation = htab->elf.sgotplt->output_section->vma
                  + htab->sgotplt->output_offset
                  + htab->elf.sgotplt->output_offset
                  + offplt + htab->sgotplt_jump_table_size;
                  + offplt + htab->sgotplt_jump_table_size;
              else
              else
                relocation = htab->sgot->output_section->vma
                relocation = htab->elf.sgot->output_section->vma
                  + htab->sgot->output_offset + off;
                  + htab->elf.sgot->output_offset + off;
              unresolved_reloc = FALSE;
              unresolved_reloc = FALSE;
            }
            }
          else
          else
            {
            {
              bfd_vma roff = rel->r_offset;
              bfd_vma roff = rel->r_offset;
Line 3026... Line 3508...
                     addq foo@gottpoff(%rip), %rax */
                     addq foo@gottpoff(%rip), %rax */
                  memcpy (contents + roff - 4,
                  memcpy (contents + roff - 4,
                          "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x03\x05\0\0\0",
                          "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x03\x05\0\0\0",
                          16);
                          16);
 
 
                  relocation = (htab->sgot->output_section->vma
                  relocation = (htab->elf.sgot->output_section->vma
                                + htab->sgot->output_offset + off
                                + htab->elf.sgot->output_offset + off
                                - roff
                                - roff
                                - input_section->output_section->vma
                                - input_section->output_section->vma
                                - input_section->output_offset
                                - input_section->output_offset
                                - 12);
                                - 12);
                  bfd_put_32 (output_bfd, relocation,
                  bfd_put_32 (output_bfd, relocation,
Line 3061... Line 3543...
                     suffices to change the second byte from 0x8d to
                     suffices to change the second byte from 0x8d to
                     0x8b.  */
                     0x8b.  */
                  bfd_put_8 (output_bfd, 0x8b, contents + roff - 2);
                  bfd_put_8 (output_bfd, 0x8b, contents + roff - 2);
 
 
                  bfd_put_32 (output_bfd,
                  bfd_put_32 (output_bfd,
                              htab->sgot->output_section->vma
                              htab->elf.sgot->output_section->vma
                              + htab->sgot->output_offset + off
                              + htab->elf.sgot->output_offset + off
                              - rel->r_offset
                              - rel->r_offset
                              - input_section->output_section->vma
                              - input_section->output_section->vma
                              - input_section->output_offset
                              - input_section->output_offset
                              - 4,
                              - 4,
                              contents + roff);
                              contents + roff);
Line 3097... Line 3579...
        case R_X86_64_TLSLD:
        case R_X86_64_TLSLD:
          if (! elf64_x86_64_tls_transition (info, input_bfd,
          if (! elf64_x86_64_tls_transition (info, input_bfd,
                                             input_section, contents,
                                             input_section, contents,
                                             symtab_hdr, sym_hashes,
                                             symtab_hdr, sym_hashes,
                                             &r_type, GOT_UNKNOWN,
                                             &r_type, GOT_UNKNOWN,
                                             rel, relend, h))
                                             rel, relend, h, r_symndx))
            return FALSE;
            return FALSE;
 
 
          if (r_type != R_X86_64_TLSLD)
          if (r_type != R_X86_64_TLSLD)
            {
            {
              /* LD->LE transition:
              /* LD->LE transition:
Line 3115... Line 3597...
              /* Skip R_X86_64_PC32/R_X86_64_PLT32.  */
              /* Skip R_X86_64_PC32/R_X86_64_PLT32.  */
              rel++;
              rel++;
              continue;
              continue;
            }
            }
 
 
          if (htab->sgot == NULL)
          if (htab->elf.sgot == NULL)
            abort ();
            abort ();
 
 
          off = htab->tls_ld_got.offset;
          off = htab->tls_ld_got.offset;
          if (off & 1)
          if (off & 1)
            off &= ~1;
            off &= ~1;
          else
          else
            {
            {
              Elf_Internal_Rela outrel;
              Elf_Internal_Rela outrel;
              bfd_byte *loc;
              bfd_byte *loc;
 
 
              if (htab->srelgot == NULL)
              if (htab->elf.srelgot == NULL)
                abort ();
                abort ();
 
 
              outrel.r_offset = (htab->sgot->output_section->vma
              outrel.r_offset = (htab->elf.sgot->output_section->vma
                                 + htab->sgot->output_offset + off);
                                 + htab->elf.sgot->output_offset + off);
 
 
              bfd_put_64 (output_bfd, 0,
              bfd_put_64 (output_bfd, 0,
                          htab->sgot->contents + off);
                          htab->elf.sgot->contents + off);
              bfd_put_64 (output_bfd, 0,
              bfd_put_64 (output_bfd, 0,
                          htab->sgot->contents + off + GOT_ENTRY_SIZE);
                          htab->elf.sgot->contents + off + GOT_ENTRY_SIZE);
              outrel.r_info = ELF64_R_INFO (0, R_X86_64_DTPMOD64);
              outrel.r_info = ELF64_R_INFO (0, R_X86_64_DTPMOD64);
              outrel.r_addend = 0;
              outrel.r_addend = 0;
              loc = htab->srelgot->contents;
              loc = htab->elf.srelgot->contents;
              loc += htab->srelgot->reloc_count++ * sizeof (Elf64_External_Rela);
              loc += htab->elf.srelgot->reloc_count++ * sizeof (Elf64_External_Rela);
              bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc);
              bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc);
              htab->tls_ld_got.offset |= 1;
              htab->tls_ld_got.offset |= 1;
            }
            }
          relocation = htab->sgot->output_section->vma
          relocation = htab->elf.sgot->output_section->vma
                       + htab->sgot->output_offset + off;
                       + htab->elf.sgot->output_offset + off;
          unresolved_reloc = FALSE;
          unresolved_reloc = FALSE;
          break;
          break;
 
 
        case R_X86_64_DTPOFF32:
        case R_X86_64_DTPOFF32:
          if (info->shared || (input_section->flags & SEC_CODE) == 0)
          if (!info->executable|| (input_section->flags & SEC_CODE) == 0)
            relocation -= dtpoff_base (info);
            relocation -= elf64_x86_64_dtpoff_base (info);
          else
          else
            relocation = tpoff (info, relocation);
            relocation = elf64_x86_64_tpoff (info, relocation);
          break;
          break;
 
 
        case R_X86_64_TPOFF32:
        case R_X86_64_TPOFF32:
          BFD_ASSERT (! info->shared);
          BFD_ASSERT (info->executable);
          relocation = tpoff (info, relocation);
          relocation = elf64_x86_64_tpoff (info, relocation);
          break;
          break;
 
 
        default:
        default:
          break;
          break;
        }
        }
Line 3178... Line 3660...
           input_section,
           input_section,
           (long) rel->r_offset,
           (long) rel->r_offset,
           howto->name,
           howto->name,
           h->root.root.string);
           h->root.root.string);
 
 
 
do_relocation:
      r = _bfd_final_link_relocate (howto, input_bfd, input_section,
      r = _bfd_final_link_relocate (howto, input_bfd, input_section,
                                    contents, rel->r_offset,
                                    contents, rel->r_offset,
                                    relocation, rel->r_addend);
                                    relocation, rel->r_addend);
 
 
      if (r != bfd_reloc_ok)
      if (r != bfd_reloc_ok)
Line 3240... Line 3723...
    {
    {
      bfd_vma plt_index;
      bfd_vma plt_index;
      bfd_vma got_offset;
      bfd_vma got_offset;
      Elf_Internal_Rela rela;
      Elf_Internal_Rela rela;
      bfd_byte *loc;
      bfd_byte *loc;
 
      asection *plt, *gotplt, *relplt;
 
 
 
      /* When building a static executable, use .iplt, .igot.plt and
 
         .rela.iplt sections for STT_GNU_IFUNC symbols.  */
 
      if (htab->elf.splt != NULL)
 
        {
 
          plt = htab->elf.splt;
 
          gotplt = htab->elf.sgotplt;
 
          relplt = htab->elf.srelplt;
 
        }
 
      else
 
        {
 
          plt = htab->elf.iplt;
 
          gotplt = htab->elf.igotplt;
 
          relplt = htab->elf.irelplt;
 
        }
 
 
      /* This symbol has an entry in the procedure linkage table.  Set
      /* This symbol has an entry in the procedure linkage table.  Set
         it up.  */
         it up.  */
      if (h->dynindx == -1
      if ((h->dynindx == -1
          || htab->splt == NULL
           && !((h->forced_local || info->executable)
          || htab->sgotplt == NULL
                && h->def_regular
          || htab->srelplt == NULL)
                && h->type == STT_GNU_IFUNC))
 
          || plt == NULL
 
          || gotplt == NULL
 
          || relplt == NULL)
        abort ();
        abort ();
 
 
      /* Get the index in the procedure linkage table which
      /* Get the index in the procedure linkage table which
         corresponds to this symbol.  This is the index of this symbol
         corresponds to this symbol.  This is the index of this symbol
         in all the symbols for which we are making plt entries.  The
         in all the symbols for which we are making plt entries.  The
         first entry in the procedure linkage table is reserved.  */
         first entry in the procedure linkage table is reserved.
      plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1;
 
 
 
      /* Get the offset into the .got table of the entry that
         Get the offset into the .got table of the entry that
         corresponds to this function.  Each .got entry is GOT_ENTRY_SIZE
         corresponds to this function.  Each .got entry is GOT_ENTRY_SIZE
         bytes. The first three are reserved for the dynamic linker.  */
         bytes. The first three are reserved for the dynamic linker.
 
 
 
         For static executables, we don't reserve anything.  */
 
 
 
      if (plt == htab->elf.splt)
 
        {
 
          plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1;
      got_offset = (plt_index + 3) * GOT_ENTRY_SIZE;
      got_offset = (plt_index + 3) * GOT_ENTRY_SIZE;
 
        }
 
      else
 
        {
 
          plt_index = h->plt.offset / PLT_ENTRY_SIZE;
 
          got_offset = plt_index * GOT_ENTRY_SIZE;
 
        }
 
 
      /* Fill in the entry in the procedure linkage table.  */
      /* Fill in the entry in the procedure linkage table.  */
      memcpy (htab->splt->contents + h->plt.offset, elf64_x86_64_plt_entry,
      memcpy (plt->contents + h->plt.offset, elf64_x86_64_plt_entry,
              PLT_ENTRY_SIZE);
              PLT_ENTRY_SIZE);
 
 
      /* Insert the relocation positions of the plt section.  The magic
      /* Insert the relocation positions of the plt section.  The magic
         numbers at the end of the statements are the positions of the
         numbers at the end of the statements are the positions of the
         relocations in the plt section.  */
         relocations in the plt section.  */
      /* Put offset for jmp *name@GOTPCREL(%rip), since the
      /* Put offset for jmp *name@GOTPCREL(%rip), since the
         instruction uses 6 bytes, subtract this value.  */
         instruction uses 6 bytes, subtract this value.  */
      bfd_put_32 (output_bfd,
      bfd_put_32 (output_bfd,
                      (htab->sgotplt->output_section->vma
                      (gotplt->output_section->vma
                       + htab->sgotplt->output_offset
                       + gotplt->output_offset
                       + got_offset
                       + got_offset
                       - htab->splt->output_section->vma
                       - plt->output_section->vma
                       - htab->splt->output_offset
                       - plt->output_offset
                       - h->plt.offset
                       - h->plt.offset
                       - 6),
                       - 6),
                  htab->splt->contents + h->plt.offset + 2);
                  plt->contents + h->plt.offset + 2);
 
 
 
      /* Don't fill PLT entry for static executables.  */
 
      if (plt == htab->elf.splt)
 
        {
      /* Put relocation index.  */
      /* Put relocation index.  */
      bfd_put_32 (output_bfd, plt_index,
      bfd_put_32 (output_bfd, plt_index,
                  htab->splt->contents + h->plt.offset + 7);
                      plt->contents + h->plt.offset + 7);
      /* Put offset for jmp .PLT0.  */
      /* Put offset for jmp .PLT0.  */
      bfd_put_32 (output_bfd, - (h->plt.offset + PLT_ENTRY_SIZE),
      bfd_put_32 (output_bfd, - (h->plt.offset + PLT_ENTRY_SIZE),
                  htab->splt->contents + h->plt.offset + 12);
                      plt->contents + h->plt.offset + 12);
 
        }
 
 
      /* Fill in the entry in the global offset table, initially this
      /* Fill in the entry in the global offset table, initially this
         points to the pushq instruction in the PLT which is at offset 6.  */
         points to the pushq instruction in the PLT which is at offset 6.  */
      bfd_put_64 (output_bfd, (htab->splt->output_section->vma
      bfd_put_64 (output_bfd, (plt->output_section->vma
                               + htab->splt->output_offset
                               + plt->output_offset
                               + h->plt.offset + 6),
                               + h->plt.offset + 6),
                  htab->sgotplt->contents + got_offset);
                  gotplt->contents + got_offset);
 
 
      /* Fill in the entry in the .rela.plt section.  */
      /* Fill in the entry in the .rela.plt section.  */
      rela.r_offset = (htab->sgotplt->output_section->vma
      rela.r_offset = (gotplt->output_section->vma
                       + htab->sgotplt->output_offset
                       + gotplt->output_offset
                       + got_offset);
                       + got_offset);
 
      if (h->dynindx == -1
 
          || ((info->executable
 
               || ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
 
              && h->def_regular
 
              && h->type == STT_GNU_IFUNC))
 
        {
 
          /* If an STT_GNU_IFUNC symbol is locally defined, generate
 
             R_X86_64_IRELATIVE instead of R_X86_64_JUMP_SLOT.  */
 
          rela.r_info = ELF64_R_INFO (0, R_X86_64_IRELATIVE);
 
          rela.r_addend = (h->root.u.def.value
 
                           + h->root.u.def.section->output_section->vma
 
                           + h->root.u.def.section->output_offset);
 
        }
 
      else
 
        {
      rela.r_info = ELF64_R_INFO (h->dynindx, R_X86_64_JUMP_SLOT);
      rela.r_info = ELF64_R_INFO (h->dynindx, R_X86_64_JUMP_SLOT);
      rela.r_addend = 0;
      rela.r_addend = 0;
      loc = htab->srelplt->contents + plt_index * sizeof (Elf64_External_Rela);
        }
 
      loc = relplt->contents + plt_index * sizeof (Elf64_External_Rela);
      bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
      bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
 
 
      if (!h->def_regular)
      if (!h->def_regular)
        {
        {
          /* Mark the symbol as undefined, rather than as defined in
          /* Mark the symbol as undefined, rather than as defined in
Line 3326... Line 3860...
      Elf_Internal_Rela rela;
      Elf_Internal_Rela rela;
      bfd_byte *loc;
      bfd_byte *loc;
 
 
      /* This symbol has an entry in the global offset table.  Set it
      /* This symbol has an entry in the global offset table.  Set it
         up.  */
         up.  */
      if (htab->sgot == NULL || htab->srelgot == NULL)
      if (htab->elf.sgot == NULL || htab->elf.srelgot == NULL)
        abort ();
        abort ();
 
 
      rela.r_offset = (htab->sgot->output_section->vma
      rela.r_offset = (htab->elf.sgot->output_section->vma
                       + htab->sgot->output_offset
                       + htab->elf.sgot->output_offset
                       + (h->got.offset &~ (bfd_vma) 1));
                       + (h->got.offset &~ (bfd_vma) 1));
 
 
      /* If this is a static link, or it is a -Bsymbolic link and the
      /* If this is a static link, or it is a -Bsymbolic link and the
         symbol is defined locally or was forced to be local because
         symbol is defined locally or was forced to be local because
         of a version file, we just want to emit a RELATIVE reloc.
         of a version file, we just want to emit a RELATIVE reloc.
         The entry in the global offset table will already have been
         The entry in the global offset table will already have been
         initialized in the relocate_section function.  */
         initialized in the relocate_section function.  */
      if (info->shared
      if (h->def_regular
 
          && h->type == STT_GNU_IFUNC)
 
        {
 
          if (info->shared)
 
            {
 
              /* Generate R_X86_64_GLOB_DAT.  */
 
              goto do_glob_dat;
 
            }
 
          else
 
            {
 
              asection *plt;
 
 
 
              if (!h->pointer_equality_needed)
 
                abort ();
 
 
 
              /* For non-shared object, we can't use .got.plt, which
 
                 contains the real function addres if we need pointer
 
                 equality.  We load the GOT entry with the PLT entry.  */
 
              plt = htab->elf.splt ? htab->elf.splt : htab->elf.iplt;
 
              bfd_put_64 (output_bfd, (plt->output_section->vma
 
                                       + plt->output_offset
 
                                       + h->plt.offset),
 
                          htab->elf.sgot->contents + h->got.offset);
 
              return TRUE;
 
            }
 
        }
 
      else if (info->shared
          && SYMBOL_REFERENCES_LOCAL (info, h))
          && SYMBOL_REFERENCES_LOCAL (info, h))
        {
        {
 
          if (!h->def_regular)
 
            return FALSE;
          BFD_ASSERT((h->got.offset & 1) != 0);
          BFD_ASSERT((h->got.offset & 1) != 0);
          rela.r_info = ELF64_R_INFO (0, R_X86_64_RELATIVE);
          rela.r_info = ELF64_R_INFO (0, R_X86_64_RELATIVE);
          rela.r_addend = (h->root.u.def.value
          rela.r_addend = (h->root.u.def.value
                           + h->root.u.def.section->output_section->vma
                           + h->root.u.def.section->output_section->vma
                           + h->root.u.def.section->output_offset);
                           + h->root.u.def.section->output_offset);
        }
        }
      else
      else
        {
        {
          BFD_ASSERT((h->got.offset & 1) == 0);
          BFD_ASSERT((h->got.offset & 1) == 0);
 
do_glob_dat:
          bfd_put_64 (output_bfd, (bfd_vma) 0,
          bfd_put_64 (output_bfd, (bfd_vma) 0,
                      htab->sgot->contents + h->got.offset);
                      htab->elf.sgot->contents + h->got.offset);
          rela.r_info = ELF64_R_INFO (h->dynindx, R_X86_64_GLOB_DAT);
          rela.r_info = ELF64_R_INFO (h->dynindx, R_X86_64_GLOB_DAT);
          rela.r_addend = 0;
          rela.r_addend = 0;
        }
        }
 
 
      loc = htab->srelgot->contents;
      loc = htab->elf.srelgot->contents;
      loc += htab->srelgot->reloc_count++ * sizeof (Elf64_External_Rela);
      loc += htab->elf.srelgot->reloc_count++ * sizeof (Elf64_External_Rela);
      bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
      bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
    }
    }
 
 
  if (h->needs_copy)
  if (h->needs_copy)
    {
    {
Line 3384... Line 3947...
      loc = htab->srelbss->contents;
      loc = htab->srelbss->contents;
      loc += htab->srelbss->reloc_count++ * sizeof (Elf64_External_Rela);
      loc += htab->srelbss->reloc_count++ * sizeof (Elf64_External_Rela);
      bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
      bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
    }
    }
 
 
  /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute.  */
  /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute.  SYM may
  if (strcmp (h->root.root.string, "_DYNAMIC") == 0
     be NULL for local symbols.  */
      || h == htab->elf.hgot)
  if (sym != NULL
 
      && (strcmp (h->root.root.string, "_DYNAMIC") == 0
 
          || h == htab->elf.hgot))
    sym->st_shndx = SHN_ABS;
    sym->st_shndx = SHN_ABS;
 
 
  return TRUE;
  return TRUE;
}
}
 
 
 
/* Finish up local dynamic symbol handling.  We set the contents of
 
   various dynamic sections here.  */
 
 
 
static bfd_boolean
 
elf64_x86_64_finish_local_dynamic_symbol (void **slot, void *inf)
 
{
 
  struct elf_link_hash_entry *h
 
    = (struct elf_link_hash_entry *) *slot;
 
  struct bfd_link_info *info
 
    = (struct bfd_link_info *) inf;
 
 
 
  return elf64_x86_64_finish_dynamic_symbol (info->output_bfd,
 
                                             info, h, NULL);
 
}
 
 
/* Used to decide how to sort relocs in an optimal manner for the
/* Used to decide how to sort relocs in an optimal manner for the
   dynamic linker, before writing them out.  */
   dynamic linker, before writing them out.  */
 
 
static enum elf_reloc_type_class
static enum elf_reloc_type_class
elf64_x86_64_reloc_type_class (const Elf_Internal_Rela *rela)
elf64_x86_64_reloc_type_class (const Elf_Internal_Rela *rela)
Line 3428... Line 4008...
 
 
  if (htab->elf.dynamic_sections_created)
  if (htab->elf.dynamic_sections_created)
    {
    {
      Elf64_External_Dyn *dyncon, *dynconend;
      Elf64_External_Dyn *dyncon, *dynconend;
 
 
      if (sdyn == NULL || htab->sgot == NULL)
      if (sdyn == NULL || htab->elf.sgot == NULL)
        abort ();
        abort ();
 
 
      dyncon = (Elf64_External_Dyn *) sdyn->contents;
      dyncon = (Elf64_External_Dyn *) sdyn->contents;
      dynconend = (Elf64_External_Dyn *) (sdyn->contents + sdyn->size);
      dynconend = (Elf64_External_Dyn *) (sdyn->contents + sdyn->size);
      for (; dyncon < dynconend; dyncon++)
      for (; dyncon < dynconend; dyncon++)
Line 3446... Line 4026...
            {
            {
            default:
            default:
              continue;
              continue;
 
 
            case DT_PLTGOT:
            case DT_PLTGOT:
              s = htab->sgotplt;
              s = htab->elf.sgotplt;
              dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
              dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
              break;
              break;
 
 
            case DT_JMPREL:
            case DT_JMPREL:
              dyn.d_un.d_ptr = htab->srelplt->output_section->vma;
              dyn.d_un.d_ptr = htab->elf.srelplt->output_section->vma;
              break;
              break;
 
 
            case DT_PLTRELSZ:
            case DT_PLTRELSZ:
              s = htab->srelplt->output_section;
              s = htab->elf.srelplt->output_section;
              dyn.d_un.d_val = s->size;
              dyn.d_un.d_val = s->size;
              break;
              break;
 
 
            case DT_RELASZ:
            case DT_RELASZ:
              /* The procedure linkage table relocs (DT_JMPREL) should
              /* The procedure linkage table relocs (DT_JMPREL) should
Line 3467... Line 4047...
                 Therefore, we override the DT_RELASZ entry here to
                 Therefore, we override the DT_RELASZ entry here to
                 make it not include the JMPREL relocs.  Since the
                 make it not include the JMPREL relocs.  Since the
                 linker script arranges for .rela.plt to follow all
                 linker script arranges for .rela.plt to follow all
                 other relocation sections, we don't have to worry
                 other relocation sections, we don't have to worry
                 about changing the DT_RELA entry.  */
                 about changing the DT_RELA entry.  */
              if (htab->srelplt != NULL)
              if (htab->elf.srelplt != NULL)
                {
                {
                  s = htab->srelplt->output_section;
                  s = htab->elf.srelplt->output_section;
                  dyn.d_un.d_val -= s->size;
                  dyn.d_un.d_val -= s->size;
                }
                }
              break;
              break;
 
 
            case DT_TLSDESC_PLT:
            case DT_TLSDESC_PLT:
              s = htab->splt;
              s = htab->elf.splt;
              dyn.d_un.d_ptr = s->output_section->vma + s->output_offset
              dyn.d_un.d_ptr = s->output_section->vma + s->output_offset
                + htab->tlsdesc_plt;
                + htab->tlsdesc_plt;
              break;
              break;
 
 
            case DT_TLSDESC_GOT:
            case DT_TLSDESC_GOT:
              s = htab->sgot;
              s = htab->elf.sgot;
              dyn.d_un.d_ptr = s->output_section->vma + s->output_offset
              dyn.d_un.d_ptr = s->output_section->vma + s->output_offset
                + htab->tlsdesc_got;
                + htab->tlsdesc_got;
              break;
              break;
            }
            }
 
 
          bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon);
          bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon);
        }
        }
 
 
      /* Fill in the special first entry in the procedure linkage table.  */
      /* Fill in the special first entry in the procedure linkage table.  */
      if (htab->splt && htab->splt->size > 0)
      if (htab->elf.splt && htab->elf.splt->size > 0)
        {
        {
          /* Fill in the first entry in the procedure linkage table.  */
          /* Fill in the first entry in the procedure linkage table.  */
          memcpy (htab->splt->contents, elf64_x86_64_plt0_entry,
          memcpy (htab->elf.splt->contents, elf64_x86_64_plt0_entry,
                  PLT_ENTRY_SIZE);
                  PLT_ENTRY_SIZE);
          /* Add offset for pushq GOT+8(%rip), since the instruction
          /* Add offset for pushq GOT+8(%rip), since the instruction
             uses 6 bytes subtract this value.  */
             uses 6 bytes subtract this value.  */
          bfd_put_32 (output_bfd,
          bfd_put_32 (output_bfd,
                      (htab->sgotplt->output_section->vma
                      (htab->elf.sgotplt->output_section->vma
                       + htab->sgotplt->output_offset
                       + htab->elf.sgotplt->output_offset
                       + 8
                       + 8
                       - htab->splt->output_section->vma
                       - htab->elf.splt->output_section->vma
                       - htab->splt->output_offset
                       - htab->elf.splt->output_offset
                       - 6),
                       - 6),
                      htab->splt->contents + 2);
                      htab->elf.splt->contents + 2);
          /* Add offset for jmp *GOT+16(%rip). The 12 is the offset to
          /* Add offset for jmp *GOT+16(%rip). The 12 is the offset to
             the end of the instruction.  */
             the end of the instruction.  */
          bfd_put_32 (output_bfd,
          bfd_put_32 (output_bfd,
                      (htab->sgotplt->output_section->vma
                      (htab->elf.sgotplt->output_section->vma
                       + htab->sgotplt->output_offset
                       + htab->elf.sgotplt->output_offset
                       + 16
                       + 16
                       - htab->splt->output_section->vma
                       - htab->elf.splt->output_section->vma
                       - htab->splt->output_offset
                       - htab->elf.splt->output_offset
                       - 12),
                       - 12),
                      htab->splt->contents + 8);
                      htab->elf.splt->contents + 8);
 
 
          elf_section_data (htab->splt->output_section)->this_hdr.sh_entsize =
          elf_section_data (htab->elf.splt->output_section)->this_hdr.sh_entsize =
            PLT_ENTRY_SIZE;
            PLT_ENTRY_SIZE;
 
 
          if (htab->tlsdesc_plt)
          if (htab->tlsdesc_plt)
            {
            {
              bfd_put_64 (output_bfd, (bfd_vma) 0,
              bfd_put_64 (output_bfd, (bfd_vma) 0,
                          htab->sgot->contents + htab->tlsdesc_got);
                          htab->elf.sgot->contents + htab->tlsdesc_got);
 
 
              memcpy (htab->splt->contents + htab->tlsdesc_plt,
              memcpy (htab->elf.splt->contents + htab->tlsdesc_plt,
                      elf64_x86_64_plt0_entry,
                      elf64_x86_64_plt0_entry,
                      PLT_ENTRY_SIZE);
                      PLT_ENTRY_SIZE);
 
 
              /* Add offset for pushq GOT+8(%rip), since the
              /* Add offset for pushq GOT+8(%rip), since the
                 instruction uses 6 bytes subtract this value.  */
                 instruction uses 6 bytes subtract this value.  */
              bfd_put_32 (output_bfd,
              bfd_put_32 (output_bfd,
                          (htab->sgotplt->output_section->vma
                          (htab->elf.sgotplt->output_section->vma
                           + htab->sgotplt->output_offset
                           + htab->elf.sgotplt->output_offset
                           + 8
                           + 8
                           - htab->splt->output_section->vma
                           - htab->elf.splt->output_section->vma
                           - htab->splt->output_offset
                           - htab->elf.splt->output_offset
                           - htab->tlsdesc_plt
                           - htab->tlsdesc_plt
                           - 6),
                           - 6),
                          htab->splt->contents + htab->tlsdesc_plt + 2);
                          htab->elf.splt->contents + htab->tlsdesc_plt + 2);
              /* Add offset for jmp *GOT+TDG(%rip), where TGD stands for
              /* Add offset for jmp *GOT+TDG(%rip), where TGD stands for
                 htab->tlsdesc_got. The 12 is the offset to the end of
                 htab->tlsdesc_got. The 12 is the offset to the end of
                 the instruction.  */
                 the instruction.  */
              bfd_put_32 (output_bfd,
              bfd_put_32 (output_bfd,
                          (htab->sgot->output_section->vma
                          (htab->elf.sgot->output_section->vma
                           + htab->sgot->output_offset
                           + htab->elf.sgot->output_offset
                           + htab->tlsdesc_got
                           + htab->tlsdesc_got
                           - htab->splt->output_section->vma
                           - htab->elf.splt->output_section->vma
                           - htab->splt->output_offset
                           - htab->elf.splt->output_offset
                           - htab->tlsdesc_plt
                           - htab->tlsdesc_plt
                           - 12),
                           - 12),
                          htab->splt->contents + htab->tlsdesc_plt + 8);
                          htab->elf.splt->contents + htab->tlsdesc_plt + 8);
            }
            }
        }
        }
    }
    }
 
 
  if (htab->sgotplt)
  if (htab->elf.sgotplt)
    {
    {
      /* Fill in the first three entries in the global offset table.  */
      /* Fill in the first three entries in the global offset table.  */
      if (htab->sgotplt->size > 0)
      if (htab->elf.sgotplt->size > 0)
        {
        {
          /* Set the first entry in the global offset table to the address of
          /* Set the first entry in the global offset table to the address of
             the dynamic section.  */
             the dynamic section.  */
          if (sdyn == NULL)
          if (sdyn == NULL)
            bfd_put_64 (output_bfd, (bfd_vma) 0, htab->sgotplt->contents);
            bfd_put_64 (output_bfd, (bfd_vma) 0, htab->elf.sgotplt->contents);
          else
          else
            bfd_put_64 (output_bfd,
            bfd_put_64 (output_bfd,
                        sdyn->output_section->vma + sdyn->output_offset,
                        sdyn->output_section->vma + sdyn->output_offset,
                        htab->sgotplt->contents);
                        htab->elf.sgotplt->contents);
          /* Write GOT[1] and GOT[2], needed for the dynamic linker.  */
          /* Write GOT[1] and GOT[2], needed for the dynamic linker.  */
          bfd_put_64 (output_bfd, (bfd_vma) 0, htab->sgotplt->contents + GOT_ENTRY_SIZE);
          bfd_put_64 (output_bfd, (bfd_vma) 0, htab->elf.sgotplt->contents + GOT_ENTRY_SIZE);
          bfd_put_64 (output_bfd, (bfd_vma) 0, htab->sgotplt->contents + GOT_ENTRY_SIZE*2);
          bfd_put_64 (output_bfd, (bfd_vma) 0, htab->elf.sgotplt->contents + GOT_ENTRY_SIZE*2);
        }
        }
 
 
      elf_section_data (htab->sgotplt->output_section)->this_hdr.sh_entsize =
      elf_section_data (htab->elf.sgotplt->output_section)->this_hdr.sh_entsize =
        GOT_ENTRY_SIZE;
        GOT_ENTRY_SIZE;
    }
    }
 
 
  if (htab->sgot && htab->sgot->size > 0)
  if (htab->elf.sgot && htab->elf.sgot->size > 0)
    elf_section_data (htab->sgot->output_section)->this_hdr.sh_entsize
    elf_section_data (htab->elf.sgot->output_section)->this_hdr.sh_entsize
      = GOT_ENTRY_SIZE;
      = GOT_ENTRY_SIZE;
 
 
 
  /* Fill PLT and GOT entries for local STT_GNU_IFUNC symbols.  */
 
  htab_traverse (htab->loc_hash_table,
 
                 elf64_x86_64_finish_local_dynamic_symbol,
 
                 info);
 
 
  return TRUE;
  return TRUE;
}
}
 
 
/* Return address for Ith PLT stub in section PLT, for relocation REL
/* Return address for Ith PLT stub in section PLT, for relocation REL
   or (bfd_vma) -1 if it should not be included.  */
   or (bfd_vma) -1 if it should not be included.  */
Line 3619... Line 4204...
   file.  We use it to put SHN_X86_64_LCOMMON items in .lbss, instead
   file.  We use it to put SHN_X86_64_LCOMMON items in .lbss, instead
   of .bss.  */
   of .bss.  */
 
 
static bfd_boolean
static bfd_boolean
elf64_x86_64_add_symbol_hook (bfd *abfd,
elf64_x86_64_add_symbol_hook (bfd *abfd,
                              struct bfd_link_info *info ATTRIBUTE_UNUSED,
                              struct bfd_link_info *info,
                              Elf_Internal_Sym *sym,
                              Elf_Internal_Sym *sym,
                              const char **namep ATTRIBUTE_UNUSED,
                              const char **namep ATTRIBUTE_UNUSED,
                              flagword *flagsp ATTRIBUTE_UNUSED,
                              flagword *flagsp ATTRIBUTE_UNUSED,
                              asection **secp, bfd_vma *valp)
                              asection **secp,
 
                              bfd_vma *valp)
{
{
  asection *lcomm;
  asection *lcomm;
 
 
  switch (sym->st_shndx)
  switch (sym->st_shndx)
    {
    {
Line 3646... Line 4232...
        }
        }
      *secp = lcomm;
      *secp = lcomm;
      *valp = sym->st_size;
      *valp = sym->st_size;
      break;
      break;
    }
    }
 
 
 
  if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
 
    elf_tdata (info->output_bfd)->has_ifunc_symbols = TRUE;
 
 
  return TRUE;
  return TRUE;
}
}
 
 
 
 
/* Given a BFD section, try to locate the corresponding ELF section
/* Given a BFD section, try to locate the corresponding ELF section
Line 3825... Line 4415...
 
 
#define elf_info_to_howto                   elf64_x86_64_info_to_howto
#define elf_info_to_howto                   elf64_x86_64_info_to_howto
 
 
#define bfd_elf64_bfd_link_hash_table_create \
#define bfd_elf64_bfd_link_hash_table_create \
  elf64_x86_64_link_hash_table_create
  elf64_x86_64_link_hash_table_create
 
#define bfd_elf64_bfd_link_hash_table_free \
 
  elf64_x86_64_link_hash_table_free
#define bfd_elf64_bfd_reloc_type_lookup     elf64_x86_64_reloc_type_lookup
#define bfd_elf64_bfd_reloc_type_lookup     elf64_x86_64_reloc_type_lookup
#define bfd_elf64_bfd_reloc_name_lookup \
#define bfd_elf64_bfd_reloc_name_lookup \
  elf64_x86_64_reloc_name_lookup
  elf64_x86_64_reloc_name_lookup
 
 
#define elf_backend_adjust_dynamic_symbol   elf64_x86_64_adjust_dynamic_symbol
#define elf_backend_adjust_dynamic_symbol   elf64_x86_64_adjust_dynamic_symbol
Line 3873... Line 4465...
#define elf_backend_additional_program_headers \
#define elf_backend_additional_program_headers \
  elf64_x86_64_additional_program_headers
  elf64_x86_64_additional_program_headers
#define elf_backend_hash_symbol \
#define elf_backend_hash_symbol \
  elf64_x86_64_hash_symbol
  elf64_x86_64_hash_symbol
 
 
 
#undef  elf_backend_post_process_headers
 
#define elf_backend_post_process_headers  _bfd_elf_set_osabi
 
 
#include "elf64-target.h"
#include "elf64-target.h"
 
 
/* FreeBSD support.  */
/* FreeBSD support.  */
 
 
#undef  TARGET_LITTLE_SYM
#undef  TARGET_LITTLE_SYM
Line 3885... Line 4480...
#define TARGET_LITTLE_NAME                  "elf64-x86-64-freebsd"
#define TARGET_LITTLE_NAME                  "elf64-x86-64-freebsd"
 
 
#undef  ELF_OSABI
#undef  ELF_OSABI
#define ELF_OSABI                           ELFOSABI_FREEBSD
#define ELF_OSABI                           ELFOSABI_FREEBSD
 
 
 
#undef  elf64_bed
 
#define elf64_bed elf64_x86_64_fbsd_bed
 
 
 
#include "elf64-target.h"
 
 
 
/* Intel L1OM support.  */
 
 
 
static bfd_boolean
 
elf64_l1om_elf_object_p (bfd *abfd)
 
{
 
  /* Set the right machine number for an L1OM elf64 file.  */
 
  bfd_default_set_arch_mach (abfd, bfd_arch_l1om, bfd_mach_l1om);
 
  return TRUE;
 
}
 
 
 
#undef  TARGET_LITTLE_SYM
 
#define TARGET_LITTLE_SYM                   bfd_elf64_l1om_vec
 
#undef  TARGET_LITTLE_NAME
 
#define TARGET_LITTLE_NAME                  "elf64-l1om"
 
#undef ELF_ARCH
 
#define ELF_ARCH                            bfd_arch_l1om
 
 
 
#undef  ELF_MACHINE_CODE
 
#define ELF_MACHINE_CODE                    EM_L1OM
 
 
 
#undef  ELF_OSABI
 
 
 
#undef  elf64_bed
 
#define elf64_bed elf64_l1om_bed
 
 
 
#undef elf_backend_object_p
 
#define elf_backend_object_p                elf64_l1om_elf_object_p
 
 
#undef  elf_backend_post_process_headers
#undef  elf_backend_post_process_headers
#define elf_backend_post_process_headers  _bfd_elf_set_osabi
 
 
#include "elf64-target.h"
 
 
 
/* FreeBSD L1OM support.  */
 
 
 
#undef  TARGET_LITTLE_SYM
 
#define TARGET_LITTLE_SYM                   bfd_elf64_l1om_freebsd_vec
 
#undef  TARGET_LITTLE_NAME
 
#define TARGET_LITTLE_NAME                  "elf64-l1om-freebsd"
 
 
 
#undef  ELF_OSABI
 
#define ELF_OSABI                           ELFOSABI_FREEBSD
 
 
#undef  elf64_bed
#undef  elf64_bed
#define elf64_bed elf64_x86_64_fbsd_bed
#define elf64_bed elf64_l1om_fbsd_bed
 
 
 
#undef  elf_backend_post_process_headers
 
#define elf_backend_post_process_headers  _bfd_elf_set_osabi
 
 
#include "elf64-target.h"
#include "elf64-target.h"
 
 
 No newline at end of file
 No newline at end of file

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.