Back to index

cell-binutils  2.17cvs20070401
Classes | Defines | Functions | Variables
elf32-spu.c File Reference
#include "bfd.h"
#include "sysdep.h"
#include "bfdlink.h"
#include "libbfd.h"
#include "elf-bfd.h"
#include "elf/spu.h"
#include "elf32-spu.h"
#include "elf32-target.h"

Go to the source code of this file.

Classes

struct  spu_stub_hash_entry
struct  stubarr

Defines

#define spu_hash_table(p)   ((struct spu_link_hash_table *) ((p)->hash))
#define SIZEOF_STUB1   8
#define ILA_79   0x4200004f /* ila $79,function_address */
#define BR   0x32000000 /* br stub2 */
#define SIZEOF_STUB2   8
#define ILA_78   0x4200004e /* ila $78,overlay_number */
#define NOP   0x40200000
#define TARGET_BIG_SYM   bfd_elf32_spu_vec
#define TARGET_BIG_NAME   "elf32-spu"
#define ELF_ARCH   bfd_arch_spu
#define ELF_MACHINE_CODE   EM_SPU
#define ELF_MAXPAGESIZE   0x80
#define elf_backend_rela_normal   1
#define elf_backend_can_gc_sections   1
#define bfd_elf32_bfd_reloc_type_lookup   spu_elf_reloc_type_lookup
#define bfd_elf32_bfd_reloc_name_lookup   spu_elf_reloc_name_lookup
#define elf_info_to_howto   spu_elf_info_to_howto
#define elf_backend_gc_mark_hook   spu_elf_gc_mark_hook
#define elf_backend_relocate_section   spu_elf_relocate_section
#define elf_backend_symbol_processing   spu_elf_backend_symbol_processing
#define bfd_elf32_new_section_hook   spu_elf_new_section_hook
#define bfd_elf32_bfd_link_hash_table_create   spu_elf_link_hash_table_create
#define bfd_elf32_bfd_link_hash_table_free   spu_elf_link_hash_table_free
#define elf_backend_additional_program_headers   spu_elf_additional_program_headers
#define elf_backend_modify_segment_map   spu_elf_modify_segment_map
#define elf_backend_modify_program_headers   spu_elf_modify_program_headers
#define elf_backend_post_process_headers   spu_elf_post_process_headers
#define elf_backend_section_processing   spu_elf_section_processing
#define elf_backend_special_sections   spu_elf_special_sections

Functions

static bfd_reloc_status_type spu_elf_rel9 (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **)
static enum elf_spu_reloc_type spu_elf_bfd_to_reloc_type (bfd_reloc_code_real_type code)
static void spu_elf_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *cache_ptr, Elf_Internal_Rela *dst)
static reloc_howto_type * spu_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, bfd_reloc_code_real_type code)
static reloc_howto_type * spu_elf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name)
static bfd_boolean spu_elf_new_section_hook (bfd *abfd, asection *sec)
static void spu_elf_backend_symbol_processing (bfd *abfd ATTRIBUTE_UNUSED, asymbol *sym)
static struct bfd_hash_entrystub_hash_newfunc (struct bfd_hash_entry *entry, struct bfd_hash_table *table, const char *string)
static struct bfd_link_hash_tablespu_elf_link_hash_table_create (bfd *abfd)
static void spu_elf_link_hash_table_free (struct bfd_link_hash_table *hash)
static bfd_boolean get_sym_h (struct elf_link_hash_entry **hp, Elf_Internal_Sym **symp, asection **symsecp, Elf_Internal_Sym **locsymsp, unsigned long r_symndx, bfd *ibfd)
static char * spu_stub_name (const asection *sym_sec, const struct elf_link_hash_entry *h, const Elf_Internal_Rela *rel)
bfd_boolean spu_elf_create_sections (bfd *output_bfd, struct bfd_link_info *info)
static asectionspu_elf_gc_mark_hook (asection *sec, struct bfd_link_info *info ATTRIBUTE_UNUSED, Elf_Internal_Rela *rel ATTRIBUTE_UNUSED, struct elf_link_hash_entry *h, Elf_Internal_Sym *sym)
static int sort_sections (const void *a, const void *b)
bfd_boolean spu_elf_find_overlays (bfd *output_bfd, struct bfd_link_info *info)
static bfd_boolean is_branch (const unsigned char *insn)
static bfd_boolean needs_ovl_stub (const char *sym_name, asection *sym_sec, asection *input_section, struct spu_link_hash_table *htab, bfd_boolean is_branch)
static bfd_boolean allocate_spuear_stubs (struct elf_link_hash_entry *h, void *inf)
static bfd_boolean populate_stubs (struct bfd_hash_entry *bh, void *inf)
static int sort_stubs (const void *a, const void *b)
bfd_boolean spu_elf_size_stubs (bfd *output_bfd, struct bfd_link_info *info, int non_overlay_stubs, asection **stub, asection **ovtab, asection **toe)
static void * ovl_mgr_open (struct bfd *nbfd ATTRIBUTE_UNUSED, void *stream)
static file_ptr ovl_mgr_pread (struct bfd *abfd ATTRIBUTE_UNUSED, void *stream, void *buf, file_ptr nbytes, file_ptr offset)
bfd_boolean spu_elf_open_builtin_lib (bfd **ovl_bfd, const struct _ovl_stream *stream)
static bfd_boolean write_one_stub (struct bfd_hash_entry *bh, void *inf)
static struct elf_link_hash_entrydefine_ovtab_symbol (struct spu_link_hash_table *htab, const char *name)
bfd_boolean spu_elf_build_stubs (struct bfd_link_info *info, int emit_syms, asection *toe)
static bfd_boolean spu_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, bfd *input_bfd, asection *input_section, bfd_byte *contents, Elf_Internal_Rela *relocs, Elf_Internal_Sym *local_syms, asection **local_sections)
void spu_elf_plugin (int val)
static void spu_elf_post_process_headers (bfd *abfd, struct bfd_link_info *info ATTRIBUTE_UNUSED)
static int spu_elf_additional_program_headers (bfd *abfd, struct bfd_link_info *info)
static bfd_boolean spu_elf_modify_segment_map (bfd *abfd, struct bfd_link_info *info)
asectionspu_elf_check_vma (bfd *abfd, bfd_vma lo, bfd_vma hi)
static int spu_elf_modify_program_headers (bfd *abfd, struct bfd_link_info *info)
static bfd_boolean spu_elf_section_processing (bfd *abfd ATTRIBUTE_UNUSED, Elf_Internal_Shdr *i_shdrp)

Variables

static reloc_howto_type elf_howto_table []
static struct bfd_elf_special_section []
static int spu_plugin = 0

Class Documentation

struct spu_link_hash_table

Definition at line 238 of file elf32-spu.c.

Collaboration diagram for spu_link_hash_table:
Class Members
unsigned int emit_stub_syms:1
unsigned int non_overlay_stubs: 1
unsigned int num_buf
unsigned int num_overlays
asection ** ovl_region
struct elf_link_hash_entry * ovly_load
asection * ovtab
asection * stub
unsigned int stub_overflow: 1
struct spu_stub_hash_entry

Definition at line 279 of file elf32-spu.c.

Collaboration diagram for spu_stub_hash_entry:
Class Members
bfd_vma delta
bfd_vma off
bfd_vma target_off
asection * target_section
struct stubarr

Definition at line 733 of file elf32-spu.c.

Collaboration diagram for stubarr:
Class Members
unsigned int count
int err
struct spu_stub_hash_entry ** sh
struct bfd_hash_table * stub_hash_table

Define Documentation

Definition at line 1834 of file elf32-spu.c.

Definition at line 1835 of file elf32-spu.c.

Definition at line 1828 of file elf32-spu.c.

Definition at line 1827 of file elf32-spu.c.

Definition at line 1833 of file elf32-spu.c.

#define BR   0x32000000 /* br stub2 */

Definition at line 667 of file elf32-spu.c.

#define ELF_ARCH   bfd_arch_spu

Definition at line 1820 of file elf32-spu.c.

Definition at line 1837 of file elf32-spu.c.

Definition at line 1825 of file elf32-spu.c.

Definition at line 1830 of file elf32-spu.c.

Definition at line 1839 of file elf32-spu.c.

Definition at line 1838 of file elf32-spu.c.

Definition at line 1840 of file elf32-spu.c.

#define elf_backend_rela_normal   1

Definition at line 1824 of file elf32-spu.c.

Definition at line 1831 of file elf32-spu.c.

Definition at line 1841 of file elf32-spu.c.

#define elf_backend_special_sections   spu_elf_special_sections

Definition at line 1842 of file elf32-spu.c.

Definition at line 1832 of file elf32-spu.c.

Definition at line 1829 of file elf32-spu.c.

#define ELF_MACHINE_CODE   EM_SPU

Definition at line 1821 of file elf32-spu.c.

#define ELF_MAXPAGESIZE   0x80

Definition at line 1823 of file elf32-spu.c.

#define ILA_78   0x4200004e /* ila $78,overlay_number */

Definition at line 671 of file elf32-spu.c.

#define ILA_79   0x4200004f /* ila $79,function_address */

Definition at line 666 of file elf32-spu.c.

#define NOP   0x40200000

Definition at line 673 of file elf32-spu.c.

#define SIZEOF_STUB1   8

Definition at line 665 of file elf32-spu.c.

#define SIZEOF_STUB2   8

Definition at line 670 of file elf32-spu.c.

#define spu_hash_table (   p)    ((struct spu_link_hash_table *) ((p)->hash))

Definition at line 276 of file elf32-spu.c.

#define TARGET_BIG_NAME   "elf32-spu"

Definition at line 1819 of file elf32-spu.c.

Definition at line 1818 of file elf32-spu.c.


Function Documentation

static bfd_boolean allocate_spuear_stubs ( struct elf_link_hash_entry h,
void *  inf 
) [static]

Definition at line 744 of file elf32-spu.c.

{
  /* Symbols starting with _SPUEAR_ need a stub because they may be
     invoked by the PPU.  */
  if ((h->root.type == bfd_link_hash_defined
       || h->root.type == bfd_link_hash_defweak)
      && h->def_regular
      && strncmp (h->root.root.string, "_SPUEAR_", 8) == 0)
    {
      struct stubarr *stubs = inf;
      static Elf_Internal_Rela zero_rel;
      char *stub_name = spu_stub_name (h->root.u.def.section, h, &zero_rel);
      struct spu_stub_hash_entry *sh;

      if (stub_name == NULL)
       {
         stubs->err = 1;
         return FALSE;
       }

      sh = (struct spu_stub_hash_entry *)
       bfd_hash_lookup (stubs->stub_hash_table, stub_name, TRUE, FALSE);
      if (sh == NULL)
       {
         free (stub_name);
         return FALSE;
       }

      /* If this entry isn't new, we already have a stub.  */
      if (sh->target_section != NULL)
       {
         free (stub_name);
         return TRUE;
       }

      sh->target_section = h->root.u.def.section;
      sh->target_off = h->root.u.def.value;
      stubs->count += 1;
    }
  
  return TRUE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static struct elf_link_hash_entry* define_ovtab_symbol ( struct spu_link_hash_table htab,
const char *  name 
) [static, read]

Definition at line 1268 of file elf32-spu.c.

{
  struct elf_link_hash_entry *h;

  h = elf_link_hash_lookup (&htab->elf, name, TRUE, FALSE, FALSE);
  if (h == NULL)
    return NULL;

  if (h->root.type != bfd_link_hash_defined
      || !h->def_regular)
    {
      h->root.type = bfd_link_hash_defined;
      h->root.u.def.section = htab->ovtab;
      h->type = STT_OBJECT;
      h->ref_regular = 1;
      h->def_regular = 1;
      h->ref_regular_nonweak = 1;
      h->non_elf = 0;
    }
  else
    {
      (*_bfd_error_handler) (_("%B is not allowed to define %s"),
                          h->root.u.def.section->owner,
                          h->root.root.string);
      bfd_set_error (bfd_error_bad_value);
      return NULL;
    }

  return h;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static bfd_boolean get_sym_h ( struct elf_link_hash_entry **  hp,
Elf_Internal_Sym **  symp,
asection **  symsecp,
Elf_Internal_Sym **  locsymsp,
unsigned long  r_symndx,
bfd ibfd 
) [static]

Definition at line 371 of file elf32-spu.c.

{
  Elf_Internal_Shdr *symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;

  if (r_symndx >= symtab_hdr->sh_info)
    {
      struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (ibfd);
      struct elf_link_hash_entry *h;

      h = sym_hashes[r_symndx - symtab_hdr->sh_info];
      while (h->root.type == bfd_link_hash_indirect
            || h->root.type == bfd_link_hash_warning)
       h = (struct elf_link_hash_entry *) h->root.u.i.link;

      if (hp != NULL)
       *hp = h;

      if (symp != NULL)
       *symp = NULL;

      if (symsecp != NULL)
       {
         asection *symsec = NULL;
         if (h->root.type == bfd_link_hash_defined
             || h->root.type == bfd_link_hash_defweak)
           symsec = h->root.u.def.section;
         *symsecp = symsec;
       }
    }
  else
    {
      Elf_Internal_Sym *sym;
      Elf_Internal_Sym *locsyms = *locsymsp;

      if (locsyms == NULL)
       {
         locsyms = (Elf_Internal_Sym *) symtab_hdr->contents;
         if (locsyms == NULL)
           locsyms = bfd_elf_get_elf_syms (ibfd, symtab_hdr,
                                       symtab_hdr->sh_info,
                                       0, NULL, NULL, NULL);
         if (locsyms == NULL)
           return FALSE;
         *locsymsp = locsyms;
       }
      sym = locsyms + r_symndx;

      if (hp != NULL)
       *hp = NULL;

      if (symp != NULL)
       *symp = sym;

      if (symsecp != NULL)
       {
         asection *symsec = NULL;
         if ((sym->st_shndx != SHN_UNDEF
              && sym->st_shndx < SHN_LORESERVE)
             || sym->st_shndx > SHN_HIRESERVE)
           symsec = bfd_section_from_elf_index (ibfd, sym->st_shndx);
         *symsecp = symsec;
       }
    }
  return TRUE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static bfd_boolean is_branch ( const unsigned char *  insn) [static]

Definition at line 688 of file elf32-spu.c.

{
  return (((insn[0] & 0xec) == 0x20 && (insn[1] & 0x80) == 0)
         || (insn[0] & 0xfc) == 0x10);
}

Here is the caller graph for this function:

static bfd_boolean needs_ovl_stub ( const char *  sym_name,
asection sym_sec,
asection input_section,
struct spu_link_hash_table htab,
bfd_boolean  is_branch 
) [static]

Definition at line 697 of file elf32-spu.c.

{
  if (htab->num_overlays == 0)
    return FALSE;

  if (sym_sec == NULL
      || sym_sec->output_section == NULL)
    return FALSE;

  /* setjmp always goes via an overlay stub, because then the return
     and hence the longjmp goes via __ovly_return.  That magically
     makes setjmp/longjmp between overlays work.  */
  if (strncmp (sym_name, "setjmp", 6) == 0
      && (sym_name[6] == '\0' || sym_name[6] == '@'))
    return TRUE;

  /* Usually, symbols in non-overlay sections don't need stubs.  */
  if (spu_elf_section_data (sym_sec->output_section)->ovl_index == 0
      && !htab->non_overlay_stubs)
    return FALSE;

  /* A reference from some other section to a symbol in an overlay
     section needs a stub.  */
  if (spu_elf_section_data (sym_sec->output_section)->ovl_index
       != spu_elf_section_data (input_section->output_section)->ovl_index)
    return TRUE;

  /* If this insn isn't a branch then we are possibly taking the
     address of a function and passing it out somehow.  */
  return !is_branch;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void* ovl_mgr_open ( struct bfd *nbfd  ATTRIBUTE_UNUSED,
void *  stream 
) [static]

Definition at line 1143 of file elf32-spu.c.

{
  return stream;
}

Here is the caller graph for this function:

static file_ptr ovl_mgr_pread ( struct bfd *abfd  ATTRIBUTE_UNUSED,
void *  stream,
void *  buf,
file_ptr  nbytes,
file_ptr  offset 
) [static]

Definition at line 1149 of file elf32-spu.c.

{
  struct _ovl_stream *os;
  size_t count;
  size_t max;

  os = (struct _ovl_stream *) stream;
  max = (const char *) os->end - (const char *) os->start;

  if ((ufile_ptr) offset >= max)
    return 0;

  count = nbytes;
  if (count > max - offset)
    count = max - offset;

  memcpy (buf, (const char *) os->start + offset, count);
  return count;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static bfd_boolean populate_stubs ( struct bfd_hash_entry bh,
void *  inf 
) [static]

Definition at line 791 of file elf32-spu.c.

{
  struct stubarr *stubs = inf;

  stubs->sh[--stubs->count] = (struct spu_stub_hash_entry *) bh;
  return TRUE;
}

Here is the caller graph for this function:

static int sort_sections ( const void *  a,
const void *  b 
) [static]

Definition at line 572 of file elf32-spu.c.

{
  const asection *const *s1 = a;
  const asection *const *s2 = b;
  bfd_signed_vma delta = (*s1)->vma - (*s2)->vma;

  if (delta != 0)
    return delta < 0 ? -1 : 1;

  return (*s1)->index - (*s2)->index;
}

Here is the caller graph for this function:

static int sort_stubs ( const void *  a,
const void *  b 
) [static]

Definition at line 802 of file elf32-spu.c.

{
  const struct spu_stub_hash_entry *const *sa = a;
  const struct spu_stub_hash_entry *const *sb = b;
  int i;
  bfd_signed_vma d;

  i = spu_elf_section_data ((*sa)->target_section->output_section)->ovl_index;
  i -= spu_elf_section_data ((*sb)->target_section->output_section)->ovl_index;
  if (i != 0)
    return i;

  d = ((*sa)->target_section->output_section->vma
       + (*sa)->target_section->output_offset
       + (*sa)->target_off
       - (*sb)->target_section->output_section->vma
       - (*sb)->target_section->output_offset
       - (*sb)->target_off);
  if (d != 0)
    return d < 0 ? -1 : 1;

  /* Two functions at the same address.  Aliases perhaps.  */
  i = strcmp ((*sb)->root.string, (*sa)->root.string);
  BFD_ASSERT (i != 0);
  return i;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int spu_elf_additional_program_headers ( bfd abfd,
struct bfd_link_info info 
) [static]

Definition at line 1619 of file elf32-spu.c.

{
  struct spu_link_hash_table *htab = spu_hash_table (info);
  int extra = htab->num_overlays;
  asection *sec;

  if (extra)
    ++extra;

  sec = bfd_get_section_by_name (abfd, ".toe");
  if (sec != NULL && (sec->flags & SEC_LOAD) != 0)
    ++extra;

  return extra;
}

Here is the call graph for this function:

static void spu_elf_backend_symbol_processing ( bfd *abfd  ATTRIBUTE_UNUSED,
asymbol sym 
) [static]

Definition at line 228 of file elf32-spu.c.

{
  if (sym->name != NULL
      && sym->section != bfd_abs_section_ptr
      && strncmp (sym->name, "_EAR_", 5) == 0)
    sym->flags |= BSF_KEEP;
}

Here is the call graph for this function:

static enum elf_spu_reloc_type spu_elf_bfd_to_reloc_type ( bfd_reloc_code_real_type  code) [static]

Definition at line 89 of file elf32-spu.c.

{
  switch (code)
    {
    default:
      return R_SPU_NONE;
    case BFD_RELOC_SPU_IMM10W:
      return R_SPU_ADDR10;
    case BFD_RELOC_SPU_IMM16W:
      return R_SPU_ADDR16;
    case BFD_RELOC_SPU_LO16:
      return R_SPU_ADDR16_LO;
    case BFD_RELOC_SPU_HI16:
      return R_SPU_ADDR16_HI;
    case BFD_RELOC_SPU_IMM18:
      return R_SPU_ADDR18;
    case BFD_RELOC_SPU_PCREL16:
      return R_SPU_REL16;
    case BFD_RELOC_SPU_IMM7:
      return R_SPU_ADDR7;
    case BFD_RELOC_SPU_IMM8:
      return R_SPU_NONE;
    case BFD_RELOC_SPU_PCREL9a:
      return R_SPU_REL9;
    case BFD_RELOC_SPU_PCREL9b:
      return R_SPU_REL9I;
    case BFD_RELOC_SPU_IMM10:
      return R_SPU_ADDR10I;
    case BFD_RELOC_SPU_IMM16:
      return R_SPU_ADDR16I;
    case BFD_RELOC_32:
      return R_SPU_ADDR32;
    case BFD_RELOC_32_PCREL:
      return R_SPU_REL32;
    }
}

Here is the caller graph for this function:

bfd_boolean spu_elf_build_stubs ( struct bfd_link_info info,
int  emit_syms,
asection toe 
)

Definition at line 1302 of file elf32-spu.c.

{
  struct spu_link_hash_table *htab = spu_hash_table (info);
  struct elf_link_hash_entry *h;
  bfd_byte *p;
  asection *s;
  bfd *obfd;
  unsigned int i;

  htab->emit_stub_syms = emit_syms;
  htab->stub->contents = bfd_zalloc (htab->stub->owner, htab->stub->size);
  if (htab->stub->contents == NULL)
    return FALSE;

  h = elf_link_hash_lookup (&htab->elf, "__ovly_load", FALSE, FALSE, FALSE);
  htab->ovly_load = h;
  BFD_ASSERT (h != NULL
             && (h->root.type == bfd_link_hash_defined
                || h->root.type == bfd_link_hash_defweak)
             && h->def_regular);

  s = h->root.u.def.section->output_section;
  if (spu_elf_section_data (s)->ovl_index)
    {
      (*_bfd_error_handler) (_("%s in overlay section"),
                          h->root.u.def.section->owner);
      bfd_set_error (bfd_error_bad_value);
      return FALSE;
    }

  /* Write out all the stubs.  */
  bfd_hash_traverse (&htab->stub_hash_table, write_one_stub, htab);

  if (htab->stub_overflow)
    {
      (*_bfd_error_handler) (_("overlay stub relocation overflow"));
      bfd_set_error (bfd_error_bad_value);
      return FALSE;
    }

  htab->ovtab->contents = bfd_zalloc (htab->ovtab->owner, htab->ovtab->size);
  if (htab->ovtab->contents == NULL)
    return FALSE;

  /* Write out _ovly_table.  */
  p = htab->ovtab->contents;
  obfd = htab->ovtab->output_section->owner;
  for (s = obfd->sections; s != NULL; s = s->next)
    {
      unsigned int ovl_index = spu_elf_section_data (s)->ovl_index;

      if (ovl_index != 0)
       {
         unsigned int lo, hi, mid;
         unsigned long off = (ovl_index - 1) * 16;
         bfd_put_32 (htab->ovtab->owner, s->vma, p + off);
         bfd_put_32 (htab->ovtab->owner, (s->size + 15) & -16, p + off + 4);
         /* file_off written later in spu_elf_modify_program_headers.  */

         lo = 0;
         hi = htab->num_buf;
         while (lo < hi)
           {
             mid = (lo + hi) >> 1;
             if (htab->ovl_region[2 * mid + 1]->vma
                + htab->ovl_region[2 * mid + 1]->size <= s->vma)
              lo = mid + 1;
             else if (htab->ovl_region[2 * mid]->vma > s->vma)
              hi = mid;
             else
              {
                bfd_put_32 (htab->ovtab->owner, mid + 1, p + off + 12);
                break;
              }
           }
         BFD_ASSERT (lo < hi);
       }
    }

  /* Write out _ovly_buf_table.  */
  p = htab->ovtab->contents + htab->num_overlays * 16;
  for (i = 0; i < htab->num_buf; i++)
    {
      bfd_put_32 (htab->ovtab->owner, 0, p);
      p += 4;
    }

  h = define_ovtab_symbol (htab, "_ovly_table");
  if (h == NULL)
    return FALSE;
  h->root.u.def.value = 0;
  h->size = htab->num_overlays * 16;

  h = define_ovtab_symbol (htab, "_ovly_table_end");
  if (h == NULL)
    return FALSE;
  h->root.u.def.value = htab->num_overlays * 16;
  h->size = 0;

  h = define_ovtab_symbol (htab, "_ovly_buf_table");
  if (h == NULL)
    return FALSE;
  h->root.u.def.value = htab->num_overlays * 16;
  h->size = htab->num_buf * 4;

  h = define_ovtab_symbol (htab, "_ovly_buf_table_end");
  if (h == NULL)
    return FALSE;
  h->root.u.def.value = htab->num_overlays * 16 + htab->num_buf * 4;
  h->size = 0;

  h = define_ovtab_symbol (htab, "_EAR_");
  if (h == NULL)
    return FALSE;
  h->root.u.def.section = toe;
  h->root.u.def.value = 0;
  h->size = 16;

  return TRUE;
}

Here is the call graph for this function:

asection* spu_elf_check_vma ( bfd abfd,
bfd_vma  lo,
bfd_vma  hi 
)

Definition at line 1696 of file elf32-spu.c.

{
  struct elf_segment_map *m;
  unsigned int i;

  for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next)
    if (m->p_type == PT_LOAD)
      for (i = 0; i < m->count; i++)
       if (m->sections[i]->size != 0
           && (m->sections[i]->vma < lo
              || m->sections[i]->vma > hi
              || m->sections[i]->vma + m->sections[i]->size - 1 > hi))
         return m->sections[i];

  return NULL;
}

Definition at line 491 of file elf32-spu.c.

{
  bfd *ibfd;

  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->next)
    if (bfd_get_section_by_name (ibfd, SPU_PTNOTE_SPUNAME) != NULL)
      break;

  if (ibfd == NULL)
    {
      /* Make SPU_PTNOTE_SPUNAME section.  */
      asection *s;
      size_t name_len;
      size_t size;
      bfd_byte *data;
      flagword flags;

      ibfd = info->input_bfds;
      flags = SEC_LOAD | SEC_READONLY | SEC_HAS_CONTENTS | SEC_IN_MEMORY;
      s = bfd_make_section_anyway_with_flags (ibfd, SPU_PTNOTE_SPUNAME, flags);
      if (s == NULL
         || !bfd_set_section_alignment (ibfd, s, 4))
       return FALSE;

      name_len = strlen (bfd_get_filename (output_bfd)) + 1;
      size = 12 + ((sizeof (SPU_PLUGIN_NAME) + 3) & -4);
      size += (name_len + 3) & -4;

      if (!bfd_set_section_size (ibfd, s, size))
       return FALSE;

      data = bfd_zalloc (ibfd, size);
      if (data == NULL)
       return FALSE;

      bfd_put_32 (ibfd, sizeof (SPU_PLUGIN_NAME), data + 0);
      bfd_put_32 (ibfd, name_len, data + 4);
      bfd_put_32 (ibfd, 1, data + 8);
      memcpy (data + 12, SPU_PLUGIN_NAME, sizeof (SPU_PLUGIN_NAME));
      memcpy (data + 12 + ((sizeof (SPU_PLUGIN_NAME) + 3) & -4),
             bfd_get_filename (output_bfd), name_len);
      s->contents = data;
    }

  return TRUE;
}

Here is the call graph for this function:

bfd_boolean spu_elf_find_overlays ( bfd output_bfd,
struct bfd_link_info info 
)

Definition at line 587 of file elf32-spu.c.

{
  struct spu_link_hash_table *htab = spu_hash_table (info);
  asection **alloc_sec;
  unsigned int i, n, ovl_index, num_buf;
  asection *s;
  bfd_vma ovl_end;

  if (output_bfd->section_count < 2)
    return FALSE;

  alloc_sec = bfd_malloc (output_bfd->section_count * sizeof (*alloc_sec));
  if (alloc_sec == NULL)
    return FALSE;

  /* Pick out all the alloced sections.  */
  for (n = 0, s = output_bfd->sections; s != NULL; s = s->next)
    if ((s->flags & SEC_ALLOC) != 0
       && (s->flags & (SEC_LOAD | SEC_THREAD_LOCAL)) != SEC_THREAD_LOCAL
       && s->size != 0)
      alloc_sec[n++] = s;

  if (n == 0)
    {
      free (alloc_sec);
      return FALSE;
    }

  /* Sort them by vma.  */
  qsort (alloc_sec, n, sizeof (*alloc_sec), sort_sections);

  /* Look for overlapping vmas.  Any with overlap must be overlays.
     Count them.  Also count the number of overlay regions and for
     each region save a section from that region with the lowest vma
     and another section with the highest end vma.  */
  ovl_end = alloc_sec[0]->vma + alloc_sec[0]->size;
  for (ovl_index = 0, num_buf = 0, i = 1; i < n; i++)
    {
      s = alloc_sec[i];
      if (s->vma < ovl_end)
       {
         asection *s0 = alloc_sec[i - 1];

         if (spu_elf_section_data (s0)->ovl_index == 0)
           {
             spu_elf_section_data (s0)->ovl_index = ++ovl_index;
             alloc_sec[num_buf * 2] = s0;
             alloc_sec[num_buf * 2 + 1] = s0;
             num_buf++;
           }
         spu_elf_section_data (s)->ovl_index = ++ovl_index;
         if (ovl_end < s->vma + s->size)
           {
             ovl_end = s->vma + s->size;
             alloc_sec[num_buf * 2 - 1] = s;
           }
       }
      else
       ovl_end = s->vma + s->size;
    }

  htab->num_overlays = ovl_index;
  htab->num_buf = num_buf;
  if (ovl_index == 0)
    {
      free (alloc_sec);
      return FALSE;
    }

  alloc_sec = bfd_realloc (alloc_sec, num_buf * 2 * sizeof (*alloc_sec));
  if (alloc_sec == NULL)
    return FALSE;

  htab->ovl_region = alloc_sec;
  return TRUE;
}

Here is the call graph for this function:

static asection* spu_elf_gc_mark_hook ( asection sec,
struct bfd_link_info *info  ATTRIBUTE_UNUSED,
Elf_Internal_Rela *rel  ATTRIBUTE_UNUSED,
struct elf_link_hash_entry h,
Elf_Internal_Sym *  sym 
) [static]

Definition at line 542 of file elf32-spu.c.

{
  if (h != NULL)
    {
      switch (h->root.type)
       {
       case bfd_link_hash_defined:
       case bfd_link_hash_defweak:
         return h->root.u.def.section;

       case bfd_link_hash_common:
         return h->root.u.c.p->section;

       default:
         break;
       }
    }
  else
    return bfd_section_from_elf_index (sec->owner, sym->st_shndx);

  return NULL;
}

Here is the call graph for this function:

static void spu_elf_info_to_howto ( bfd *abfd  ATTRIBUTE_UNUSED,
arelent cache_ptr,
Elf_Internal_Rela dst 
) [static]

Definition at line 127 of file elf32-spu.c.

{
  enum elf_spu_reloc_type r_type;

  r_type = (enum elf_spu_reloc_type) ELF32_R_TYPE (dst->r_info);
  BFD_ASSERT (r_type < R_SPU_max);
  cache_ptr->howto = &elf_howto_table[(int) r_type];
}
static struct bfd_link_hash_table* spu_elf_link_hash_table_create ( bfd abfd) [static, read]

Definition at line 328 of file elf32-spu.c.

{
  struct spu_link_hash_table *htab;

  htab = bfd_malloc (sizeof (*htab));
  if (htab == NULL)
    return NULL;

  if (!_bfd_elf_link_hash_table_init (&htab->elf, abfd,
                                  _bfd_elf_link_hash_newfunc,
                                  sizeof (struct elf_link_hash_entry)))
    {
      free (htab);
      return NULL;
    }

  /* Init the stub hash table too.  */
  if (!bfd_hash_table_init (&htab->stub_hash_table, stub_hash_newfunc,
                         sizeof (struct spu_stub_hash_entry)))
    return NULL;

  memset (&htab->stub, 0,
         sizeof (*htab) - offsetof (struct spu_link_hash_table, stub));

  return &htab->elf.root;
}

Here is the call graph for this function:

static void spu_elf_link_hash_table_free ( struct bfd_link_hash_table hash) [static]

Definition at line 358 of file elf32-spu.c.

{
  struct spu_link_hash_table *ret = (struct spu_link_hash_table *) hash;

  bfd_hash_table_free (&ret->stub_hash_table);
  _bfd_generic_link_hash_table_free (hash);
}

Here is the call graph for this function:

static int spu_elf_modify_program_headers ( bfd abfd,
struct bfd_link_info info 
) [static]

Definition at line 1716 of file elf32-spu.c.

{
  const struct elf_backend_data *bed;
  struct elf_obj_tdata *tdata;
  Elf_Internal_Phdr *phdr, *last;
  struct spu_link_hash_table *htab;
  unsigned int count;
  unsigned int i;

  if (info == NULL)
    return TRUE;

  bed = get_elf_backend_data (abfd);
  tdata = elf_tdata (abfd);
  phdr = tdata->phdr;
  count = tdata->program_header_size / bed->s->sizeof_phdr;
  htab = spu_hash_table (info);
  if (htab->num_overlays != 0)
    {
      struct elf_segment_map *m;
      unsigned int o;

      for (i = 0, m = elf_tdata (abfd)->segment_map; m; ++i, m = m->next)
       if (m->count != 0
           && (o = spu_elf_section_data (m->sections[0])->ovl_index) != 0)
         {
           /* Mark this as an overlay header.  */
           phdr[i].p_flags |= PF_OVERLAY;

           if (htab->ovtab != NULL && htab->ovtab->size != 0)
             {
              bfd_byte *p = htab->ovtab->contents;
              unsigned int off = (o - 1) * 16 + 8;

              /* Write file_off into _ovly_table.  */
              bfd_put_32 (htab->ovtab->owner, phdr[i].p_offset, p + off);
             }
         }
    }

  /* Round up p_filesz and p_memsz of PT_LOAD segments to multiples
     of 16.  This should always be possible when using the standard
     linker scripts, but don't create overlapping segments if
     someone is playing games with linker scripts.  */
  last = NULL;
  for (i = count; i-- != 0; )
    if (phdr[i].p_type == PT_LOAD)
      {
       unsigned adjust;

       adjust = -phdr[i].p_filesz & 15;
       if (adjust != 0
           && last != NULL
           && phdr[i].p_offset + phdr[i].p_filesz > last->p_offset - adjust)
         break;

       adjust = -phdr[i].p_memsz & 15;
       if (adjust != 0
           && last != NULL
           && phdr[i].p_filesz != 0
           && phdr[i].p_vaddr + phdr[i].p_memsz > last->p_vaddr - adjust
           && phdr[i].p_vaddr + phdr[i].p_memsz <= last->p_vaddr)
         break;

       if (phdr[i].p_filesz != 0)
         last = &phdr[i];
      }

  if (i == (unsigned int) -1)
    for (i = count; i-- != 0; )
      if (phdr[i].p_type == PT_LOAD)
       {
       unsigned adjust;

       adjust = -phdr[i].p_filesz & 15;
       phdr[i].p_filesz += adjust;

       adjust = -phdr[i].p_memsz & 15;
       phdr[i].p_memsz += adjust;
      }

  return TRUE;
}

Here is the call graph for this function:

static bfd_boolean spu_elf_modify_segment_map ( bfd abfd,
struct bfd_link_info info 
) [static]

Definition at line 1639 of file elf32-spu.c.

{
  asection *toe, *s;
  struct elf_segment_map *m;
  unsigned int i;

  if (info == NULL)
    return TRUE;

  toe = bfd_get_section_by_name (abfd, ".toe");
  for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next)
    if (m->p_type == PT_LOAD && m->count > 1)
      for (i = 0; i < m->count; i++)
       if ((s = m->sections[i]) == toe
           || spu_elf_section_data (s)->ovl_index != 0)
         {
           struct elf_segment_map *m2;
           bfd_vma amt;

           if (i + 1 < m->count)
             {
              amt = sizeof (struct elf_segment_map);
              amt += (m->count - (i + 2)) * sizeof (m->sections[0]);
              m2 = bfd_zalloc (abfd, amt);
              if (m2 == NULL)
                return FALSE;
              m2->count = m->count - (i + 1);
              memcpy (m2->sections, m->sections + i + 1,
                     m2->count * sizeof (m->sections[0]));
              m2->p_type = PT_LOAD;
              m2->next = m->next;
              m->next = m2;
             }
           m->count = 1;
           if (i != 0)
             {
              m->count = i;
              amt = sizeof (struct elf_segment_map);
              m2 = bfd_zalloc (abfd, amt);
              if (m2 == NULL)
                return FALSE;
              m2->p_type = PT_LOAD;
              m2->count = 1;
              m2->sections[0] = s;
              m2->next = m->next;
              m->next = m2;
             }
           break;
         }

  return TRUE;
}

Here is the call graph for this function:

static bfd_boolean spu_elf_new_section_hook ( bfd abfd,
asection sec 
) [static]

Definition at line 209 of file elf32-spu.c.

{
  if (!sec->used_by_bfd)
    {
      struct _spu_elf_section_data *sdata;

      sdata = bfd_zalloc (abfd, sizeof (*sdata));
      if (sdata == NULL)
       return FALSE;
      sec->used_by_bfd = sdata;
    }

  return _bfd_elf_new_section_hook (abfd, sec);
}

Here is the call graph for this function:

Definition at line 1174 of file elf32-spu.c.

{
  *ovl_bfd = bfd_openr_iovec ("builtin ovl_mgr",
                           "elf32-spu",
                           ovl_mgr_open,
                           (void *) stream,
                           ovl_mgr_pread,
                           NULL,
                           NULL);
  return *ovl_bfd != NULL;
}

Here is the call graph for this function:

void spu_elf_plugin ( int  val)

Definition at line 1596 of file elf32-spu.c.

{
  spu_plugin = val;
}
static void spu_elf_post_process_headers ( bfd abfd,
struct bfd_link_info *info  ATTRIBUTE_UNUSED 
) [static]

Definition at line 1604 of file elf32-spu.c.

{
  if (spu_plugin)
    {
      Elf_Internal_Ehdr *i_ehdrp = elf_elfheader (abfd);

      i_ehdrp->e_type = ET_DYN;
    }
}
static bfd_reloc_status_type spu_elf_rel9 ( bfd abfd,
arelent reloc_entry,
asymbol symbol,
void *  data,
asection input_section,
bfd output_bfd,
char **  error_message 
) [static]

Definition at line 162 of file elf32-spu.c.

{
  bfd_size_type octets;
  bfd_vma val;
  long insn;

  /* If this is a relocatable link (output_bfd test tells us), just
     call the generic function.  Any adjustment will be done at final
     link time.  */
  if (output_bfd != NULL)
    return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
                              input_section, output_bfd, error_message);

  if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
    return bfd_reloc_outofrange;
  octets = reloc_entry->address * bfd_octets_per_byte (abfd);

  /* Get symbol value.  */
  val = 0;
  if (!bfd_is_com_section (symbol->section))
    val = symbol->value;
  if (symbol->section->output_section)
    val += symbol->section->output_section->vma;

  val += reloc_entry->addend;

  /* Make it pc-relative.  */
  val -= input_section->output_section->vma + input_section->output_offset;

  val >>= 2;
  if (val + 256 >= 512)
    return bfd_reloc_overflow;

  insn = bfd_get_32 (abfd, (bfd_byte *) data + octets);

  /* Move two high bits of value to REL9I and REL9 position.
     The mask will take care of selecting the right field.  */
  val = (val & 0x7f) | ((val & 0x180) << 7) | ((val & 0x180) << 16);
  insn &= ~reloc_entry->howto->dst_mask;
  insn |= val & reloc_entry->howto->dst_mask;
  bfd_put_32 (abfd, insn, (bfd_byte *) data + octets);
  return bfd_reloc_ok;
}

Here is the call graph for this function:

static reloc_howto_type* spu_elf_reloc_name_lookup ( bfd *abfd  ATTRIBUTE_UNUSED,
const char *  r_name 
) [static]

Definition at line 146 of file elf32-spu.c.

{
  unsigned int i;

  for (i = 0; i < sizeof (elf_howto_table) / sizeof (elf_howto_table[0]); i++)
    if (elf_howto_table[i].name != NULL
       && strcasecmp (elf_howto_table[i].name, r_name) == 0)
      return &elf_howto_table[i];

  return NULL;
}

Here is the call graph for this function:

static reloc_howto_type* spu_elf_reloc_type_lookup ( bfd *abfd  ATTRIBUTE_UNUSED,
bfd_reloc_code_real_type  code 
) [static]

Definition at line 139 of file elf32-spu.c.

Here is the call graph for this function:

static bfd_boolean spu_elf_relocate_section ( bfd output_bfd,
struct bfd_link_info info,
bfd input_bfd,
asection input_section,
bfd_byte contents,
Elf_Internal_Rela relocs,
Elf_Internal_Sym *  local_syms,
asection **  local_sections 
) [static]

Definition at line 1426 of file elf32-spu.c.

{
  Elf_Internal_Shdr *symtab_hdr;
  struct elf_link_hash_entry **sym_hashes;
  Elf_Internal_Rela *rel, *relend;
  struct spu_link_hash_table *htab;
  bfd_boolean ret = TRUE;

  htab = spu_hash_table (info);
  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
  sym_hashes = (struct elf_link_hash_entry **) (elf_sym_hashes (input_bfd));

  rel = relocs;
  relend = relocs + input_section->reloc_count;
  for (; rel < relend; rel++)
    {
      int r_type;
      reloc_howto_type *howto;
      unsigned long r_symndx;
      Elf_Internal_Sym *sym;
      asection *sec;
      struct elf_link_hash_entry *h;
      const char *sym_name;
      bfd_vma relocation;
      bfd_vma addend;
      bfd_reloc_status_type r;
      bfd_boolean unresolved_reloc;
      bfd_boolean warned;

      r_symndx = ELF32_R_SYM (rel->r_info);
      r_type = ELF32_R_TYPE (rel->r_info);
      howto = elf_howto_table + r_type;
      unresolved_reloc = FALSE;
      warned = FALSE;

      h = NULL;
      sym = NULL;
      sec = NULL;
      if (r_symndx < symtab_hdr->sh_info)
       {
         sym = local_syms + r_symndx;
         sec = local_sections[r_symndx];
         sym_name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym, sec);
         relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
       }
      else
       {
         RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
                               r_symndx, symtab_hdr, sym_hashes,
                               h, sec, relocation,
                               unresolved_reloc, warned);
         sym_name = h->root.root.string;
       }

      if (sec != NULL && elf_discarded_section (sec))
       {
         /* For relocs against symbols from removed linkonce sections,
            or sections discarded by a linker script, we just want the
            section contents zeroed.  Avoid any special processing.  */
         _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset);
         rel->r_info = 0;
         rel->r_addend = 0;
         continue;
       }

      if (info->relocatable)
       continue;

      if (unresolved_reloc)
       {
         (*_bfd_error_handler)
           (_("%B(%s+0x%lx): unresolvable %s relocation against symbol `%s'"),
            input_bfd,
            bfd_get_section_name (input_bfd, input_section),
            (long) rel->r_offset,
            howto->name,
            sym_name);
         ret = FALSE;
       }

      /* If this symbol is in an overlay area, we may need to relocate
        to the overlay stub.  */
      addend = rel->r_addend;
      if (needs_ovl_stub (sym_name, sec, input_section, htab,
                       is_branch (contents + rel->r_offset)))
       {
         char *stub_name;
         struct spu_stub_hash_entry *sh;

         stub_name = spu_stub_name (sec, h, rel);
         if (stub_name == NULL)
           return FALSE;

         sh = (struct spu_stub_hash_entry *)
           bfd_hash_lookup (&htab->stub_hash_table, stub_name, FALSE, FALSE);
         if (sh != NULL)
           {
             relocation = (htab->stub->output_section->vma
                         + htab->stub->output_offset
                         + sh->off);
             addend = 0;
           }
         free (stub_name);
       }

      r = _bfd_final_link_relocate (howto,
                                input_bfd,
                                input_section,
                                contents,
                                rel->r_offset, relocation, addend);

      if (r != bfd_reloc_ok)
       {
         const char *msg = (const char *) 0;

         switch (r)
           {
           case bfd_reloc_overflow:
             if (!((*info->callbacks->reloc_overflow)
                  (info, (h ? &h->root : NULL), sym_name, howto->name,
                   (bfd_vma) 0, input_bfd, input_section, rel->r_offset)))
              return FALSE;
             break;

           case bfd_reloc_undefined:
             if (!((*info->callbacks->undefined_symbol)
                  (info, sym_name, input_bfd, input_section,
                   rel->r_offset, TRUE)))
              return FALSE;
             break;

           case bfd_reloc_outofrange:
             msg = _("internal error: out of range error");
             goto common_error;

           case bfd_reloc_notsupported:
             msg = _("internal error: unsupported relocation error");
             goto common_error;

           case bfd_reloc_dangerous:
             msg = _("internal error: dangerous error");
             goto common_error;

           default:
             msg = _("internal error: unknown error");
             /* fall through */

           common_error:
             if (!((*info->callbacks->warning)
                  (info, msg, sym_name, input_bfd, input_section,
                   rel->r_offset)))
              return FALSE;
             break;
           }
       }
    }

  return ret;
}

Here is the call graph for this function:

static bfd_boolean spu_elf_section_processing ( bfd *abfd  ATTRIBUTE_UNUSED,
Elf_Internal_Shdr i_shdrp 
) [static]

Definition at line 1803 of file elf32-spu.c.

{
  asection *sec;

  sec = i_shdrp->bfd_section;
  if (sec != NULL
      && (sec->flags & SEC_LINKER_CREATED) != 0
      && sec->name != NULL
      && strcmp (sec->name, SPU_PTNOTE_SPUNAME) == 0)
    i_shdrp->contents = sec->contents;

  return TRUE;
}

Here is the call graph for this function:

bfd_boolean spu_elf_size_stubs ( bfd output_bfd,
struct bfd_link_info info,
int  non_overlay_stubs,
asection **  stub,
asection **  ovtab,
asection **  toe 
)

Definition at line 832 of file elf32-spu.c.

{
  struct spu_link_hash_table *htab = spu_hash_table (info);
  bfd *ibfd;
  struct stubarr stubs;
  unsigned i, group;
  flagword flags;

  htab->non_overlay_stubs = non_overlay_stubs;
  stubs.stub_hash_table = &htab->stub_hash_table;
  stubs.count = 0;
  stubs.err = 0;
  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
    {
      extern const bfd_target bfd_elf32_spu_vec;
      Elf_Internal_Shdr *symtab_hdr;
      asection *section;
      Elf_Internal_Sym *local_syms = NULL;

      if (ibfd->xvec != &bfd_elf32_spu_vec)
       continue;

      /* We'll need the symbol table in a second.  */
      symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
      if (symtab_hdr->sh_info == 0)
       continue;

      /* Walk over each section attached to the input bfd.  */
      for (section = ibfd->sections; section != NULL; section = section->next)
       {
         Elf_Internal_Rela *internal_relocs, *irelaend, *irela;

         /* If there aren't any relocs, then there's nothing more to do.  */
         if ((section->flags & SEC_RELOC) == 0
             || (section->flags & SEC_ALLOC) == 0
             || (section->flags & SEC_LOAD) == 0
             || section->reloc_count == 0)
           continue;

         /* If this section is a link-once section that will be
            discarded, then don't create any stubs.  */
         if (section->output_section == NULL
             || section->output_section->owner != output_bfd)
           continue;

         /* Get the relocs.  */
         internal_relocs
           = _bfd_elf_link_read_relocs (ibfd, section, NULL, NULL,
                                    info->keep_memory);
         if (internal_relocs == NULL)
           goto error_ret_free_local;

         /* Now examine each relocation.  */
         irela = internal_relocs;
         irelaend = irela + section->reloc_count;
         for (; irela < irelaend; irela++)
           {
             enum elf_spu_reloc_type r_type;
             unsigned int r_indx;
             asection *sym_sec;
             Elf_Internal_Sym *sym;
             struct elf_link_hash_entry *h;
             const char *sym_name;
             char *stub_name;
             struct spu_stub_hash_entry *sh;
             unsigned int sym_type;
             enum _insn_type { non_branch, branch, call } insn_type;

             r_type = ELF32_R_TYPE (irela->r_info);
             r_indx = ELF32_R_SYM (irela->r_info);

             if (r_type >= R_SPU_max)
              {
                bfd_set_error (bfd_error_bad_value);
                goto error_ret_free_internal;
              }

             /* Determine the reloc target section.  */
             if (!get_sym_h (&h, &sym, &sym_sec, &local_syms, r_indx, ibfd))
              goto error_ret_free_internal;

             if (sym_sec == NULL
                || sym_sec->output_section == NULL
                || sym_sec->output_section->owner != output_bfd)
              continue;

             /* Ensure no stubs for user supplied overlay manager syms.  */
             if (h != NULL
                && (strcmp (h->root.root.string, "__ovly_load") == 0
                    || strcmp (h->root.root.string, "__ovly_return") == 0))
              continue;

             insn_type = non_branch;
             if (r_type == R_SPU_REL16
                || r_type == R_SPU_ADDR16)
              {
                unsigned char insn[4];

                if (!bfd_get_section_contents (ibfd, section, insn,
                                           irela->r_offset, 4))
                  goto error_ret_free_internal;

                if (is_branch (insn))
                  {
                    insn_type = branch;
                    if ((insn[0] & 0xfd) == 0x31)
                     insn_type = call;
                  }
              }

             /* We are only interested in function symbols.  */
             if (h != NULL)
              {
                sym_type = h->type;
                sym_name = h->root.root.string;
              }
             else
              {
                sym_type = ELF_ST_TYPE (sym->st_info);
                sym_name = bfd_elf_sym_name (sym_sec->owner,
                                          symtab_hdr,
                                          sym,
                                          sym_sec);
              }
             if (sym_type != STT_FUNC)
              {
                /* It's common for people to write assembly and forget
                   to give function symbols the right type.  Handle
                   calls to such symbols, but warn so that (hopefully)
                   people will fix their code.  We need the symbol
                   type to be correct to distinguish function pointer
                   initialisation from other pointer initialisation.  */
                if (insn_type == call)
                  (*_bfd_error_handler) (_("warning: call to non-function"
                                        " symbol %s defined in %B"),
                                      sym_sec->owner, sym_name);
                else
                  continue;
              }

             if (!needs_ovl_stub (sym_name, sym_sec, section, htab,
                               insn_type != non_branch))
              continue;

             stub_name = spu_stub_name (sym_sec, h, irela);
             if (stub_name == NULL)
              goto error_ret_free_internal;

             sh = (struct spu_stub_hash_entry *)
              bfd_hash_lookup (&htab->stub_hash_table, stub_name,
                             TRUE, FALSE);
             if (sh == NULL)
              {
                free (stub_name);
              error_ret_free_internal:
                if (elf_section_data (section)->relocs != internal_relocs)
                  free (internal_relocs);
              error_ret_free_local:
                if (local_syms != NULL
                    && (symtab_hdr->contents
                       != (unsigned char *) local_syms))
                  free (local_syms);
                return FALSE;
              }

             /* If this entry isn't new, we already have a stub.  */
             if (sh->target_section != NULL)
              {
                free (stub_name);
                continue;
              }

             sh->target_section = sym_sec;
             if (h != NULL)
              sh->target_off = h->root.u.def.value;
             else
              sh->target_off = sym->st_value;
             sh->target_off += irela->r_addend;

             stubs.count += 1;
           }

         /* We're done with the internal relocs, free them.  */
         if (elf_section_data (section)->relocs != internal_relocs)
           free (internal_relocs);
       }

      if (local_syms != NULL
         && symtab_hdr->contents != (unsigned char *) local_syms)
       {
         if (!info->keep_memory)
           free (local_syms);
         else
           symtab_hdr->contents = (unsigned char *) local_syms;
       }
    }

  elf_link_hash_traverse (&htab->elf, allocate_spuear_stubs, &stubs);
  if (stubs.err)
    return FALSE;

  *stub = NULL;
  if (stubs.count == 0)
    return TRUE;

  ibfd = info->input_bfds;
  flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_READONLY
          | SEC_HAS_CONTENTS | SEC_IN_MEMORY);
  htab->stub = bfd_make_section_anyway_with_flags (ibfd, ".stub", flags);
  *stub = htab->stub;
  if (htab->stub == NULL
      || !bfd_set_section_alignment (ibfd, htab->stub, 2))
    return FALSE;

  flags = (SEC_ALLOC | SEC_LOAD
          | SEC_HAS_CONTENTS | SEC_IN_MEMORY);
  htab->ovtab = bfd_make_section_anyway_with_flags (ibfd, ".ovtab", flags);
  *ovtab = htab->ovtab;
  if (htab->ovtab == NULL
      || !bfd_set_section_alignment (ibfd, htab->stub, 4))
    return FALSE;

  *toe = bfd_make_section_anyway_with_flags (ibfd, ".toe", SEC_ALLOC);
  if (*toe == NULL
      || !bfd_set_section_alignment (ibfd, *toe, 4))
    return FALSE;
  (*toe)->size = 16;

  /* Retrieve all the stubs and sort.  */
  stubs.sh = bfd_malloc (stubs.count * sizeof (*stubs.sh));
  if (stubs.sh == NULL)
    return FALSE;
  i = stubs.count;
  bfd_hash_traverse (&htab->stub_hash_table, populate_stubs, &stubs);
  BFD_ASSERT (stubs.count == 0);

  stubs.count = i;
  qsort (stubs.sh, stubs.count, sizeof (*stubs.sh), sort_stubs);

  /* Now that the stubs are sorted, place them in the stub section.
     Stubs are grouped per overlay
     .     ila $79,func1
     .     br 1f
     .     ila $79,func2
     .     br 1f
     .
     .
     .     ila $79,funcn
     .     nop
     . 1:
     .     ila $78,ovl_index
     .     br __ovly_load  */

  group = 0;
  for (i = 0; i < stubs.count; i++)
    {
      if (spu_elf_section_data (stubs.sh[group]->target_section
                            ->output_section)->ovl_index
         != spu_elf_section_data (stubs.sh[i]->target_section
                               ->output_section)->ovl_index)
       {
         htab->stub->size += SIZEOF_STUB2;
         for (; group != i; group++)
           stubs.sh[group]->delta
             = stubs.sh[i - 1]->off - stubs.sh[group]->off;
       }
      if (group == i
         || ((stubs.sh[i - 1]->target_section->output_section->vma
              + stubs.sh[i - 1]->target_section->output_offset
              + stubs.sh[i - 1]->target_off)
             != (stubs.sh[i]->target_section->output_section->vma
                + stubs.sh[i]->target_section->output_offset
                + stubs.sh[i]->target_off)))
       {
         stubs.sh[i]->off = htab->stub->size;
         htab->stub->size += SIZEOF_STUB1;
       }
      else
       stubs.sh[i]->off = stubs.sh[i - 1]->off;
    }
  if (group != i)
    htab->stub->size += SIZEOF_STUB2;
  for (; group != i; group++)
    stubs.sh[group]->delta = stubs.sh[i - 1]->off - stubs.sh[group]->off;

 /* htab->ovtab consists of two arrays.
    .  struct {
    .    u32 vma;
    .    u32 size;
    .    u32 file_off;
    .    u32 buf;
    .  } _ovly_table[];
    .
    .  struct {
    .    u32 mapped;
    .  } _ovly_buf_table[];  */

  htab->ovtab->alignment_power = 4;
  htab->ovtab->size = htab->num_overlays * 16 + htab->num_buf * 4;

  return TRUE;
}

Here is the call graph for this function:

static char* spu_stub_name ( const asection sym_sec,
const struct elf_link_hash_entry h,
const Elf_Internal_Rela rel 
) [static]

Definition at line 446 of file elf32-spu.c.

{
  char *stub_name;
  bfd_size_type len;

  if (h)
    {
      len = strlen (h->root.root.string) + 1 + 8 + 1;
      stub_name = bfd_malloc (len);
      if (stub_name == NULL)
       return stub_name;

      sprintf (stub_name, "%s+%x",
              h->root.root.string,
              (int) rel->r_addend & 0xffffffff);
      len -= 8;
    }
  else
    {
      len = 8 + 1 + 8 + 1 + 8 + 1;
      stub_name = bfd_malloc (len);
      if (stub_name == NULL)
       return stub_name;

      sprintf (stub_name, "%x:%x+%x",
              sym_sec->id & 0xffffffff,
              (int) ELF32_R_SYM (rel->r_info) & 0xffffffff,
              (int) rel->r_addend & 0xffffffff);
      len = strlen (stub_name);
    }

  if (stub_name[len - 2] == '+'
      && stub_name[len - 1] == '0'
      && stub_name[len] == 0)
    stub_name[len - 2] = 0;

  return stub_name;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static struct bfd_hash_entry* stub_hash_newfunc ( struct bfd_hash_entry entry,
struct bfd_hash_table table,
const char *  string 
) [static, read]

Definition at line 297 of file elf32-spu.c.

{
  /* Allocate the structure if it has not already been allocated by a
     subclass.  */
  if (entry == NULL)
    {
      entry = bfd_hash_allocate (table, sizeof (struct spu_stub_hash_entry));
      if (entry == NULL)
       return entry;
    }

  /* Call the allocation method of the superclass.  */
  entry = bfd_hash_newfunc (entry, table, string);
  if (entry != NULL)
    {
      struct spu_stub_hash_entry *sh = (struct spu_stub_hash_entry *) entry;

      sh->target_section = NULL;
      sh->target_off = 0;
      sh->off = 0;
      sh->delta = 0;
    }

  return entry;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static bfd_boolean write_one_stub ( struct bfd_hash_entry bh,
void *  inf 
) [static]

Definition at line 1190 of file elf32-spu.c.

{
  struct spu_stub_hash_entry *ent = (struct spu_stub_hash_entry *) bh;
  struct spu_link_hash_table *htab = inf;
  asection *sec = htab->stub;
  asection *s = ent->target_section;
  unsigned int ovl;
  bfd_vma val;

  val = ent->target_off + s->output_offset + s->output_section->vma;
  bfd_put_32 (sec->owner, ILA_79 + ((val << 7) & 0x01ffff80),
             sec->contents + ent->off);
  val = ent->delta + 4;
  bfd_put_32 (sec->owner, BR + ((val << 5) & 0x007fff80),
             sec->contents + ent->off + 4);

  /* If this is the last stub of this group, write stub2.  */
  if (ent->delta == 0)
    {
      bfd_put_32 (sec->owner, NOP,
                sec->contents + ent->off + 4);

      ovl = spu_elf_section_data (s->output_section)->ovl_index;
      bfd_put_32 (sec->owner, ILA_78 + ((ovl << 7) & 0x01ffff80),
                sec->contents + ent->off + 8);

      val = (htab->ovly_load->root.u.def.section->output_section->vma
            + htab->ovly_load->root.u.def.section->output_offset
            + htab->ovly_load->root.u.def.value
            - (sec->output_section->vma
              + sec->output_offset
              + ent->off + 12));

      if (val + 0x20000 >= 0x40000)
       htab->stub_overflow = TRUE;

      bfd_put_32 (sec->owner, BR + ((val << 5) & 0x007fff80),
                sec->contents + ent->off + 12);
    }

  if (htab->emit_stub_syms)
    {
      struct elf_link_hash_entry *h;
      size_t len1, len2;
      char *name;

      len1 = sizeof ("00000000.ovl_call.") - 1;
      len2 = strlen (ent->root.string);
      name = bfd_malloc (len1 + len2 + 1);
      if (name == NULL)
       return FALSE;
      memcpy (name, "00000000.ovl_call.", len1);
      memcpy (name + len1, ent->root.string, len2 + 1);
      h = elf_link_hash_lookup (&htab->elf, name, TRUE, FALSE, FALSE);
      if (h == NULL)
       return FALSE;
      if (h->root.type == bfd_link_hash_new)
       {
         h->root.type = bfd_link_hash_defined;
         h->root.u.def.section = sec;
         h->root.u.def.value = ent->off;
         h->size = (ent->delta == 0
                   ? SIZEOF_STUB1 + SIZEOF_STUB2 : SIZEOF_STUB1);
         h->type = STT_FUNC;
         h->ref_regular = 1;
         h->def_regular = 1;
         h->ref_regular_nonweak = 1;
         h->forced_local = 1;
         h->non_elf = 0;
       }
    }

  return TRUE;
}

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

Initial value:
 {
  { ".toe", 4, 0, SHT_NOBITS, SHF_ALLOC },
  { NULL, 0, 0, 0, 0 }
}

Definition at line 83 of file elf32-spu.c.

reloc_howto_type elf_howto_table[] [static]

Definition at line 38 of file elf32-spu.c.

int spu_plugin = 0 [static]

Definition at line 1593 of file elf32-spu.c.