Back to index

cell-binutils  2.17cvs20070401
Classes | Defines | Functions
elf32-spu.h File Reference
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Classes

struct  _spu_elf_section_data
struct  _ovl_stream

Defines

#define spu_elf_section_data(sec)   ((struct _spu_elf_section_data *) elf_section_data (sec))

Functions

void spu_elf_plugin (int)
bfd_boolean spu_elf_open_builtin_lib (bfd **, const struct _ovl_stream *)
bfd_boolean spu_elf_create_sections (bfd *, struct bfd_link_info *)
bfd_boolean spu_elf_find_overlays (bfd *, struct bfd_link_info *)
bfd_boolean spu_elf_size_stubs (bfd *, struct bfd_link_info *, int, asection **, asection **, asection **)
bfd_boolean spu_elf_build_stubs (struct bfd_link_info *, int, asection *)
asectionspu_elf_check_vma (bfd *, bfd_vma, bfd_vma)

Class Documentation

struct _spu_elf_section_data

Definition at line 23 of file elf32-spu.h.

Class Members
unsigned int ovl_index
struct _ovl_stream

Definition at line 34 of file elf32-spu.h.

Class Members
const void * end
const void * start

Define Documentation

Definition at line 31 of file elf32-spu.h.


Function Documentation

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:

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:

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:

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  )

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

{
  spu_plugin = val;
}
bfd_boolean spu_elf_size_stubs ( bfd ,
struct bfd_link_info ,
int  ,
asection **  ,
asection **  ,
asection **   
)

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: