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

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [gnu-src/] [gdb-6.8/] [bfd/] [elf32-xtensa.c] - Diff between revs 157 and 225

Show entire file | Details | Blame | View Log

Rev 157 Rev 225
Line 1... Line 1...
/* Xtensa-specific support for 32-bit ELF.
/* Xtensa-specific support for 32-bit ELF.
   Copyright 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
   Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009
 
   Free Software Foundation, Inc.
 
 
   This file is part of BFD, the Binary File Descriptor library.
   This file is part of BFD, the Binary File Descriptor library.
 
 
   This program is free software; you can redistribute it and/or
   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   modify it under the terms of the GNU General Public License as
Line 106... Line 107...
static bfd_boolean xtensa_is_insntable_section (asection *);
static bfd_boolean xtensa_is_insntable_section (asection *);
static bfd_boolean xtensa_is_littable_section (asection *);
static bfd_boolean xtensa_is_littable_section (asection *);
static bfd_boolean xtensa_is_proptable_section (asection *);
static bfd_boolean xtensa_is_proptable_section (asection *);
static int internal_reloc_compare (const void *, const void *);
static int internal_reloc_compare (const void *, const void *);
static int internal_reloc_matches (const void *, const void *);
static int internal_reloc_matches (const void *, const void *);
extern asection *xtensa_get_property_section (asection *, const char *);
static asection *xtensa_get_property_section (asection *, const char *);
 
extern asection *xtensa_make_property_section (asection *, const char *);
static flagword xtensa_get_property_predef_flags (asection *);
static flagword xtensa_get_property_predef_flags (asection *);
 
 
/* Other functions called directly by the linker.  */
/* Other functions called directly by the linker.  */
 
 
typedef void (*deps_callback_t)
typedef void (*deps_callback_t)
Line 285... Line 287...
         bfd_elf_xtensa_reloc, "R_XTENSA_SLOT12_ALT", FALSE, 0, 0, TRUE),
         bfd_elf_xtensa_reloc, "R_XTENSA_SLOT12_ALT", FALSE, 0, 0, TRUE),
  HOWTO (R_XTENSA_SLOT13_ALT, 0, 0, 0, TRUE, 0, complain_overflow_dont,
  HOWTO (R_XTENSA_SLOT13_ALT, 0, 0, 0, TRUE, 0, complain_overflow_dont,
         bfd_elf_xtensa_reloc, "R_XTENSA_SLOT13_ALT", FALSE, 0, 0, TRUE),
         bfd_elf_xtensa_reloc, "R_XTENSA_SLOT13_ALT", FALSE, 0, 0, TRUE),
  HOWTO (R_XTENSA_SLOT14_ALT, 0, 0, 0, TRUE, 0, complain_overflow_dont,
  HOWTO (R_XTENSA_SLOT14_ALT, 0, 0, 0, TRUE, 0, complain_overflow_dont,
         bfd_elf_xtensa_reloc, "R_XTENSA_SLOT14_ALT", FALSE, 0, 0, TRUE),
         bfd_elf_xtensa_reloc, "R_XTENSA_SLOT14_ALT", FALSE, 0, 0, TRUE),
 
 
 
  /* TLS relocations.  */
 
  HOWTO (R_XTENSA_TLSDESC_FN, 0, 2, 32, FALSE, 0, complain_overflow_dont,
 
         bfd_elf_xtensa_reloc, "R_XTENSA_TLSDESC_FN",
 
         FALSE, 0, 0xffffffff, FALSE),
 
  HOWTO (R_XTENSA_TLSDESC_ARG, 0, 2, 32, FALSE, 0, complain_overflow_dont,
 
         bfd_elf_xtensa_reloc, "R_XTENSA_TLSDESC_ARG",
 
         FALSE, 0, 0xffffffff, FALSE),
 
  HOWTO (R_XTENSA_TLS_DTPOFF, 0, 2, 32, FALSE, 0, complain_overflow_dont,
 
         bfd_elf_xtensa_reloc, "R_XTENSA_TLS_DTPOFF",
 
         FALSE, 0, 0xffffffff, FALSE),
 
  HOWTO (R_XTENSA_TLS_TPOFF, 0, 2, 32, FALSE, 0, complain_overflow_dont,
 
         bfd_elf_xtensa_reloc, "R_XTENSA_TLS_TPOFF",
 
         FALSE, 0, 0xffffffff, FALSE),
 
  HOWTO (R_XTENSA_TLS_FUNC, 0, 0, 0, FALSE, 0, complain_overflow_dont,
 
         bfd_elf_xtensa_reloc, "R_XTENSA_TLS_FUNC",
 
         FALSE, 0, 0, FALSE),
 
  HOWTO (R_XTENSA_TLS_ARG, 0, 0, 0, FALSE, 0, complain_overflow_dont,
 
         bfd_elf_xtensa_reloc, "R_XTENSA_TLS_ARG",
 
         FALSE, 0, 0, FALSE),
 
  HOWTO (R_XTENSA_TLS_CALL, 0, 0, 0, FALSE, 0, complain_overflow_dont,
 
         bfd_elf_xtensa_reloc, "R_XTENSA_TLS_CALL",
 
         FALSE, 0, 0, FALSE),
};
};
 
 
#if DEBUG_GEN_RELOC
#if DEBUG_GEN_RELOC
#define TRACE(str) \
#define TRACE(str) \
  fprintf (stderr, "Xtensa bfd reloc lookup %d (%s)\n", code, str)
  fprintf (stderr, "Xtensa bfd reloc lookup %d (%s)\n", code, str)
Line 372... Line 397...
 
 
    case BFD_RELOC_VTABLE_ENTRY:
    case BFD_RELOC_VTABLE_ENTRY:
      TRACE ("BFD_RELOC_VTABLE_ENTRY");
      TRACE ("BFD_RELOC_VTABLE_ENTRY");
      return &elf_howto_table[(unsigned) R_XTENSA_GNU_VTENTRY ];
      return &elf_howto_table[(unsigned) R_XTENSA_GNU_VTENTRY ];
 
 
 
    case BFD_RELOC_XTENSA_TLSDESC_FN:
 
      TRACE ("BFD_RELOC_XTENSA_TLSDESC_FN");
 
      return &elf_howto_table[(unsigned) R_XTENSA_TLSDESC_FN ];
 
 
 
    case BFD_RELOC_XTENSA_TLSDESC_ARG:
 
      TRACE ("BFD_RELOC_XTENSA_TLSDESC_ARG");
 
      return &elf_howto_table[(unsigned) R_XTENSA_TLSDESC_ARG ];
 
 
 
    case BFD_RELOC_XTENSA_TLS_DTPOFF:
 
      TRACE ("BFD_RELOC_XTENSA_TLS_DTPOFF");
 
      return &elf_howto_table[(unsigned) R_XTENSA_TLS_DTPOFF ];
 
 
 
    case BFD_RELOC_XTENSA_TLS_TPOFF:
 
      TRACE ("BFD_RELOC_XTENSA_TLS_TPOFF");
 
      return &elf_howto_table[(unsigned) R_XTENSA_TLS_TPOFF ];
 
 
 
    case BFD_RELOC_XTENSA_TLS_FUNC:
 
      TRACE ("BFD_RELOC_XTENSA_TLS_FUNC");
 
      return &elf_howto_table[(unsigned) R_XTENSA_TLS_FUNC ];
 
 
 
    case BFD_RELOC_XTENSA_TLS_ARG:
 
      TRACE ("BFD_RELOC_XTENSA_TLS_ARG");
 
      return &elf_howto_table[(unsigned) R_XTENSA_TLS_ARG ];
 
 
 
    case BFD_RELOC_XTENSA_TLS_CALL:
 
      TRACE ("BFD_RELOC_XTENSA_TLS_CALL");
 
      return &elf_howto_table[(unsigned) R_XTENSA_TLS_CALL ];
 
 
    default:
    default:
      if (code >= BFD_RELOC_XTENSA_SLOT0_OP
      if (code >= BFD_RELOC_XTENSA_SLOT0_OP
          && code <= BFD_RELOC_XTENSA_SLOT14_OP)
          && code <= BFD_RELOC_XTENSA_SLOT14_OP)
        {
        {
          unsigned n = (R_XTENSA_SLOT0_OP +
          unsigned n = (R_XTENSA_SLOT0_OP +
Line 476... Line 529...
  0xb1, 0x00, 0x00,     /* l32r  a11, [literal for reloc index] */
  0xb1, 0x00, 0x00,     /* l32r  a11, [literal for reloc index] */
  0xa0, 0x08, 0x00,     /* jx    a8 */
  0xa0, 0x08, 0x00,     /* jx    a8 */
  0                      /* unused */
  0                      /* unused */
};
};
 
 
 
/* The size of the thread control block.  */
 
#define TCB_SIZE        8
 
 
 
struct elf_xtensa_link_hash_entry
 
{
 
  struct elf_link_hash_entry elf;
 
 
 
  bfd_signed_vma tlsfunc_refcount;
 
 
 
#define GOT_UNKNOWN     0
 
#define GOT_NORMAL      1
 
#define GOT_TLS_GD      2       /* global or local dynamic */
 
#define GOT_TLS_IE      4       /* initial or local exec */
 
#define GOT_TLS_ANY     (GOT_TLS_GD | GOT_TLS_IE)
 
  unsigned char tls_type;
 
};
 
 
 
#define elf_xtensa_hash_entry(ent) ((struct elf_xtensa_link_hash_entry *)(ent))
 
 
 
struct elf_xtensa_obj_tdata
 
{
 
  struct elf_obj_tdata root;
 
 
 
  /* tls_type for each local got entry.  */
 
  char *local_got_tls_type;
 
 
 
  bfd_signed_vma *local_tlsfunc_refcounts;
 
};
 
 
 
#define elf_xtensa_tdata(abfd) \
 
  ((struct elf_xtensa_obj_tdata *) (abfd)->tdata.any)
 
 
 
#define elf_xtensa_local_got_tls_type(abfd) \
 
  (elf_xtensa_tdata (abfd)->local_got_tls_type)
 
 
 
#define elf_xtensa_local_tlsfunc_refcounts(abfd) \
 
  (elf_xtensa_tdata (abfd)->local_tlsfunc_refcounts)
 
 
 
#define is_xtensa_elf(bfd) \
 
  (bfd_get_flavour (bfd) == bfd_target_elf_flavour \
 
   && elf_tdata (bfd) != NULL \
 
   && elf_object_id (bfd) == XTENSA_ELF_TDATA)
 
 
 
static bfd_boolean
 
elf_xtensa_mkobject (bfd *abfd)
 
{
 
  return bfd_elf_allocate_object (abfd, sizeof (struct elf_xtensa_obj_tdata),
 
                                  XTENSA_ELF_TDATA);
 
}
 
 
/* Xtensa ELF linker hash table.  */
/* Xtensa ELF linker hash table.  */
 
 
struct elf_xtensa_link_hash_table
struct elf_xtensa_link_hash_table
{
{
  struct elf_link_hash_table elf;
  struct elf_link_hash_table elf;
Line 498... Line 601...
     the sections have to be created before size_dynamic_sections,
     the sections have to be created before size_dynamic_sections,
     where we figure out the exact number of PLT entries that will be
     where we figure out the exact number of PLT entries that will be
     needed.  It is OK if this count is an overestimate, e.g., some
     needed.  It is OK if this count is an overestimate, e.g., some
     relocations may be removed by GC.  */
     relocations may be removed by GC.  */
  int plt_reloc_count;
  int plt_reloc_count;
 
 
 
  struct elf_xtensa_link_hash_entry *tlsbase;
};
};
 
 
/* Get the Xtensa ELF linker hash table from a link_info structure.  */
/* Get the Xtensa ELF linker hash table from a link_info structure.  */
 
 
#define elf_xtensa_hash_table(p) \
#define elf_xtensa_hash_table(p) \
  ((struct elf_xtensa_link_hash_table *) ((p)->hash))
  ((struct elf_xtensa_link_hash_table *) ((p)->hash))
 
 
 
/* Create an entry in an Xtensa ELF linker hash table.  */
 
 
 
static struct bfd_hash_entry *
 
elf_xtensa_link_hash_newfunc (struct bfd_hash_entry *entry,
 
                              struct bfd_hash_table *table,
 
                              const char *string)
 
{
 
  /* Allocate the structure if it has not already been allocated by a
 
     subclass.  */
 
  if (entry == NULL)
 
    {
 
      entry = bfd_hash_allocate (table,
 
                                 sizeof (struct elf_xtensa_link_hash_entry));
 
      if (entry == NULL)
 
        return entry;
 
    }
 
 
 
  /* Call the allocation method of the superclass.  */
 
  entry = _bfd_elf_link_hash_newfunc (entry, table, string);
 
  if (entry != NULL)
 
    {
 
      struct elf_xtensa_link_hash_entry *eh = elf_xtensa_hash_entry (entry);
 
      eh->tlsfunc_refcount = 0;
 
      eh->tls_type = GOT_UNKNOWN;
 
    }
 
 
 
  return entry;
 
}
 
 
/* Create an Xtensa ELF linker hash table.  */
/* Create an Xtensa ELF linker hash table.  */
 
 
static struct bfd_link_hash_table *
static struct bfd_link_hash_table *
elf_xtensa_link_hash_table_create (bfd *abfd)
elf_xtensa_link_hash_table_create (bfd *abfd)
{
{
 
  struct elf_link_hash_entry *tlsbase;
  struct elf_xtensa_link_hash_table *ret;
  struct elf_xtensa_link_hash_table *ret;
  bfd_size_type amt = sizeof (struct elf_xtensa_link_hash_table);
  bfd_size_type amt = sizeof (struct elf_xtensa_link_hash_table);
 
 
  ret = bfd_malloc (amt);
  ret = bfd_malloc (amt);
  if (ret == NULL)
  if (ret == NULL)
    return NULL;
    return NULL;
 
 
  if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd,
  if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd,
                                      _bfd_elf_link_hash_newfunc,
                                      elf_xtensa_link_hash_newfunc,
                                      sizeof (struct elf_link_hash_entry)))
                                      sizeof (struct elf_xtensa_link_hash_entry)))
    {
    {
      free (ret);
      free (ret);
      return NULL;
      return NULL;
    }
    }
 
 
Line 535... Line 670...
  ret->sgotloc = NULL;
  ret->sgotloc = NULL;
  ret->spltlittbl = NULL;
  ret->spltlittbl = NULL;
 
 
  ret->plt_reloc_count = 0;
  ret->plt_reloc_count = 0;
 
 
 
  /* Create a hash entry for "_TLS_MODULE_BASE_" to speed up checking
 
     for it later.  */
 
  tlsbase = elf_link_hash_lookup (&ret->elf, "_TLS_MODULE_BASE_",
 
                                  TRUE, FALSE, FALSE);
 
  tlsbase->root.type = bfd_link_hash_new;
 
  tlsbase->root.u.undef.abfd = NULL;
 
  tlsbase->non_elf = 0;
 
  ret->tlsbase = elf_xtensa_hash_entry (tlsbase);
 
  ret->tlsbase->tls_type = GOT_UNKNOWN;
 
 
  return &ret->elf.root;
  return &ret->elf.root;
}
}
 
 
 
/* Copy the extra info we tack onto an elf_link_hash_entry.  */
 
 
 
static void
 
elf_xtensa_copy_indirect_symbol (struct bfd_link_info *info,
 
                                 struct elf_link_hash_entry *dir,
 
                                 struct elf_link_hash_entry *ind)
 
{
 
  struct elf_xtensa_link_hash_entry *edir, *eind;
 
 
 
  edir = elf_xtensa_hash_entry (dir);
 
  eind = elf_xtensa_hash_entry (ind);
 
 
 
  if (ind->root.type == bfd_link_hash_indirect)
 
    {
 
      edir->tlsfunc_refcount += eind->tlsfunc_refcount;
 
      eind->tlsfunc_refcount = 0;
 
 
 
      if (dir->got.refcount <= 0)
 
        {
 
          edir->tls_type = eind->tls_type;
 
          eind->tls_type = GOT_UNKNOWN;
 
        }
 
    }
 
 
 
  _bfd_elf_link_hash_copy_indirect (info, dir, ind);
 
}
 
 
static inline bfd_boolean
static inline bfd_boolean
elf_xtensa_dynamic_symbol_p (struct elf_link_hash_entry *h,
elf_xtensa_dynamic_symbol_p (struct elf_link_hash_entry *h,
                             struct bfd_link_info *info)
                             struct bfd_link_info *info)
{
{
  /* Check if we should do dynamic things to this symbol.  The
  /* Check if we should do dynamic things to this symbol.  The
Line 797... Line 969...
  Elf_Internal_Shdr *symtab_hdr;
  Elf_Internal_Shdr *symtab_hdr;
  struct elf_link_hash_entry **sym_hashes;
  struct elf_link_hash_entry **sym_hashes;
  const Elf_Internal_Rela *rel;
  const Elf_Internal_Rela *rel;
  const Elf_Internal_Rela *rel_end;
  const Elf_Internal_Rela *rel_end;
 
 
  if (info->relocatable)
  if (info->relocatable || (sec->flags & SEC_ALLOC) == 0)
    return TRUE;
    return TRUE;
 
 
 
  BFD_ASSERT (is_xtensa_elf (abfd));
 
 
  htab = elf_xtensa_hash_table (info);
  htab = elf_xtensa_hash_table (info);
  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
  sym_hashes = elf_sym_hashes (abfd);
  sym_hashes = elf_sym_hashes (abfd);
 
 
  rel_end = relocs + sec->reloc_count;
  rel_end = relocs + sec->reloc_count;
  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 = NULL;
 
      struct elf_xtensa_link_hash_entry *eh;
 
      int tls_type, old_tls_type;
 
      bfd_boolean is_got = FALSE;
 
      bfd_boolean is_plt = FALSE;
 
      bfd_boolean is_tlsfunc = FALSE;
 
 
      r_symndx = ELF32_R_SYM (rel->r_info);
      r_symndx = ELF32_R_SYM (rel->r_info);
      r_type = ELF32_R_TYPE (rel->r_info);
      r_type = ELF32_R_TYPE (rel->r_info);
 
 
      if (r_symndx >= NUM_SHDR_ENTRIES (symtab_hdr))
      if (r_symndx >= NUM_SHDR_ENTRIES (symtab_hdr))
Line 821... Line 1000...
          (*_bfd_error_handler) (_("%B: bad symbol index: %d"),
          (*_bfd_error_handler) (_("%B: bad symbol index: %d"),
                                 abfd, r_symndx);
                                 abfd, r_symndx);
          return FALSE;
          return FALSE;
        }
        }
 
 
      if (r_symndx < symtab_hdr->sh_info)
      if (r_symndx >= symtab_hdr->sh_info)
        h = NULL;
 
      else
 
        {
        {
          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;
        }
        }
 
      eh = elf_xtensa_hash_entry (h);
 
 
      switch (r_type)
      switch (r_type)
        {
        {
        case R_XTENSA_32:
        case R_XTENSA_TLSDESC_FN:
          if (h == NULL)
          if (info->shared)
            goto local_literal;
            {
 
              tls_type = GOT_TLS_GD;
 
              is_got = TRUE;
 
              is_tlsfunc = TRUE;
 
            }
 
          else
 
            tls_type = GOT_TLS_IE;
 
          break;
 
 
          if ((sec->flags & SEC_ALLOC) != 0)
        case R_XTENSA_TLSDESC_ARG:
 
          if (info->shared)
            {
            {
              if (h->got.refcount <= 0)
              tls_type = GOT_TLS_GD;
                h->got.refcount = 1;
              is_got = TRUE;
 
            }
              else
              else
                h->got.refcount += 1;
            {
 
              tls_type = GOT_TLS_IE;
 
              if (h && elf_xtensa_hash_entry (h) != htab->tlsbase)
 
                is_got = TRUE;
            }
            }
          break;
          break;
 
 
 
        case R_XTENSA_TLS_DTPOFF:
 
          if (info->shared)
 
            tls_type = GOT_TLS_GD;
 
          else
 
            tls_type = GOT_TLS_IE;
 
          break;
 
 
 
        case R_XTENSA_TLS_TPOFF:
 
          tls_type = GOT_TLS_IE;
 
          if (info->shared)
 
            info->flags |= DF_STATIC_TLS;
 
          if (info->shared || h)
 
            is_got = TRUE;
 
          break;
 
 
 
        case R_XTENSA_32:
 
          tls_type = GOT_NORMAL;
 
          is_got = TRUE;
 
          break;
 
 
        case R_XTENSA_PLT:
        case R_XTENSA_PLT:
          /* If this relocation is against a local symbol, then it's
          tls_type = GOT_NORMAL;
             exactly the same as a normal local GOT entry.  */
          is_plt = TRUE;
          if (h == NULL)
          break;
            goto local_literal;
 
 
 
          if ((sec->flags & SEC_ALLOC) != 0)
        case R_XTENSA_GNU_VTINHERIT:
 
          /* This relocation describes the C++ object vtable hierarchy.
 
             Reconstruct it for later use during GC.  */
 
          if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
 
            return FALSE;
 
          continue;
 
 
 
        case R_XTENSA_GNU_VTENTRY:
 
          /* This relocation describes which C++ vtable entries are actually
 
             used.  Record for later use during GC.  */
 
          BFD_ASSERT (h != NULL);
 
          if (h != NULL
 
              && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
 
            return FALSE;
 
          continue;
 
 
 
        default:
 
          /* Nothing to do for any other relocations.  */
 
          continue;
 
        }
 
 
 
      if (h)
 
        {
 
          if (is_plt)
            {
            {
              if (h->plt.refcount <= 0)
              if (h->plt.refcount <= 0)
                {
                {
                  h->needs_plt = 1;
                  h->needs_plt = 1;
                  h->plt.refcount = 1;
                  h->plt.refcount = 1;
Line 873... Line 1105...
                {
                {
                  if (! add_extra_plt_sections (info, htab->plt_reloc_count))
                  if (! add_extra_plt_sections (info, htab->plt_reloc_count))
                    return FALSE;
                    return FALSE;
                }
                }
            }
            }
          break;
          else if (is_got)
 
 
        local_literal:
 
          if ((sec->flags & SEC_ALLOC) != 0)
 
            {
            {
              bfd_signed_vma *local_got_refcounts;
              if (h->got.refcount <= 0)
 
                h->got.refcount = 1;
 
              else
 
                h->got.refcount += 1;
 
            }
 
 
              /* This is a global offset table entry for a local symbol.  */
          if (is_tlsfunc)
              local_got_refcounts = elf_local_got_refcounts (abfd);
            eh->tlsfunc_refcount += 1;
              if (local_got_refcounts == NULL)
 
 
          old_tls_type = eh->tls_type;
 
        }
 
      else
                {
                {
                  bfd_size_type size;
          /* Allocate storage the first time.  */
 
          if (elf_local_got_refcounts (abfd) == NULL)
 
            {
 
              bfd_size_type size = symtab_hdr->sh_info;
 
              void *mem;
 
 
                  size = symtab_hdr->sh_info;
              mem = bfd_zalloc (abfd, size * sizeof (bfd_signed_vma));
                  size *= sizeof (bfd_signed_vma);
              if (mem == NULL)
                  local_got_refcounts =
 
                    (bfd_signed_vma *) bfd_zalloc (abfd, size);
 
                  if (local_got_refcounts == NULL)
 
                    return FALSE;
                    return FALSE;
                  elf_local_got_refcounts (abfd) = local_got_refcounts;
              elf_local_got_refcounts (abfd) = (bfd_signed_vma *) mem;
                }
 
              local_got_refcounts[r_symndx] += 1;
 
            }
 
          break;
 
 
 
        case R_XTENSA_GNU_VTINHERIT:
              mem = bfd_zalloc (abfd, size);
          /* This relocation describes the C++ object vtable hierarchy.
              if (mem == NULL)
             Reconstruct it for later use during GC.  */
 
          if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
 
            return FALSE;
            return FALSE;
          break;
              elf_xtensa_local_got_tls_type (abfd) = (char *) mem;
 
 
        case R_XTENSA_GNU_VTENTRY:
              mem = bfd_zalloc (abfd, size * sizeof (bfd_signed_vma));
          /* This relocation describes which C++ vtable entries are actually
              if (mem == NULL)
             used.  Record for later use during GC.  */
 
          BFD_ASSERT (h != NULL);
 
          if (h != NULL
 
              && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
 
            return FALSE;
            return FALSE;
          break;
              elf_xtensa_local_tlsfunc_refcounts (abfd)
 
                = (bfd_signed_vma *) mem;
 
            }
 
 
        default:
          /* This is a global offset table entry for a local symbol.  */
          break;
          if (is_got || is_plt)
 
            elf_local_got_refcounts (abfd) [r_symndx] += 1;
 
 
 
          if (is_tlsfunc)
 
            elf_xtensa_local_tlsfunc_refcounts (abfd) [r_symndx] += 1;
 
 
 
          old_tls_type = elf_xtensa_local_got_tls_type (abfd) [r_symndx];
 
        }
 
 
 
      if ((old_tls_type & GOT_TLS_IE) && (tls_type & GOT_TLS_IE))
 
        tls_type |= old_tls_type;
 
      /* If a TLS symbol is accessed using IE at least once,
 
         there is no point to use a dynamic model for it.  */
 
      else if (old_tls_type != tls_type && old_tls_type != GOT_UNKNOWN
 
               && ((old_tls_type & GOT_TLS_GD) == 0
 
                   || (tls_type & GOT_TLS_IE) == 0))
 
        {
 
          if ((old_tls_type & GOT_TLS_IE) && (tls_type & GOT_TLS_GD))
 
            tls_type = old_tls_type;
 
          else if ((old_tls_type & GOT_TLS_GD) && (tls_type & GOT_TLS_GD))
 
            tls_type |= old_tls_type;
 
          else
 
            {
 
              (*_bfd_error_handler)
 
                (_("%B: `%s' accessed both as normal and thread local symbol"),
 
                 abfd,
 
                 h ? h->root.root.string : "<local>");
 
              return FALSE;
 
            }
 
        }
 
 
 
      if (old_tls_type != tls_type)
 
        {
 
          if (eh)
 
            eh->tls_type = tls_type;
 
          else
 
            elf_xtensa_local_got_tls_type (abfd) [r_symndx] = tls_type;
        }
        }
    }
    }
 
 
  return TRUE;
  return TRUE;
}
}
Line 1001... Line 1266...
/* Update the GOT & PLT entry reference counts
/* Update the GOT & PLT entry reference counts
   for the section being removed.  */
   for the section being removed.  */
 
 
static bfd_boolean
static bfd_boolean
elf_xtensa_gc_sweep_hook (bfd *abfd,
elf_xtensa_gc_sweep_hook (bfd *abfd,
                          struct bfd_link_info *info ATTRIBUTE_UNUSED,
                          struct bfd_link_info *info,
                          asection *sec,
                          asection *sec,
                          const Elf_Internal_Rela *relocs)
                          const Elf_Internal_Rela *relocs)
{
{
  Elf_Internal_Shdr *symtab_hdr;
  Elf_Internal_Shdr *symtab_hdr;
  struct elf_link_hash_entry **sym_hashes;
  struct elf_link_hash_entry **sym_hashes;
  bfd_signed_vma *local_got_refcounts;
 
  const Elf_Internal_Rela *rel, *relend;
  const Elf_Internal_Rela *rel, *relend;
 
  struct elf_xtensa_link_hash_table *htab;
 
 
 
  htab = elf_xtensa_hash_table (info);
 
 
  if (info->relocatable)
  if (info->relocatable)
    return TRUE;
    return TRUE;
 
 
  if ((sec->flags & SEC_ALLOC) == 0)
  if ((sec->flags & SEC_ALLOC) == 0)
    return TRUE;
    return TRUE;
 
 
  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
  sym_hashes = elf_sym_hashes (abfd);
  sym_hashes = elf_sym_hashes (abfd);
  local_got_refcounts = elf_local_got_refcounts (abfd);
 
 
 
  relend = relocs + sec->reloc_count;
  relend = relocs + sec->reloc_count;
  for (rel = relocs; rel < relend; rel++)
  for (rel = relocs; rel < relend; rel++)
    {
    {
      unsigned long r_symndx;
      unsigned long r_symndx;
      unsigned int r_type;
      unsigned int r_type;
      struct elf_link_hash_entry *h = NULL;
      struct elf_link_hash_entry *h = NULL;
 
      struct elf_xtensa_link_hash_entry *eh;
 
      bfd_boolean is_got = FALSE;
 
      bfd_boolean is_plt = FALSE;
 
      bfd_boolean is_tlsfunc = FALSE;
 
 
      r_symndx = ELF32_R_SYM (rel->r_info);
      r_symndx = ELF32_R_SYM (rel->r_info);
      if (r_symndx >= symtab_hdr->sh_info)
      if (r_symndx >= symtab_hdr->sh_info)
        {
        {
          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;
        }
        }
 
      eh = elf_xtensa_hash_entry (h);
 
 
      r_type = ELF32_R_TYPE (rel->r_info);
      r_type = ELF32_R_TYPE (rel->r_info);
      switch (r_type)
      switch (r_type)
        {
        {
        case R_XTENSA_32:
        case R_XTENSA_TLSDESC_FN:
          if (h == NULL)
          if (info->shared)
            goto local_literal;
            {
          if (h->got.refcount > 0)
              is_got = TRUE;
            h->got.refcount--;
              is_tlsfunc = TRUE;
 
            }
          break;
          break;
 
 
        case R_XTENSA_PLT:
        case R_XTENSA_TLSDESC_ARG:
          if (h == NULL)
          if (info->shared)
            goto local_literal;
            is_got = TRUE;
          if (h->plt.refcount > 0)
          else
            h->plt.refcount--;
            {
 
              if (h && elf_xtensa_hash_entry (h) != htab->tlsbase)
 
                is_got = TRUE;
 
            }
          break;
          break;
 
 
        local_literal:
        case R_XTENSA_TLS_TPOFF:
          if (local_got_refcounts[r_symndx] > 0)
          if (info->shared || h)
            local_got_refcounts[r_symndx] -= 1;
            is_got = TRUE;
          break;
          break;
 
 
        default:
        case R_XTENSA_32:
 
          is_got = TRUE;
          break;
          break;
 
 
 
        case R_XTENSA_PLT:
 
          is_plt = TRUE;
 
          break;
 
 
 
        default:
 
          continue;
 
        }
 
 
 
      if (h)
 
        {
 
          if (is_plt)
 
            {
 
              if (h->plt.refcount > 0)
 
                h->plt.refcount--;
 
            }
 
          else if (is_got)
 
            {
 
              if (h->got.refcount > 0)
 
                h->got.refcount--;
 
            }
 
          if (is_tlsfunc)
 
            {
 
              if (eh->tlsfunc_refcount > 0)
 
                eh->tlsfunc_refcount--;
 
            }
 
        }
 
      else
 
        {
 
          if (is_got || is_plt)
 
            {
 
              bfd_signed_vma *got_refcount
 
                = &elf_local_got_refcounts (abfd) [r_symndx];
 
              if (*got_refcount > 0)
 
                *got_refcount -= 1;
 
            }
 
          if (is_tlsfunc)
 
            {
 
              bfd_signed_vma *tlsfunc_refcount
 
                = &elf_xtensa_local_tlsfunc_refcounts (abfd) [r_symndx];
 
              if (*tlsfunc_refcount > 0)
 
                *tlsfunc_refcount -= 1;
 
            }
        }
        }
    }
    }
 
 
  return TRUE;
  return TRUE;
}
}
Line 1084... Line 1403...
    return FALSE;
    return FALSE;
  htab->splt = bfd_get_section_by_name (dynobj, ".plt");
  htab->splt = bfd_get_section_by_name (dynobj, ".plt");
  htab->srelplt = bfd_get_section_by_name (dynobj, ".rela.plt");
  htab->srelplt = bfd_get_section_by_name (dynobj, ".rela.plt");
  htab->sgot = bfd_get_section_by_name (dynobj, ".got");
  htab->sgot = bfd_get_section_by_name (dynobj, ".got");
  htab->sgotplt = bfd_get_section_by_name (dynobj, ".got.plt");
  htab->sgotplt = bfd_get_section_by_name (dynobj, ".got.plt");
 
  htab->srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
 
 
  /* Create any extra PLT sections in case check_relocs has already
  /* Create any extra PLT sections in case check_relocs has already
     been called on all the non-dynamic input files.  */
     been called on all the non-dynamic input files.  */
  if (! add_extra_plt_sections (info, htab->plt_reloc_count))
  if (! add_extra_plt_sections (info, htab->plt_reloc_count))
    return FALSE;
    return FALSE;
Line 1099... Line 1419...
  /* Mark the ".got.plt" section READONLY.  */
  /* Mark the ".got.plt" section READONLY.  */
  if (htab->sgotplt == NULL
  if (htab->sgotplt == NULL
      || ! bfd_set_section_flags (dynobj, htab->sgotplt, flags))
      || ! bfd_set_section_flags (dynobj, htab->sgotplt, flags))
    return FALSE;
    return FALSE;
 
 
  /* Create ".rela.got".  */
 
  htab->srelgot = bfd_make_section_with_flags (dynobj, ".rela.got", flags);
 
  if (htab->srelgot == NULL
 
      || ! bfd_set_section_alignment (dynobj, htab->srelgot, 2))
 
    return FALSE;
 
 
 
  /* Create ".got.loc" (literal tables for use by dynamic linker).  */
  /* Create ".got.loc" (literal tables for use by dynamic linker).  */
  htab->sgotloc = bfd_make_section_with_flags (dynobj, ".got.loc", flags);
  htab->sgotloc = bfd_make_section_with_flags (dynobj, ".got.loc", flags);
  if (htab->sgotloc == NULL
  if (htab->sgotloc == NULL
      || ! bfd_set_section_alignment (dynobj, htab->sgotloc, 2))
      || ! bfd_set_section_alignment (dynobj, htab->sgotloc, 2))
    return FALSE;
    return FALSE;
Line 1197... Line 1511...
static bfd_boolean
static bfd_boolean
elf_xtensa_allocate_dynrelocs (struct elf_link_hash_entry *h, void *arg)
elf_xtensa_allocate_dynrelocs (struct elf_link_hash_entry *h, void *arg)
{
{
  struct bfd_link_info *info;
  struct bfd_link_info *info;
  struct elf_xtensa_link_hash_table *htab;
  struct elf_xtensa_link_hash_table *htab;
  bfd_boolean is_dynamic;
  struct elf_xtensa_link_hash_entry *eh = elf_xtensa_hash_entry (h);
 
 
  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;
 
 
  info = (struct bfd_link_info *) arg;
  info = (struct bfd_link_info *) arg;
  htab = elf_xtensa_hash_table (info);
  htab = elf_xtensa_hash_table (info);
 
 
  is_dynamic = elf_xtensa_dynamic_symbol_p (h, info);
  /* If we saw any use of an IE model for this symbol, we can then optimize
 
     away GOT entries for any TLSDESC_FN relocs.  */
 
  if ((eh->tls_type & GOT_TLS_IE) != 0)
 
    {
 
      BFD_ASSERT (h->got.refcount >= eh->tlsfunc_refcount);
 
      h->got.refcount -= eh->tlsfunc_refcount;
 
    }
 
 
  if (! is_dynamic)
  if (! elf_xtensa_dynamic_symbol_p (h, info))
    elf_xtensa_make_sym_local (info, h);
    elf_xtensa_make_sym_local (info, h);
 
 
  if (h->plt.refcount > 0)
  if (h->plt.refcount > 0)
    htab->srelplt->size += (h->plt.refcount * sizeof (Elf32_External_Rela));
    htab->srelplt->size += (h->plt.refcount * sizeof (Elf32_External_Rela));
 
 
Line 1246... Line 1566...
      symtab_hdr = &elf_tdata (i)->symtab_hdr;
      symtab_hdr = &elf_tdata (i)->symtab_hdr;
      cnt = symtab_hdr->sh_info;
      cnt = symtab_hdr->sh_info;
 
 
      for (j = 0; j < cnt; ++j)
      for (j = 0; j < cnt; ++j)
        {
        {
 
          /* If we saw any use of an IE model for this symbol, we can
 
             then optimize away GOT entries for any TLSDESC_FN relocs.  */
 
          if ((elf_xtensa_local_got_tls_type (i) [j] & GOT_TLS_IE) != 0)
 
            {
 
              bfd_signed_vma *tlsfunc_refcount
 
                = &elf_xtensa_local_tlsfunc_refcounts (i) [j];
 
              BFD_ASSERT (local_got_refcounts[j] >= *tlsfunc_refcount);
 
              local_got_refcounts[j] -= *tlsfunc_refcount;
 
            }
 
 
          if (local_got_refcounts[j] > 0)
          if (local_got_refcounts[j] > 0)
            htab->srelgot->size += (local_got_refcounts[j]
            htab->srelgot->size += (local_got_refcounts[j]
                                    * sizeof (Elf32_External_Rela));
                                    * sizeof (Elf32_External_Rela));
        }
        }
    }
    }
Line 1495... Line 1825...
#undef add_dynamic_entry
#undef add_dynamic_entry
 
 
  return TRUE;
  return TRUE;
}
}
 
 
 
static bfd_boolean
 
elf_xtensa_always_size_sections (bfd *output_bfd,
 
                                 struct bfd_link_info *info)
 
{
 
  struct elf_xtensa_link_hash_table *htab;
 
  asection *tls_sec;
 
 
 
  htab = elf_xtensa_hash_table (info);
 
  tls_sec = htab->elf.tls_sec;
 
 
 
  if (tls_sec && (htab->tlsbase->tls_type & GOT_TLS_ANY) != 0)
 
    {
 
      struct elf_link_hash_entry *tlsbase = &htab->tlsbase->elf;
 
      struct bfd_link_hash_entry *bh = &tlsbase->root;
 
      const struct elf_backend_data *bed = get_elf_backend_data (output_bfd);
 
 
 
      tlsbase->type = STT_TLS;
 
      if (!(_bfd_generic_link_add_one_symbol
 
            (info, output_bfd, "_TLS_MODULE_BASE_", BSF_LOCAL,
 
             tls_sec, 0, NULL, FALSE,
 
             bed->collect, &bh)))
 
        return FALSE;
 
      tlsbase->def_regular = 1;
 
      tlsbase->other = STV_HIDDEN;
 
      (*bed->elf_backend_hide_symbol) (info, tlsbase, TRUE);
 
    }
 
 
 
  return TRUE;
 
}
 
 


 
/* Return the base VMA address which should be subtracted from real addresses
 
   when resolving @dtpoff relocation.
 
   This is PT_TLS segment p_vaddr.  */
 
 
 
static bfd_vma
 
dtpoff_base (struct bfd_link_info *info)
 
{
 
  /* If tls_sec is NULL, we should have signalled an error already.  */
 
  if (elf_hash_table (info)->tls_sec == NULL)
 
    return 0;
 
  return elf_hash_table (info)->tls_sec->vma;
 
}
 
 
 
/* Return the relocation value for @tpoff relocation
 
   if STT_TLS virtual address is ADDRESS.  */
 
 
 
static bfd_vma
 
tpoff (struct bfd_link_info *info, bfd_vma address)
 
{
 
  struct elf_link_hash_table *htab = elf_hash_table (info);
 
  bfd_vma base;
 
 
 
  /* If tls_sec is NULL, we should have signalled an error already.  */
 
  if (htab->tls_sec == NULL)
 
    return 0;
 
  base = align_power ((bfd_vma) TCB_SIZE, htab->tls_sec->alignment_power);
 
  return address - htab->tls_sec->vma + base;
 
}
 
 
/* Perform the specified relocation.  The instruction at (contents + address)
/* Perform the specified relocation.  The instruction at (contents + address)
   is modified to set one operand to represent the value in "relocation".  The
   is modified to set one operand to represent the value in "relocation".  The
   operand position is determined by the relocation type recorded in the
   operand position is determined by the relocation type recorded in the
   howto.  */
   howto.  */
 
 
Line 1543... Line 1932...
    {
    {
    case R_XTENSA_NONE:
    case R_XTENSA_NONE:
    case R_XTENSA_DIFF8:
    case R_XTENSA_DIFF8:
    case R_XTENSA_DIFF16:
    case R_XTENSA_DIFF16:
    case R_XTENSA_DIFF32:
    case R_XTENSA_DIFF32:
 
    case R_XTENSA_TLS_FUNC:
 
    case R_XTENSA_TLS_ARG:
 
    case R_XTENSA_TLS_CALL:
      return bfd_reloc_ok;
      return bfd_reloc_ok;
 
 
    case R_XTENSA_ASM_EXPAND:
    case R_XTENSA_ASM_EXPAND:
      if (!is_weak_undef)
      if (!is_weak_undef)
        {
        {
Line 1582... Line 1974...
        howto = &elf_howto_table[(unsigned) R_XTENSA_SLOT0_OP ];
        howto = &elf_howto_table[(unsigned) R_XTENSA_SLOT0_OP ];
      }
      }
      break;
      break;
 
 
    case R_XTENSA_32:
    case R_XTENSA_32:
    case R_XTENSA_PLT:
 
      {
      {
        bfd_vma x;
        bfd_vma x;
        x = bfd_get_32 (abfd, contents + address);
        x = bfd_get_32 (abfd, contents + address);
        x = x + relocation;
        x = x + relocation;
        bfd_put_32 (abfd, x, contents + address);
        bfd_put_32 (abfd, x, contents + address);
Line 1594... Line 1985...
      return bfd_reloc_ok;
      return bfd_reloc_ok;
 
 
    case R_XTENSA_32_PCREL:
    case R_XTENSA_32_PCREL:
      bfd_put_32 (abfd, relocation - self_address, contents + address);
      bfd_put_32 (abfd, relocation - self_address, contents + address);
      return bfd_reloc_ok;
      return bfd_reloc_ok;
 
 
 
    case R_XTENSA_PLT:
 
    case R_XTENSA_TLSDESC_FN:
 
    case R_XTENSA_TLSDESC_ARG:
 
    case R_XTENSA_TLS_DTPOFF:
 
    case R_XTENSA_TLS_TPOFF:
 
      bfd_put_32 (abfd, relocation, contents + address);
 
      return bfd_reloc_ok;
    }
    }
 
 
  /* Only instruction slot-specific relocations handled below.... */
  /* Only instruction slot-specific relocations handled below.... */
  slot = get_relocation_slot (howto->type);
  slot = get_relocation_slot (howto->type);
  if (slot == XTENSA_UNDEFINED)
  if (slot == XTENSA_UNDEFINED)
Line 1880... Line 2279...
      *error_message = vsprint_msg (*error_message, ": (%s + 0x%lx)",
      *error_message = vsprint_msg (*error_message, ": (%s + 0x%lx)",
                                    strlen (symbol->name) + 17,
                                    strlen (symbol->name) + 17,
                                    symbol->name,
                                    symbol->name,
                                    (unsigned long) reloc_entry->addend);
                                    (unsigned long) reloc_entry->addend);
    }
    }
 
 
  return flag;
  return flag;
 
}
 
 
 
 
 
/* Set up an entry in the procedure linkage table.  */
 
 
 
static bfd_vma
 
elf_xtensa_create_plt_entry (struct bfd_link_info *info,
 
                             bfd *output_bfd,
 
                             unsigned reloc_index)
 
{
 
  asection *splt, *sgotplt;
 
  bfd_vma plt_base, got_base;
 
  bfd_vma code_offset, lit_offset;
 
  int chunk;
 
 
 
  chunk = reloc_index / PLT_ENTRIES_PER_CHUNK;
 
  splt = elf_xtensa_get_plt_section (info, chunk);
 
  sgotplt = elf_xtensa_get_gotplt_section (info, chunk);
 
  BFD_ASSERT (splt != NULL && sgotplt != NULL);
 
 
 
  plt_base = splt->output_section->vma + splt->output_offset;
 
  got_base = sgotplt->output_section->vma + sgotplt->output_offset;
 
 
 
  lit_offset = 8 + (reloc_index % PLT_ENTRIES_PER_CHUNK) * 4;
 
  code_offset = (reloc_index % PLT_ENTRIES_PER_CHUNK) * PLT_ENTRY_SIZE;
 
 
 
  /* Fill in the literal entry.  This is the offset of the dynamic
 
     relocation entry.  */
 
  bfd_put_32 (output_bfd, reloc_index * sizeof (Elf32_External_Rela),
 
              sgotplt->contents + lit_offset);
 
 
 
  /* Fill in the entry in the procedure linkage table.  */
 
  memcpy (splt->contents + code_offset,
 
          (bfd_big_endian (output_bfd)
 
           ? elf_xtensa_be_plt_entry
 
           : elf_xtensa_le_plt_entry),
 
          PLT_ENTRY_SIZE);
 
  bfd_put_16 (output_bfd, l32r_offset (got_base + 0,
 
                                       plt_base + code_offset + 3),
 
              splt->contents + code_offset + 4);
 
  bfd_put_16 (output_bfd, l32r_offset (got_base + 4,
 
                                       plt_base + code_offset + 6),
 
              splt->contents + code_offset + 7);
 
  bfd_put_16 (output_bfd, l32r_offset (got_base + lit_offset,
 
                                       plt_base + code_offset + 9),
 
              splt->contents + code_offset + 10);
 
 
 
  return plt_base + code_offset;
 
}
 
 
 
 
 
static bfd_boolean get_indirect_call_dest_reg (xtensa_opcode, unsigned *);
 
 
 
static bfd_boolean
 
replace_tls_insn (Elf_Internal_Rela *rel,
 
                  bfd *abfd,
 
                  asection *input_section,
 
                  bfd_byte *contents,
 
                  bfd_boolean is_ld_model,
 
                  char **error_message)
 
{
 
  static xtensa_insnbuf ibuff = NULL;
 
  static xtensa_insnbuf sbuff = NULL;
 
  xtensa_isa isa = xtensa_default_isa;
 
  xtensa_format fmt;
 
  xtensa_opcode old_op, new_op;
 
  bfd_size_type input_size;
 
  int r_type;
 
  unsigned dest_reg, src_reg;
 
 
 
  if (ibuff == NULL)
 
    {
 
      ibuff = xtensa_insnbuf_alloc (isa);
 
      sbuff = xtensa_insnbuf_alloc (isa);
 
    }
 
 
 
  input_size = bfd_get_section_limit (abfd, input_section);
 
 
 
  /* Read the instruction into a buffer and decode the opcode.  */
 
  xtensa_insnbuf_from_chars (isa, ibuff, contents + rel->r_offset,
 
                             input_size - rel->r_offset);
 
  fmt = xtensa_format_decode (isa, ibuff);
 
  if (fmt == XTENSA_UNDEFINED)
 
    {
 
      *error_message = "cannot decode instruction format";
 
      return FALSE;
 
    }
 
 
 
  BFD_ASSERT (xtensa_format_num_slots (isa, fmt) == 1);
 
  xtensa_format_get_slot (isa, fmt, 0, ibuff, sbuff);
 
 
 
  old_op = xtensa_opcode_decode (isa, fmt, 0, sbuff);
 
  if (old_op == XTENSA_UNDEFINED)
 
    {
 
      *error_message = "cannot decode instruction opcode";
 
      return FALSE;
 
    }
 
 
 
  r_type = ELF32_R_TYPE (rel->r_info);
 
  switch (r_type)
 
    {
 
    case R_XTENSA_TLS_FUNC:
 
    case R_XTENSA_TLS_ARG:
 
      if (old_op != get_l32r_opcode ()
 
          || xtensa_operand_get_field (isa, old_op, 0, fmt, 0,
 
                                       sbuff, &dest_reg) != 0)
 
        {
 
          *error_message = "cannot extract L32R destination for TLS access";
 
          return FALSE;
 
        }
 
      break;
 
 
 
    case R_XTENSA_TLS_CALL:
 
      if (! get_indirect_call_dest_reg (old_op, &dest_reg)
 
          || xtensa_operand_get_field (isa, old_op, 0, fmt, 0,
 
                                       sbuff, &src_reg) != 0)
 
        {
 
          *error_message = "cannot extract CALLXn operands for TLS access";
 
          return FALSE;
 
        }
 
      break;
 
 
 
    default:
 
      abort ();
 
    }
 
 
 
  if (is_ld_model)
 
    {
 
      switch (r_type)
 
        {
 
        case R_XTENSA_TLS_FUNC:
 
        case R_XTENSA_TLS_ARG:
 
          /* Change the instruction to a NOP (or "OR a1, a1, a1" for older
 
             versions of Xtensa).  */
 
          new_op = xtensa_opcode_lookup (isa, "nop");
 
          if (new_op == XTENSA_UNDEFINED)
 
            {
 
              new_op = xtensa_opcode_lookup (isa, "or");
 
              if (new_op == XTENSA_UNDEFINED
 
                  || xtensa_opcode_encode (isa, fmt, 0, sbuff, new_op) != 0
 
                  || xtensa_operand_set_field (isa, new_op, 0, fmt, 0,
 
                                               sbuff, 1) != 0
 
                  || xtensa_operand_set_field (isa, new_op, 1, fmt, 0,
 
                                               sbuff, 1) != 0
 
                  || xtensa_operand_set_field (isa, new_op, 2, fmt, 0,
 
                                               sbuff, 1) != 0)
 
                {
 
                  *error_message = "cannot encode OR for TLS access";
 
                  return FALSE;
 
                }
 
            }
 
          else
 
            {
 
              if (xtensa_opcode_encode (isa, fmt, 0, sbuff, new_op) != 0)
 
                {
 
                  *error_message = "cannot encode NOP for TLS access";
 
                  return FALSE;
 
                }
}
}
 
          break;
 
 
 
        case R_XTENSA_TLS_CALL:
/* Set up an entry in the procedure linkage table.  */
          /* Read THREADPTR into the CALLX's return value register.  */
 
          new_op = xtensa_opcode_lookup (isa, "rur.threadptr");
static bfd_vma
          if (new_op == XTENSA_UNDEFINED
elf_xtensa_create_plt_entry (struct bfd_link_info *info,
              || xtensa_opcode_encode (isa, fmt, 0, sbuff, new_op) != 0
                             bfd *output_bfd,
              || xtensa_operand_set_field (isa, new_op, 0, fmt, 0,
                             unsigned reloc_index)
                                           sbuff, dest_reg + 2) != 0)
{
{
  asection *splt, *sgotplt;
              *error_message = "cannot encode RUR.THREADPTR for TLS access";
  bfd_vma plt_base, got_base;
              return FALSE;
  bfd_vma code_offset, lit_offset;
            }
  int chunk;
          break;
 
        }
  chunk = reloc_index / PLT_ENTRIES_PER_CHUNK;
    }
  splt = elf_xtensa_get_plt_section (info, chunk);
  else
  sgotplt = elf_xtensa_get_gotplt_section (info, chunk);
    {
  BFD_ASSERT (splt != NULL && sgotplt != NULL);
      switch (r_type)
 
        {
  plt_base = splt->output_section->vma + splt->output_offset;
        case R_XTENSA_TLS_FUNC:
  got_base = sgotplt->output_section->vma + sgotplt->output_offset;
          new_op = xtensa_opcode_lookup (isa, "rur.threadptr");
 
          if (new_op == XTENSA_UNDEFINED
 
              || xtensa_opcode_encode (isa, fmt, 0, sbuff, new_op) != 0
 
              || xtensa_operand_set_field (isa, new_op, 0, fmt, 0,
 
                                           sbuff, dest_reg) != 0)
 
            {
 
              *error_message = "cannot encode RUR.THREADPTR for TLS access";
 
              return FALSE;
 
            }
 
          break;
 
 
  lit_offset = 8 + (reloc_index % PLT_ENTRIES_PER_CHUNK) * 4;
        case R_XTENSA_TLS_ARG:
  code_offset = (reloc_index % PLT_ENTRIES_PER_CHUNK) * PLT_ENTRY_SIZE;
          /* Nothing to do.  Keep the original L32R instruction.  */
 
          return TRUE;
 
 
  /* Fill in the literal entry.  This is the offset of the dynamic
        case R_XTENSA_TLS_CALL:
     relocation entry.  */
          /* Add the CALLX's src register (holding the THREADPTR value)
  bfd_put_32 (output_bfd, reloc_index * sizeof (Elf32_External_Rela),
             to the first argument register (holding the offset) and put
              sgotplt->contents + lit_offset);
             the result in the CALLX's return value register.  */
 
          new_op = xtensa_opcode_lookup (isa, "add");
 
          if (new_op == XTENSA_UNDEFINED
 
              || xtensa_opcode_encode (isa, fmt, 0, sbuff, new_op) != 0
 
              || xtensa_operand_set_field (isa, new_op, 0, fmt, 0,
 
                                           sbuff, dest_reg + 2) != 0
 
              || xtensa_operand_set_field (isa, new_op, 1, fmt, 0,
 
                                           sbuff, dest_reg + 2) != 0
 
              || xtensa_operand_set_field (isa, new_op, 2, fmt, 0,
 
                                           sbuff, src_reg) != 0)
 
            {
 
              *error_message = "cannot encode ADD for TLS access";
 
              return FALSE;
 
            }
 
          break;
 
        }
 
    }
 
 
  /* Fill in the entry in the procedure linkage table.  */
  xtensa_format_set_slot (isa, fmt, 0, ibuff, sbuff);
  memcpy (splt->contents + code_offset,
  xtensa_insnbuf_to_chars (isa, ibuff, contents + rel->r_offset,
          (bfd_big_endian (output_bfd)
                           input_size - rel->r_offset);
           ? elf_xtensa_be_plt_entry
 
           : elf_xtensa_le_plt_entry),
 
          PLT_ENTRY_SIZE);
 
  bfd_put_16 (output_bfd, l32r_offset (got_base + 0,
 
                                       plt_base + code_offset + 3),
 
              splt->contents + code_offset + 4);
 
  bfd_put_16 (output_bfd, l32r_offset (got_base + 4,
 
                                       plt_base + code_offset + 6),
 
              splt->contents + code_offset + 7);
 
  bfd_put_16 (output_bfd, l32r_offset (got_base + lit_offset,
 
                                       plt_base + code_offset + 9),
 
              splt->contents + code_offset + 10);
 
 
 
  return plt_base + code_offset;
  return TRUE;
}
}
 
 
 
 
 
#define IS_XTENSA_TLS_RELOC(R_TYPE) \
 
  ((R_TYPE) == R_XTENSA_TLSDESC_FN \
 
   || (R_TYPE) == R_XTENSA_TLSDESC_ARG \
 
   || (R_TYPE) == R_XTENSA_TLS_DTPOFF \
 
   || (R_TYPE) == R_XTENSA_TLS_TPOFF \
 
   || (R_TYPE) == R_XTENSA_TLS_FUNC \
 
   || (R_TYPE) == R_XTENSA_TLS_ARG \
 
   || (R_TYPE) == R_XTENSA_TLS_CALL)
 
 
/* Relocate an Xtensa ELF section.  This is invoked by the linker for
/* Relocate an Xtensa ELF section.  This is invoked by the linker for
   both relocatable and final links.  */
   both relocatable and final links.  */
 
 
static bfd_boolean
static bfd_boolean
elf_xtensa_relocate_section (bfd *output_bfd,
elf_xtensa_relocate_section (bfd *output_bfd,
Line 1953... Line 2534...
  Elf_Internal_Rela *rel;
  Elf_Internal_Rela *rel;
  Elf_Internal_Rela *relend;
  Elf_Internal_Rela *relend;
  struct elf_link_hash_entry **sym_hashes;
  struct elf_link_hash_entry **sym_hashes;
  property_table_entry *lit_table = 0;
  property_table_entry *lit_table = 0;
  int ltblsize = 0;
  int ltblsize = 0;
 
  char *local_got_tls_types;
  char *error_message = NULL;
  char *error_message = NULL;
  bfd_size_type input_size;
  bfd_size_type input_size;
 
  int tls_type;
 
 
  if (!xtensa_default_isa)
  if (!xtensa_default_isa)
    xtensa_default_isa = xtensa_isa_init (0, 0);
    xtensa_default_isa = xtensa_isa_init (0, 0);
 
 
 
  BFD_ASSERT (is_xtensa_elf (input_bfd));
 
 
  htab = elf_xtensa_hash_table (info);
  htab = elf_xtensa_hash_table (info);
  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
  sym_hashes = elf_sym_hashes (input_bfd);
  sym_hashes = elf_sym_hashes (input_bfd);
 
  local_got_tls_types = elf_xtensa_local_got_tls_type (input_bfd);
 
 
  if (elf_hash_table (info)->dynamic_sections_created)
  if (elf_hash_table (info)->dynamic_sections_created)
    {
    {
      ltblsize = xtensa_read_table_entries (input_bfd, input_section,
      ltblsize = xtensa_read_table_entries (input_bfd, input_section,
                                            &lit_table, XTENSA_LIT_SEC_NAME,
                                            &lit_table, XTENSA_LIT_SEC_NAME,
Line 1983... Line 2569...
      int r_type;
      int r_type;
      reloc_howto_type *howto;
      reloc_howto_type *howto;
      unsigned long r_symndx;
      unsigned long r_symndx;
      struct elf_link_hash_entry *h;
      struct elf_link_hash_entry *h;
      Elf_Internal_Sym *sym;
      Elf_Internal_Sym *sym;
 
      char sym_type;
 
      const char *name;
      asection *sec;
      asection *sec;
      bfd_vma relocation;
      bfd_vma relocation;
      bfd_reloc_status_type r;
      bfd_reloc_status_type r;
      bfd_boolean is_weak_undef;
      bfd_boolean is_weak_undef;
      bfd_boolean unresolved_reloc;
      bfd_boolean unresolved_reloc;
      bfd_boolean warned;
      bfd_boolean warned;
 
      bfd_boolean dynamic_symbol;
 
 
      r_type = ELF32_R_TYPE (rel->r_info);
      r_type = ELF32_R_TYPE (rel->r_info);
      if (r_type == (int) R_XTENSA_GNU_VTINHERIT
      if (r_type == (int) R_XTENSA_GNU_VTINHERIT
          || r_type == (int) R_XTENSA_GNU_VTENTRY)
          || r_type == (int) R_XTENSA_GNU_VTENTRY)
        continue;
        continue;
Line 2024... Line 2613...
        }
        }
 
 
      if (r_symndx < symtab_hdr->sh_info)
      if (r_symndx < symtab_hdr->sh_info)
        {
        {
          sym = local_syms + r_symndx;
          sym = local_syms + r_symndx;
 
          sym_type = ELF32_ST_TYPE (sym->st_info);
          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);
        }
        }
      else
      else
        {
        {
Line 2038... Line 2628...
 
 
          if (relocation == 0
          if (relocation == 0
              && !unresolved_reloc
              && !unresolved_reloc
              && h->root.type == bfd_link_hash_undefweak)
              && h->root.type == bfd_link_hash_undefweak)
            is_weak_undef = TRUE;
            is_weak_undef = TRUE;
 
 
 
          sym_type = h->type;
        }
        }
 
 
      if (sec != NULL && elf_discarded_section (sec))
      if (sec != NULL && elf_discarded_section (sec))
        {
        {
          /* For relocs against symbols from removed linkonce sections,
          /* For relocs against symbols from removed linkonce sections,
Line 2149... Line 2741...
             input_bfd, input_section, rel->r_offset, input_size);
             input_bfd, input_section, rel->r_offset, input_size);
          bfd_set_error (bfd_error_bad_value);
          bfd_set_error (bfd_error_bad_value);
          return FALSE;
          return FALSE;
        }
        }
 
 
      /* Generate dynamic relocations.  */
      if (h != NULL)
      if (elf_hash_table (info)->dynamic_sections_created)
        name = h->root.root.string;
 
      else
        {
        {
          bfd_boolean dynamic_symbol = elf_xtensa_dynamic_symbol_p (h, info);
          name = (bfd_elf_string_from_elf_section
 
                  (input_bfd, symtab_hdr->sh_link, sym->st_name));
 
          if (name == NULL || *name == '\0')
 
            name = bfd_section_name (input_bfd, sec);
 
        }
 
 
          if (dynamic_symbol && (is_operand_relocation (r_type)
      if (r_symndx != 0
                                 || r_type == R_XTENSA_32_PCREL))
          && r_type != R_XTENSA_NONE
 
          && (h == NULL
 
              || h->root.type == bfd_link_hash_defined
 
              || h->root.type == bfd_link_hash_defweak)
 
          && IS_XTENSA_TLS_RELOC (r_type) != (sym_type == STT_TLS))
            {
            {
              const char *name = h->root.root.string;
          (*_bfd_error_handler)
              error_message =
            ((sym_type == STT_TLS
                vsprint_msg ("invalid relocation for dynamic symbol", ": %s",
              ? _("%B(%A+0x%lx): %s used with TLS symbol %s")
                             strlen (name) + 2, name);
              : _("%B(%A+0x%lx): %s used with non-TLS symbol %s")),
              if (!((*info->callbacks->reloc_dangerous)
             input_bfd,
                    (info, error_message, input_bfd, input_section,
             input_section,
                     rel->r_offset)))
             (long) rel->r_offset,
                return FALSE;
             howto->name,
              continue;
             name);
            }
            }
          else if ((r_type == R_XTENSA_32 || r_type == R_XTENSA_PLT)
 
 
      dynamic_symbol = elf_xtensa_dynamic_symbol_p (h, info);
 
 
 
      tls_type = GOT_UNKNOWN;
 
      if (h)
 
        tls_type = elf_xtensa_hash_entry (h)->tls_type;
 
      else if (local_got_tls_types)
 
        tls_type = local_got_tls_types [r_symndx];
 
 
 
      switch (r_type)
 
        {
 
        case R_XTENSA_32:
 
        case R_XTENSA_PLT:
 
          if (elf_hash_table (info)->dynamic_sections_created
                   && (input_section->flags & SEC_ALLOC) != 0
                   && (input_section->flags & SEC_ALLOC) != 0
                   && (dynamic_symbol || info->shared))
                   && (dynamic_symbol || info->shared))
            {
            {
              Elf_Internal_Rela outrel;
              Elf_Internal_Rela outrel;
              bfd_byte *loc;
              bfd_byte *loc;
Line 2253... Line 2867...
              /* This should only happen for non-PIC code, which is not
              /* This should only happen for non-PIC code, which is not
                 supposed to be used on systems with dynamic linking.
                 supposed to be used on systems with dynamic linking.
                 Just ignore these relocations.  */
                 Just ignore these relocations.  */
              continue;
              continue;
            }
            }
 
          break;
 
 
 
        case R_XTENSA_TLS_TPOFF:
 
          /* Switch to LE model for local symbols in an executable.  */
 
          if (! info->shared && ! dynamic_symbol)
 
            {
 
              relocation = tpoff (info, relocation);
 
              break;
 
            }
 
          /* fall through */
 
 
 
        case R_XTENSA_TLSDESC_FN:
 
        case R_XTENSA_TLSDESC_ARG:
 
          {
 
            if (r_type == R_XTENSA_TLSDESC_FN)
 
              {
 
                if (! info->shared || (tls_type & GOT_TLS_IE) != 0)
 
                  r_type = R_XTENSA_NONE;
 
              }
 
            else if (r_type == R_XTENSA_TLSDESC_ARG)
 
              {
 
                if (info->shared)
 
                  {
 
                    if ((tls_type & GOT_TLS_IE) != 0)
 
                      r_type = R_XTENSA_TLS_TPOFF;
 
                  }
 
                else
 
                  {
 
                    r_type = R_XTENSA_TLS_TPOFF;
 
                    if (! dynamic_symbol)
 
                      {
 
                        relocation = tpoff (info, relocation);
 
                        break;
 
                      }
 
                  }
 
              }
 
 
 
            if (r_type == R_XTENSA_NONE)
 
              /* Nothing to do here; skip to the next reloc.  */
 
              continue;
 
 
 
            if (! elf_hash_table (info)->dynamic_sections_created)
 
              {
 
                error_message =
 
                  _("TLS relocation invalid without dynamic sections");
 
                if (!((*info->callbacks->reloc_dangerous)
 
                      (info, error_message, input_bfd, input_section,
 
                       rel->r_offset)))
 
                  return FALSE;
 
              }
 
            else
 
              {
 
                Elf_Internal_Rela outrel;
 
                bfd_byte *loc;
 
                asection *srel = htab->srelgot;
 
                int indx;
 
 
 
                outrel.r_offset = (input_section->output_section->vma
 
                                   + input_section->output_offset
 
                                   + rel->r_offset);
 
 
 
                /* Complain if the relocation is in a read-only section
 
                   and not in a literal pool.  */
 
                if ((input_section->flags & SEC_READONLY) != 0
 
                    && ! elf_xtensa_in_literal_pool (lit_table, ltblsize,
 
                                                     outrel.r_offset))
 
                  {
 
                    error_message =
 
                      _("dynamic relocation in read-only section");
 
                    if (!((*info->callbacks->reloc_dangerous)
 
                          (info, error_message, input_bfd, input_section,
 
                           rel->r_offset)))
 
                      return FALSE;
 
                  }
 
 
 
                indx = h && h->dynindx != -1 ? h->dynindx : 0;
 
                if (indx == 0)
 
                  outrel.r_addend = relocation - dtpoff_base (info);
 
                else
 
                  outrel.r_addend = 0;
 
                rel->r_addend = 0;
 
 
 
                outrel.r_info = ELF32_R_INFO (indx, r_type);
 
                relocation = 0;
 
                unresolved_reloc = FALSE;
 
 
 
                BFD_ASSERT (srel);
 
                loc = (srel->contents
 
                       + srel->reloc_count++ * sizeof (Elf32_External_Rela));
 
                bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
 
                BFD_ASSERT (sizeof (Elf32_External_Rela) * srel->reloc_count
 
                            <= srel->size);
 
              }
 
          }
 
          break;
 
 
 
        case R_XTENSA_TLS_DTPOFF:
 
          if (! info->shared)
 
            /* Switch from LD model to LE model.  */
 
            relocation = tpoff (info, relocation);
 
          else
 
            relocation -= dtpoff_base (info);
 
          break;
 
 
 
        case R_XTENSA_TLS_FUNC:
 
        case R_XTENSA_TLS_ARG:
 
        case R_XTENSA_TLS_CALL:
 
          /* Check if optimizing to IE or LE model.  */
 
          if ((tls_type & GOT_TLS_IE) != 0)
 
            {
 
              bfd_boolean is_ld_model =
 
                (h && elf_xtensa_hash_entry (h) == htab->tlsbase);
 
              if (! replace_tls_insn (rel, input_bfd, input_section, contents,
 
                                      is_ld_model, &error_message))
 
                {
 
                  if (!((*info->callbacks->reloc_dangerous)
 
                        (info, error_message, input_bfd, input_section,
 
                         rel->r_offset)))
 
                    return FALSE;
 
                }
 
 
 
              if (r_type != R_XTENSA_TLS_ARG || is_ld_model)
 
                {
 
                  /* Skip subsequent relocations on the same instruction.  */
 
                  while (rel + 1 < relend && rel[1].r_offset == rel->r_offset)
 
                    rel++;
 
                }
 
            }
 
          continue;
 
 
 
        default:
 
          if (elf_hash_table (info)->dynamic_sections_created
 
              && dynamic_symbol && (is_operand_relocation (r_type)
 
                                    || r_type == R_XTENSA_32_PCREL))
 
            {
 
              error_message =
 
                vsprint_msg ("invalid relocation for dynamic symbol", ": %s",
 
                             strlen (name) + 2, name);
 
              if (!((*info->callbacks->reloc_dangerous)
 
                    (info, error_message, input_bfd, input_section,
 
                     rel->r_offset)))
 
                return FALSE;
 
              continue;
 
            }
 
          break;
        }
        }
 
 
      /* Dynamic relocs are not propagated for SEC_DEBUGGING sections
      /* Dynamic relocs are not propagated for SEC_DEBUGGING sections
         because such sections are not SEC_ALLOC and thus ld.so will
         because such sections are not SEC_ALLOC and thus ld.so will
         not process them.  */
         not process them.  */
Line 2268... Line 3027...
            (_("%B(%A+0x%lx): unresolvable %s relocation against symbol `%s'"),
            (_("%B(%A+0x%lx): unresolvable %s relocation against symbol `%s'"),
             input_bfd,
             input_bfd,
             input_section,
             input_section,
             (long) rel->r_offset,
             (long) rel->r_offset,
             howto->name,
             howto->name,
             h->root.root.string);
             name);
          return FALSE;
          return FALSE;
        }
        }
 
 
 
      /* TLS optimizations may have changed r_type; update "howto".  */
 
      howto = &elf_howto_table[r_type];
 
 
      /* There's no point in calling bfd_perform_relocation here.
      /* There's no point in calling bfd_perform_relocation here.
         Just go directly to our "special function".  */
         Just go directly to our "special function".  */
      r = elf_xtensa_do_reloc (howto, input_bfd, input_section,
      r = elf_xtensa_do_reloc (howto, input_bfd, input_section,
                               relocation + rel->r_addend,
                               relocation + rel->r_addend,
                               contents, rel->r_offset, is_weak_undef,
                               contents, rel->r_offset, is_weak_undef,
                               &error_message);
                               &error_message);
 
 
      if (r != bfd_reloc_ok && !warned)
      if (r != bfd_reloc_ok && !warned)
        {
        {
          const char *name;
 
 
 
          BFD_ASSERT (r == bfd_reloc_dangerous || r == bfd_reloc_other);
          BFD_ASSERT (r == bfd_reloc_dangerous || r == bfd_reloc_other);
          BFD_ASSERT (error_message != NULL);
          BFD_ASSERT (error_message != NULL);
 
 
          if (h)
 
            name = h->root.root.string;
 
          else
 
            {
 
              name = bfd_elf_string_from_elf_section
 
                (input_bfd, symtab_hdr->sh_link, sym->st_name);
 
              if (name && *name == '\0')
 
                name = bfd_section_name (input_bfd, sec);
 
            }
 
          if (name)
 
            {
 
              if (rel->r_addend == 0)
              if (rel->r_addend == 0)
                error_message = vsprint_msg (error_message, ": %s",
                error_message = vsprint_msg (error_message, ": %s",
                                             strlen (name) + 2, name);
                                             strlen (name) + 2, name);
              else
              else
                error_message = vsprint_msg (error_message, ": (%s+0x%x)",
                error_message = vsprint_msg (error_message, ": (%s+0x%x)",
                                             strlen (name) + 22,
                                             strlen (name) + 22,
                                             name, (int)rel->r_addend);
                                             name, (int)rel->r_addend);
            }
 
 
 
          if (!((*info->callbacks->reloc_dangerous)
          if (!((*info->callbacks->reloc_dangerous)
                (info, error_message, input_bfd, input_section,
                (info, error_message, input_bfd, input_section,
                 rel->r_offset)))
                 rel->r_offset)))
            return FALSE;
            return FALSE;
Line 3108... Line 3856...
          || opcode == callx8_op
          || opcode == callx8_op
          || opcode == callx12_op);
          || opcode == callx12_op);
}
}
 
 
 
 
 
static bfd_boolean
 
get_indirect_call_dest_reg (xtensa_opcode opcode, unsigned *pdst)
 
{
 
  unsigned dst = (unsigned) -1;
 
 
 
  init_call_opcodes ();
 
  if (opcode == callx0_op)
 
    dst = 0;
 
  else if (opcode == callx4_op)
 
    dst = 4;
 
  else if (opcode == callx8_op)
 
    dst = 8;
 
  else if (opcode == callx12_op)
 
    dst = 12;
 
 
 
  if (dst == (unsigned) -1)
 
    return FALSE;
 
 
 
  *pdst = dst;
 
  return TRUE;
 
}
 
 
 
 
static xtensa_opcode
static xtensa_opcode
get_const16_opcode (void)
get_const16_opcode (void)
{
{
  static bfd_boolean done_lookup = FALSE;
  static bfd_boolean done_lookup = FALSE;
  static xtensa_opcode const16_opcode = XTENSA_UNDEFINED;
  static xtensa_opcode const16_opcode = XTENSA_UNDEFINED;
Line 4701... Line 5472...
    return;
    return;
 
 
  for (m_p = &l->head; *m_p && (*m_p)->offset <= offset; m_p = &(*m_p)->next)
  for (m_p = &l->head; *m_p && (*m_p)->offset <= offset; m_p = &(*m_p)->next)
    {
    {
      text_action *t = *m_p;
      text_action *t = *m_p;
 
 
 
      if (action == ta_fill)
 
        {
      /* When the action is another fill at the same address,
      /* When the action is another fill at the same address,
         just increase the size.  */
         just increase the size.  */
      if (t->offset == offset && t->action == ta_fill && action == ta_fill)
          if (t->offset == offset && t->action == ta_fill)
        {
        {
          t->removed_bytes += removed;
          t->removed_bytes += removed;
          return;
          return;
        }
        }
 
          /* Fills need to happen before widens so that we don't
 
             insert fill bytes into the instruction stream.  */
 
          if (t->offset == offset && t->action == ta_widen_insn)
 
            break;
 
        }
    }
    }
 
 
  /* Create a new record and fill it up.  */
  /* Create a new record and fill it up.  */
  ta = (text_action *) bfd_zmalloc (sizeof (text_action));
  ta = (text_action *) bfd_zmalloc (sizeof (text_action));
  ta->action = action;
  ta->action = action;
Line 9230... Line 10009...
            }
            }
 
 
          if (remove_this_rel)
          if (remove_this_rel)
            {
            {
              offset_rel->r_info = ELF32_R_INFO (0, R_XTENSA_NONE);
              offset_rel->r_info = ELF32_R_INFO (0, R_XTENSA_NONE);
              /* In case this is the last entry, move the relocation offset
 
                 to the previous entry, if there is one.  */
 
              if (offset_rel->r_offset >= bytes_to_remove)
 
                offset_rel->r_offset -= bytes_to_remove;
 
              else
 
                offset_rel->r_offset = 0;
                offset_rel->r_offset = 0;
            }
            }
 
 
          if (bytes_to_remove != 0)
          if (bytes_to_remove != 0)
            {
            {
Line 9501... Line 10275...
      isymbuf = retrieve_local_syms (abfd);
      isymbuf = retrieve_local_syms (abfd);
      section_index = isymbuf[r_symndx].st_shndx;
      section_index = isymbuf[r_symndx].st_shndx;
 
 
      if (section_index == SHN_UNDEF)
      if (section_index == SHN_UNDEF)
        target_sec = bfd_und_section_ptr;
        target_sec = bfd_und_section_ptr;
      else if (section_index > 0 && section_index < SHN_LORESERVE)
 
        target_sec = bfd_section_from_elf_index (abfd, section_index);
 
      else if (section_index == SHN_ABS)
      else if (section_index == SHN_ABS)
        target_sec = bfd_abs_section_ptr;
        target_sec = bfd_abs_section_ptr;
      else if (section_index == SHN_COMMON)
      else if (section_index == SHN_COMMON)
        target_sec = bfd_com_section_ptr;
        target_sec = bfd_com_section_ptr;
      else
      else
        /* Who knows?  */
        target_sec = bfd_section_from_elf_index (abfd, section_index);
        target_sec = NULL;
 
    }
    }
  else
  else
    {
    {
      unsigned long indx = r_symndx - symtab_hdr->sh_info;
      unsigned long indx = r_symndx - symtab_hdr->sh_info;
      struct elf_link_hash_entry *h = elf_sym_hashes (abfd)[indx];
      struct elf_link_hash_entry *h = elf_sym_hashes (abfd)[indx];
Line 9717... Line 10488...
}
}
 
 
 
 
static int linkonce_len = sizeof (".gnu.linkonce.") - 1;
static int linkonce_len = sizeof (".gnu.linkonce.") - 1;
 
 
asection *
static char *
xtensa_get_property_section (asection *sec, const char *base_name)
xtensa_property_section_name (asection *sec, const char *base_name)
{
{
  const char *suffix, *group_name;
  const char *suffix, *group_name;
  char *prop_sec_name;
  char *prop_sec_name;
  asection *prop_sec;
 
 
 
  group_name = elf_group_name (sec);
  group_name = elf_group_name (sec);
  if (group_name)
  if (group_name)
    {
    {
      suffix = strrchr (sec->name, '.');
      suffix = strrchr (sec->name, '.');
Line 9764... Line 10534...
      strcat (prop_sec_name + linkonce_len, suffix);
      strcat (prop_sec_name + linkonce_len, suffix);
    }
    }
  else
  else
    prop_sec_name = strdup (base_name);
    prop_sec_name = strdup (base_name);
 
 
 
  return prop_sec_name;
 
}
 
 
 
 
 
static asection *
 
xtensa_get_property_section (asection *sec, const char *base_name)
 
{
 
  char *prop_sec_name;
 
  asection *prop_sec;
 
 
 
  prop_sec_name = xtensa_property_section_name (sec, base_name);
 
  prop_sec = bfd_get_section_by_name_if (sec->owner, prop_sec_name,
 
                                         match_section_group,
 
                                         (void *) elf_group_name (sec));
 
  free (prop_sec_name);
 
  return prop_sec;
 
}
 
 
 
 
 
asection *
 
xtensa_make_property_section (asection *sec, const char *base_name)
 
{
 
  char *prop_sec_name;
 
  asection *prop_sec;
 
 
  /* Check if the section already exists.  */
  /* Check if the section already exists.  */
 
  prop_sec_name = xtensa_property_section_name (sec, base_name);
  prop_sec = bfd_get_section_by_name_if (sec->owner, prop_sec_name,
  prop_sec = bfd_get_section_by_name_if (sec->owner, prop_sec_name,
                                         match_section_group,
                                         match_section_group,
                                         (void *) group_name);
                                         (void *) elf_group_name (sec));
  /* If not, create it.  */
  /* If not, create it.  */
  if (! prop_sec)
  if (! prop_sec)
    {
    {
      flagword flags = (SEC_RELOC | SEC_HAS_CONTENTS | SEC_READONLY);
      flagword flags = (SEC_RELOC | SEC_HAS_CONTENTS | SEC_READONLY);
      flags |= (bfd_get_section_flags (sec->owner, sec)
      flags |= (bfd_get_section_flags (sec->owner, sec)
Line 9780... Line 10576...
      prop_sec = bfd_make_section_anyway_with_flags
      prop_sec = bfd_make_section_anyway_with_flags
        (sec->owner, strdup (prop_sec_name), flags);
        (sec->owner, strdup (prop_sec_name), flags);
      if (! prop_sec)
      if (! prop_sec)
        return 0;
        return 0;
 
 
      elf_group_name (prop_sec) = group_name;
      elf_group_name (prop_sec) = elf_group_name (sec);
    }
    }
 
 
  free (prop_sec_name);
  free (prop_sec_name);
  return prop_sec;
  return prop_sec;
}
}
Line 9940... Line 10736...
#define elf_backend_want_dynbss         0
#define elf_backend_want_dynbss         0
#define elf_backend_want_got_plt        1
#define elf_backend_want_got_plt        1
 
 
#define elf_info_to_howto                    elf_xtensa_info_to_howto_rela
#define elf_info_to_howto                    elf_xtensa_info_to_howto_rela
 
 
 
#define bfd_elf32_mkobject                   elf_xtensa_mkobject
 
 
#define bfd_elf32_bfd_merge_private_bfd_data elf_xtensa_merge_private_bfd_data
#define bfd_elf32_bfd_merge_private_bfd_data elf_xtensa_merge_private_bfd_data
#define bfd_elf32_new_section_hook           elf_xtensa_new_section_hook
#define bfd_elf32_new_section_hook           elf_xtensa_new_section_hook
#define bfd_elf32_bfd_print_private_bfd_data elf_xtensa_print_private_bfd_data
#define bfd_elf32_bfd_print_private_bfd_data elf_xtensa_print_private_bfd_data
#define bfd_elf32_bfd_relax_section          elf_xtensa_relax_section
#define bfd_elf32_bfd_relax_section          elf_xtensa_relax_section
#define bfd_elf32_bfd_reloc_type_lookup      elf_xtensa_reloc_type_lookup
#define bfd_elf32_bfd_reloc_type_lookup      elf_xtensa_reloc_type_lookup
Line 9967... Line 10765...
#define elf_backend_hide_symbol              elf_xtensa_hide_symbol
#define elf_backend_hide_symbol              elf_xtensa_hide_symbol
#define elf_backend_object_p                 elf_xtensa_object_p
#define elf_backend_object_p                 elf_xtensa_object_p
#define elf_backend_reloc_type_class         elf_xtensa_reloc_type_class
#define elf_backend_reloc_type_class         elf_xtensa_reloc_type_class
#define elf_backend_relocate_section         elf_xtensa_relocate_section
#define elf_backend_relocate_section         elf_xtensa_relocate_section
#define elf_backend_size_dynamic_sections    elf_xtensa_size_dynamic_sections
#define elf_backend_size_dynamic_sections    elf_xtensa_size_dynamic_sections
 
#define elf_backend_always_size_sections     elf_xtensa_always_size_sections
#define elf_backend_omit_section_dynsym \
#define elf_backend_omit_section_dynsym \
  ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true)
  ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true)
#define elf_backend_special_sections         elf_xtensa_special_sections
#define elf_backend_special_sections         elf_xtensa_special_sections
#define elf_backend_action_discarded         elf_xtensa_action_discarded
#define elf_backend_action_discarded         elf_xtensa_action_discarded
 
#define elf_backend_copy_indirect_symbol     elf_xtensa_copy_indirect_symbol
 
 
#include "elf32-target.h"
#include "elf32-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.