Back to index

cell-binutils  2.17cvs20070401
Functions
elf64-ppc.h File Reference
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

void ppc64_elf_init_stub_bfd (bfd *, struct bfd_link_info *)
bfd_boolean ppc64_elf_edit_opd (bfd *, struct bfd_link_info *, bfd_boolean, bfd_boolean)
asectionppc64_elf_tls_setup (bfd *, struct bfd_link_info *)
bfd_boolean ppc64_elf_tls_optimize (bfd *, struct bfd_link_info *)
bfd_boolean ppc64_elf_edit_toc (bfd *, struct bfd_link_info *)
bfd_vma ppc64_elf_toc (bfd *)
int ppc64_elf_setup_section_lists (bfd *, struct bfd_link_info *, int)
void ppc64_elf_next_toc_section (struct bfd_link_info *, asection *)
void ppc64_elf_reinit_toc (bfd *, struct bfd_link_info *)
bfd_boolean ppc64_elf_next_input_section (struct bfd_link_info *, asection *)
bfd_boolean ppc64_elf_size_stubs (bfd *, struct bfd_link_info *, bfd_signed_vma, asection *(*)(const char *, asection *), void(*)(void))
bfd_boolean ppc64_elf_build_stubs (bfd_boolean, struct bfd_link_info *, char **)
void ppc64_elf_restore_symbols (struct bfd_link_info *info)

Function Documentation

Definition at line 9552 of file elf64-ppc.c.

{
  struct ppc_link_hash_table *htab = ppc_hash_table (info);
  asection *stub_sec;
  bfd_byte *p;
  int stub_sec_count = 0;

  htab->emit_stub_syms = emit_stub_syms;

  /* Allocate memory to hold the linker stubs.  */
  for (stub_sec = htab->stub_bfd->sections;
       stub_sec != NULL;
       stub_sec = stub_sec->next)
    if ((stub_sec->flags & SEC_LINKER_CREATED) == 0
       && stub_sec->size != 0)
      {
       stub_sec->contents = bfd_zalloc (htab->stub_bfd, stub_sec->size);
       if (stub_sec->contents == NULL)
         return FALSE;
       /* We want to check that built size is the same as calculated
          size.  rawsize is a convenient location to use.  */
       stub_sec->rawsize = stub_sec->size;
       stub_sec->size = 0;
      }

  if (htab->glink != NULL && htab->glink->size != 0)
    {
      unsigned int indx;
      bfd_vma plt0;

      /* Build the .glink plt call stub.  */
      if (htab->emit_stub_syms)
       {
         struct elf_link_hash_entry *h;
         h = elf_link_hash_lookup (&htab->elf, "__glink", 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 = htab->glink;
             h->root.u.def.value = 8;
             h->ref_regular = 1;
             h->def_regular = 1;
             h->ref_regular_nonweak = 1;
             h->forced_local = 1;
             h->non_elf = 0;
           }
       }
      p = htab->glink->contents;
      plt0 = (htab->plt->output_section->vma
             + htab->plt->output_offset
             - (htab->glink->output_section->vma
               + htab->glink->output_offset
               + 16));
      bfd_put_64 (htab->glink->owner, plt0, p);
      p += 8;
      bfd_put_32 (htab->glink->owner, MFLR_R12, p);
      p += 4;
      bfd_put_32 (htab->glink->owner, BCL_20_31, p);
      p += 4;
      bfd_put_32 (htab->glink->owner, MFLR_R11, p);
      p += 4;
      bfd_put_32 (htab->glink->owner, LD_R2_M16R11, p);
      p += 4;
      bfd_put_32 (htab->glink->owner, MTLR_R12, p);
      p += 4;
      bfd_put_32 (htab->glink->owner, ADD_R12_R2_R11, p);
      p += 4;
      bfd_put_32 (htab->glink->owner, LD_R11_0R12, p);
      p += 4;
      bfd_put_32 (htab->glink->owner, LD_R2_0R12 | 8, p);
      p += 4;
      bfd_put_32 (htab->glink->owner, MTCTR_R11, p);
      p += 4;
      bfd_put_32 (htab->glink->owner, LD_R11_0R12 | 16, p);
      p += 4;
      bfd_put_32 (htab->glink->owner, BCTR, p);
      p += 4;
      while (p - htab->glink->contents < GLINK_CALL_STUB_SIZE)
       {
         bfd_put_32 (htab->glink->owner, NOP, p);
         p += 4;
       }

      /* Build the .glink lazy link call stubs.  */
      indx = 0;
      while (p < htab->glink->contents + htab->glink->size)
       {
         if (indx < 0x8000)
           {
             bfd_put_32 (htab->glink->owner, LI_R0_0 | indx, p);
             p += 4;
           }
         else
           {
             bfd_put_32 (htab->glink->owner, LIS_R0_0 | PPC_HI (indx), p);
             p += 4;
             bfd_put_32 (htab->glink->owner, ORI_R0_R0_0 | PPC_LO (indx), p);
             p += 4;
           }
         bfd_put_32 (htab->glink->owner,
                    B_DOT | ((htab->glink->contents - p + 8) & 0x3fffffc), p);
         indx++;
         p += 4;
       }
      htab->glink->rawsize = p - htab->glink->contents;
    }

  if (htab->brlt->size != 0)
    {
      htab->brlt->contents = bfd_zalloc (htab->brlt->owner,
                                    htab->brlt->size);
      if (htab->brlt->contents == NULL)
       return FALSE;
    }
  if (htab->relbrlt != NULL && htab->relbrlt->size != 0)
    {
      htab->relbrlt->contents = bfd_zalloc (htab->relbrlt->owner,
                                       htab->relbrlt->size);
      if (htab->relbrlt->contents == NULL)
       return FALSE;
    }

  /* Build the stubs as directed by the stub hash table.  */
  bfd_hash_traverse (&htab->stub_hash_table, ppc_build_one_stub, info);

  if (htab->relbrlt != NULL)
    htab->relbrlt->reloc_count = 0;

  for (stub_sec = htab->stub_bfd->sections;
       stub_sec != NULL;
       stub_sec = stub_sec->next)
    if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
      {
       stub_sec_count += 1;
       if (stub_sec->rawsize != stub_sec->size)
         break;
      }

  if (stub_sec != NULL
      || htab->glink->rawsize != htab->glink->size)
    {
      htab->stub_error = TRUE;
      (*_bfd_error_handler) (_("stubs don't match calculated size"));
    }

  if (htab->stub_error)
    return FALSE;

  if (stats != NULL)
    {
      *stats = bfd_malloc (500);
      if (*stats == NULL)
       return FALSE;

      sprintf (*stats, _("linker stubs in %u group%s\n"
                      "  branch       %lu\n"
                      "  toc adjust   %lu\n"
                      "  long branch  %lu\n"
                      "  long toc adj %lu\n"
                      "  plt call     %lu"),
              stub_sec_count,
              stub_sec_count == 1 ? "" : "s",
              htab->stub_count[ppc_stub_long_branch - 1],
              htab->stub_count[ppc_stub_long_branch_r2off - 1],
              htab->stub_count[ppc_stub_plt_branch - 1],
              htab->stub_count[ppc_stub_plt_branch_r2off - 1],
              htab->stub_count[ppc_stub_plt_call - 1]);
    }
  return TRUE;
}

Here is the call graph for this function:

Definition at line 6345 of file elf64-ppc.c.

{
  bfd *ibfd;
  bfd_boolean some_edited = FALSE;
  asection *need_pad = NULL;

  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
    {
      asection *sec;
      Elf_Internal_Rela *relstart, *rel, *relend;
      Elf_Internal_Shdr *symtab_hdr;
      Elf_Internal_Sym *local_syms;
      struct elf_link_hash_entry **sym_hashes;
      bfd_vma offset;
      bfd_size_type amt;
      long *opd_adjust;
      bfd_boolean need_edit, add_aux_fields;
      bfd_size_type cnt_16b = 0;

      sec = bfd_get_section_by_name (ibfd, ".opd");
      if (sec == NULL || sec->size == 0)
       continue;

      amt = sec->size * sizeof (long) / 8;
      opd_adjust = get_opd_info (sec);
      if (opd_adjust == NULL)
       {
         /* check_relocs hasn't been called.  Must be a ld -r link
            or --just-symbols object.   */
         opd_adjust = bfd_alloc (obfd, amt);
         if (opd_adjust == NULL)
           return FALSE;
         ppc64_elf_section_data (sec)->u.opd_adjust = opd_adjust;
         BFD_ASSERT (ppc64_elf_section_data (sec)->sec_type == sec_normal);
         ppc64_elf_section_data (sec)->sec_type = sec_opd;
       }
      memset (opd_adjust, 0, amt);

      if (no_opd_opt)
       continue;

      if (sec->sec_info_type == ELF_INFO_TYPE_JUST_SYMS)
       continue;

      if (sec->output_section == bfd_abs_section_ptr)
       continue;

      /* Look through the section relocs.  */
      if ((sec->flags & SEC_RELOC) == 0 || sec->reloc_count == 0)
       continue;

      local_syms = NULL;
      symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
      sym_hashes = elf_sym_hashes (ibfd);

      /* Read the relocations.  */
      relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL,
                                       info->keep_memory);
      if (relstart == NULL)
       return FALSE;

      /* First run through the relocs to check they are sane, and to
        determine whether we need to edit this opd section.  */
      need_edit = FALSE;
      need_pad = sec;
      offset = 0;
      relend = relstart + sec->reloc_count;
      for (rel = relstart; rel < relend; )
       {
         enum elf_ppc64_reloc_type r_type;
         unsigned long r_symndx;
         asection *sym_sec;
         struct elf_link_hash_entry *h;
         Elf_Internal_Sym *sym;

         /* .opd contains a regular array of 16 or 24 byte entries.  We're
            only interested in the reloc pointing to a function entry
            point.  */
         if (rel->r_offset != offset
             || rel + 1 >= relend
             || (rel + 1)->r_offset != offset + 8)
           {
             /* If someone messes with .opd alignment then after a
               "ld -r" we might have padding in the middle of .opd.
               Also, there's nothing to prevent someone putting
               something silly in .opd with the assembler.  No .opd
               optimization for them!  */
           broken_opd:
             (*_bfd_error_handler)
              (_("%B: .opd is not a regular array of opd entries"), ibfd);
             need_edit = FALSE;
             break;
           }

         if ((r_type = ELF64_R_TYPE (rel->r_info)) != R_PPC64_ADDR64
             || (r_type = ELF64_R_TYPE ((rel + 1)->r_info)) != R_PPC64_TOC)
           {
             (*_bfd_error_handler)
              (_("%B: unexpected reloc type %u in .opd section"),
               ibfd, r_type);
             need_edit = FALSE;
             break;
           }

         r_symndx = ELF64_R_SYM (rel->r_info);
         if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms,
                       r_symndx, ibfd))
           goto error_ret;

         if (sym_sec == NULL || sym_sec->owner == NULL)
           {
             const char *sym_name;
             if (h != NULL)
              sym_name = h->root.root.string;
             else
              sym_name = bfd_elf_sym_name (ibfd, symtab_hdr, sym,
                                        sym_sec);

             (*_bfd_error_handler)
              (_("%B: undefined sym `%s' in .opd section"),
               ibfd, sym_name);
             need_edit = FALSE;
             break;
           }

         /* opd entries are always for functions defined in the
            current input bfd.  If the symbol isn't defined in the
            input bfd, then we won't be using the function in this
            bfd;  It must be defined in a linkonce section in another
            bfd, or is weak.  It's also possible that we are
            discarding the function due to a linker script /DISCARD/,
            which we test for via the output_section.  */
         if (sym_sec->owner != ibfd
             || sym_sec->output_section == bfd_abs_section_ptr)
           need_edit = TRUE;

         rel += 2;
         if (rel == relend
             || (rel + 1 == relend && rel->r_offset == offset + 16))
           {
             if (sec->size == offset + 24)
              {
                need_pad = NULL;
                break;
              }
             if (rel == relend && sec->size == offset + 16)
              {
                cnt_16b++;
                break;
              }
             goto broken_opd;
           }

         if (rel->r_offset == offset + 24)
           offset += 24;
         else if (rel->r_offset != offset + 16)
           goto broken_opd;
         else if (rel + 1 < relend
                 && ELF64_R_TYPE (rel[0].r_info) == R_PPC64_ADDR64
                 && ELF64_R_TYPE (rel[1].r_info) == R_PPC64_TOC)
           {
             offset += 16;
             cnt_16b++;
           }
         else if (rel + 2 < relend
                 && ELF64_R_TYPE (rel[1].r_info) == R_PPC64_ADDR64
                 && ELF64_R_TYPE (rel[2].r_info) == R_PPC64_TOC)
           {
             offset += 24;
             rel += 1;
           }
         else
           goto broken_opd;
       }

      add_aux_fields = non_overlapping && cnt_16b > 0;

      if (need_edit || add_aux_fields)
       {
         Elf_Internal_Rela *write_rel;
         bfd_byte *rptr, *wptr;
         bfd_byte *new_contents = NULL;
         bfd_boolean skip;
         long opd_ent_size;

         /* This seems a waste of time as input .opd sections are all
            zeros as generated by gcc, but I suppose there's no reason
            this will always be so.  We might start putting something in
            the third word of .opd entries.  */
         if ((sec->flags & SEC_IN_MEMORY) == 0)
           {
             bfd_byte *loc;
             if (!bfd_malloc_and_get_section (ibfd, sec, &loc))
              {
                if (loc != NULL)
                  free (loc);
              error_ret:
                if (local_syms != NULL
                    && symtab_hdr->contents != (unsigned char *) local_syms)
                  free (local_syms);
                if (elf_section_data (sec)->relocs != relstart)
                  free (relstart);
                return FALSE;
              }
             sec->contents = loc;
             sec->flags |= (SEC_IN_MEMORY | SEC_HAS_CONTENTS);
           }

         elf_section_data (sec)->relocs = relstart;

         new_contents = sec->contents;
         if (add_aux_fields)
           {
             new_contents = bfd_malloc (sec->size + cnt_16b * 8);
             if (new_contents == NULL)
              return FALSE;
             need_pad = FALSE;
           }
         wptr = new_contents;
         rptr = sec->contents;

         write_rel = relstart;
         skip = FALSE;
         offset = 0;
         opd_ent_size = 0;
         for (rel = relstart; rel < relend; rel++)
           {
             unsigned long r_symndx;
             asection *sym_sec;
             struct elf_link_hash_entry *h;
             Elf_Internal_Sym *sym;

             r_symndx = ELF64_R_SYM (rel->r_info);
             if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms,
                           r_symndx, ibfd))
              goto error_ret;

             if (rel->r_offset == offset)
              {
                struct ppc_link_hash_entry *fdh = NULL;

                /* See if the .opd entry is full 24 byte or
                   16 byte (with fd_aux entry overlapped with next
                   fd_func).  */
                opd_ent_size = 24;
                if ((rel + 2 == relend && sec->size == offset + 16)
                    || (rel + 3 < relend
                       && rel[2].r_offset == offset + 16
                       && rel[3].r_offset == offset + 24
                       && ELF64_R_TYPE (rel[2].r_info) == R_PPC64_ADDR64
                       && ELF64_R_TYPE (rel[3].r_info) == R_PPC64_TOC))
                  opd_ent_size = 16;

                if (h != NULL
                    && h->root.root.string[0] == '.')
                  {
                    fdh = get_fdh ((struct ppc_link_hash_entry *) h,
                                 ppc_hash_table (info));
                    if (fdh != NULL
                       && fdh->elf.root.type != bfd_link_hash_defined
                       && fdh->elf.root.type != bfd_link_hash_defweak)
                     fdh = NULL;
                  }

                skip = (sym_sec->owner != ibfd
                       || sym_sec->output_section == bfd_abs_section_ptr);
                if (skip)
                  {
                    if (fdh != NULL && sym_sec->owner == ibfd)
                     {
                       /* Arrange for the function descriptor sym
                          to be dropped.  */
                       fdh->elf.root.u.def.value = 0;
                       fdh->elf.root.u.def.section = sym_sec;
                     }
                    opd_adjust[rel->r_offset / 8] = -1;
                  }
                else
                  {
                    /* We'll be keeping this opd entry.  */

                    if (fdh != NULL)
                     {
                       /* Redefine the function descriptor symbol to
                          this location in the opd section.  It is
                          necessary to update the value here rather
                          than using an array of adjustments as we do
                          for local symbols, because various places
                          in the generic ELF code use the value
                          stored in u.def.value.  */
                       fdh->elf.root.u.def.value = wptr - new_contents;
                       fdh->adjust_done = 1;
                     }

                    /* Local syms are a bit tricky.  We could
                      tweak them as they can be cached, but
                      we'd need to look through the local syms
                      for the function descriptor sym which we
                      don't have at the moment.  So keep an
                      array of adjustments.  */
                    opd_adjust[rel->r_offset / 8]
                     = (wptr - new_contents) - (rptr - sec->contents);

                    if (wptr != rptr)
                     memcpy (wptr, rptr, opd_ent_size);
                    wptr += opd_ent_size;
                    if (add_aux_fields && opd_ent_size == 16)
                     {
                       memset (wptr, '\0', 8);
                       wptr += 8;
                     }
                  }
                rptr += opd_ent_size;
                offset += opd_ent_size;
              }

             if (skip)
              {
                if (!NO_OPD_RELOCS
                    && !info->relocatable
                    && !dec_dynrel_count (rel->r_info, sec, info,
                                       NULL, h, sym_sec))
                  goto error_ret;
              }
             else
              {
                /* We need to adjust any reloc offsets to point to the
                   new opd entries.  While we're at it, we may as well
                   remove redundant relocs.  */
                rel->r_offset += opd_adjust[(offset - opd_ent_size) / 8];
                if (write_rel != rel)
                  memcpy (write_rel, rel, sizeof (*rel));
                ++write_rel;
              }
           }

         sec->size = wptr - new_contents;
         sec->reloc_count = write_rel - relstart;
         if (add_aux_fields)
           {
             free (sec->contents);
             sec->contents = new_contents;
           }

         /* Fudge the header size too, as this is used later in
            elf_bfd_final_link if we are emitting relocs.  */
         elf_section_data (sec)->rel_hdr.sh_size
           = sec->reloc_count * elf_section_data (sec)->rel_hdr.sh_entsize;
         BFD_ASSERT (elf_section_data (sec)->rel_hdr2 == NULL);
         some_edited = TRUE;
       }
      else if (elf_section_data (sec)->relocs != relstart)
       free (relstart);

      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;
       }
    }

  if (some_edited)
    elf_link_hash_traverse (elf_hash_table (info), adjust_opd_syms, NULL);

  /* If we are doing a final link and the last .opd entry is just 16 byte
     long, add a 8 byte padding after it.  */
  if (need_pad != NULL && !info->relocatable)
    {
      bfd_byte *p;

      if ((need_pad->flags & SEC_IN_MEMORY) == 0)
       {
         BFD_ASSERT (need_pad->size > 0);

         p = bfd_malloc (need_pad->size + 8);
         if (p == NULL)
           return FALSE;

         if (! bfd_get_section_contents (need_pad->owner, need_pad,
                                     p, 0, need_pad->size))
           return FALSE;

         need_pad->contents = p;
         need_pad->flags |= (SEC_IN_MEMORY | SEC_HAS_CONTENTS);
       }
      else
       {
         p = bfd_realloc (need_pad->contents, need_pad->size + 8);
         if (p == NULL)
           return FALSE;

         need_pad->contents = p;
       }

      memset (need_pad->contents + need_pad->size, 0, 8);
      need_pad->size += 8;
    }

  return TRUE;
}

Here is the call graph for this function:

Definition at line 3652 of file elf64-ppc.c.

{
  struct ppc_link_hash_table *htab;

  elf_elfheader (abfd)->e_ident[EI_CLASS] = ELFCLASS64;

/* Always hook our dynamic sections into the first bfd, which is the
   linker created stub bfd.  This ensures that the GOT header is at
   the start of the output TOC section.  */
  htab = ppc_hash_table (info);
  htab->stub_bfd = abfd;
  htab->elf.dynobj = abfd;
}

Definition at line 8991 of file elf64-ppc.c.

{
  struct ppc_link_hash_table *htab = ppc_hash_table (info);

  if ((isec->output_section->flags & SEC_CODE) != 0
      && isec->output_section->index <= htab->top_index)
    {
      asection **list = htab->input_list + isec->output_section->index;
      /* Steal the link_sec pointer for our list.  */
#define PREV_SEC(sec) (htab->stub_group[(sec)->id].link_sec)
      /* This happens to make the list in reverse order,
        which is what we want.  */
      PREV_SEC (isec) = *list;
      *list = isec;
    }

  if (htab->multi_toc_needed)
    {
      /* If a code section has a function that uses the TOC then we need
        to use the right TOC (obviously).  Also, make sure that .opd gets
        the correct TOC value for R_PPC64_TOC relocs that don't have or
        can't find their function symbol (shouldn't ever happen now).  */
      if (isec->has_toc_reloc || (isec->flags & SEC_CODE) == 0)
       {
         if (elf_gp (isec->owner) != 0)
           htab->toc_curr = elf_gp (isec->owner);
       }
      else if (htab->stub_group[isec->id].toc_off == 0)
       {
         int ret = toc_adjusting_stub_needed (info, isec);
         if (ret < 0)
           return FALSE;
         else
           isec->makes_toc_func_call = ret & 1;
       }
    }

  /* Functions that don't use the TOC can belong in any TOC group.
     Use the last TOC base.  This happens to make _init and _fini
     pasting work.  */
  htab->stub_group[isec->id].toc_off = htab->toc_curr;
  return TRUE;
}

Here is the call graph for this function:

Definition at line 8745 of file elf64-ppc.c.

{
  struct ppc_link_hash_table *htab = ppc_hash_table (info);

  if (!htab->no_multi_toc)
    {
      bfd_vma addr = isec->output_offset + isec->output_section->vma;
      bfd_vma off = addr - htab->toc_curr;

      if (off + isec->size > 0x10000)
       htab->toc_curr = addr;

      elf_gp (isec->owner) = (htab->toc_curr
                           - elf_gp (isec->output_section->owner)
                           + TOC_BASE_OFF);
    }
}

Definition at line 8766 of file elf64-ppc.c.

{
  struct ppc_link_hash_table *htab = ppc_hash_table (info);

  htab->multi_toc_needed = htab->toc_curr != elf_gp (output_bfd);

  /* toc_curr tracks the TOC offset used for code sections below in
     ppc64_elf_next_input_section.  Start off at 0x8000.  */
  htab->toc_curr = TOC_BASE_OFF;
}

Definition at line 9749 of file elf64-ppc.c.

{
  struct ppc_link_hash_table *htab = ppc_hash_table (info);
  elf_link_hash_traverse (&htab->elf, undo_symbol_twiddle, info);
}

Here is the call graph for this function:

Definition at line 8676 of file elf64-ppc.c.

{
  bfd *input_bfd;
  int top_id, top_index, id;
  asection *section;
  asection **input_list;
  bfd_size_type amt;
  struct ppc_link_hash_table *htab = ppc_hash_table (info);

  htab->no_multi_toc = no_multi_toc;

  if (htab->brlt == NULL)
    return 0;

  /* Find the top input section id.  */
  for (input_bfd = info->input_bfds, top_id = 3;
       input_bfd != NULL;
       input_bfd = input_bfd->link_next)
    {
      for (section = input_bfd->sections;
          section != NULL;
          section = section->next)
       {
         if (top_id < section->id)
           top_id = section->id;
       }
    }

  htab->top_id = top_id;
  amt = sizeof (struct map_stub) * (top_id + 1);
  htab->stub_group = bfd_zmalloc (amt);
  if (htab->stub_group == NULL)
    return -1;

  /* Set toc_off for com, und, abs and ind sections.  */
  for (id = 0; id < 3; id++)
    htab->stub_group[id].toc_off = TOC_BASE_OFF;

  elf_gp (output_bfd) = htab->toc_curr = ppc64_elf_toc (output_bfd);

  /* We can't use output_bfd->section_count here to find the top output
     section index as some sections may have been removed, and
     strip_excluded_output_sections doesn't renumber the indices.  */
  for (section = output_bfd->sections, top_index = 0;
       section != NULL;
       section = section->next)
    {
      if (top_index < section->index)
       top_index = section->index;
    }

  htab->top_index = top_index;
  amt = sizeof (asection *) * (top_index + 1);
  input_list = bfd_zmalloc (amt);
  htab->input_list = input_list;
  if (input_list == NULL)
    return -1;

  return 1;
}

Here is the call graph for this function:

bfd_boolean ppc64_elf_size_stubs ( bfd ,
struct bfd_link_info ,
bfd_signed_vma  ,
asection *)(const char *, asection *,
void(*)(void)   
)

Definition at line 6754 of file elf64-ppc.c.

{
  struct ppc_link_hash_table *htab;

  htab = ppc_hash_table (info);
  if (htab->tls_get_addr != NULL)
    {
      struct ppc_link_hash_entry *h = htab->tls_get_addr;

      while (h->elf.root.type == bfd_link_hash_indirect
            || h->elf.root.type == bfd_link_hash_warning)
       h = (struct ppc_link_hash_entry *) h->elf.root.u.i.link;

      htab->tls_get_addr = h;

      if (htab->tls_get_addr_fd == NULL
         && h->oh != NULL
         && h->oh->is_func_descriptor
         && (h->oh->elf.root.type == bfd_link_hash_defined
             || h->oh->elf.root.type == bfd_link_hash_defweak))
       htab->tls_get_addr_fd = h->oh;
    }

  if (htab->tls_get_addr_fd != NULL)
    {
      struct ppc_link_hash_entry *h = htab->tls_get_addr_fd;

      while (h->elf.root.type == bfd_link_hash_indirect
            || h->elf.root.type == bfd_link_hash_warning)
       h = (struct ppc_link_hash_entry *) h->elf.root.u.i.link;

      htab->tls_get_addr_fd = h;
    }

  return _bfd_elf_tls_setup (obfd, info);
}

Here is the call graph for this function:

Definition at line 9495 of file elf64-ppc.c.

{
  asection *s;
  bfd_vma TOCstart;

  /* The TOC consists of sections .got, .toc, .tocbss, .plt in that
     order.  The TOC starts where the first of these sections starts.  */
  s = bfd_get_section_by_name (obfd, ".got");
  if (s == NULL)
    s = bfd_get_section_by_name (obfd, ".toc");
  if (s == NULL)
    s = bfd_get_section_by_name (obfd, ".tocbss");
  if (s == NULL)
    s = bfd_get_section_by_name (obfd, ".plt");
  if (s == NULL)
    {
      /* This may happen for
        o  references to TOC base (SYM@toc / TOC[tc0]) without a
        .toc directive
        o  bad linker script
        o --gc-sections and empty TOC sections

        FIXME: Warn user?  */

      /* Look for a likely section.  We probably won't even be
        using TOCstart.  */
      for (s = obfd->sections; s != NULL; s = s->next)
       if ((s->flags & (SEC_ALLOC | SEC_SMALL_DATA | SEC_READONLY))
           == (SEC_ALLOC | SEC_SMALL_DATA))
         break;
      if (s == NULL)
       for (s = obfd->sections; s != NULL; s = s->next)
         if ((s->flags & (SEC_ALLOC | SEC_SMALL_DATA))
             == (SEC_ALLOC | SEC_SMALL_DATA))
           break;
      if (s == NULL)
       for (s = obfd->sections; s != NULL; s = s->next)
         if ((s->flags & (SEC_ALLOC | SEC_READONLY)) == SEC_ALLOC)
           break;
      if (s == NULL)
       for (s = obfd->sections; s != NULL; s = s->next)
         if ((s->flags & SEC_ALLOC) == SEC_ALLOC)
           break;
    }

  TOCstart = 0;
  if (s != NULL)
    TOCstart = s->output_section->vma + s->output_offset;

  return TOCstart;
}

Here is the call graph for this function:

Here is the caller graph for this function: