+ bfd_vma addr, off, limit;
+
+ if (htab == NULL)
+ return FALSE;
+
+ if (!htab->second_toc_pass)
+ {
+ /* Keep track of the first .toc or .got section for this input bfd. */
+ if (htab->toc_bfd != isec->owner)
+ {
+ htab->toc_bfd = isec->owner;
+ htab->toc_first_sec = isec;
+ }
+
+ addr = isec->output_offset + isec->output_section->vma;
+ off = addr - htab->toc_curr;
+ limit = 0x80008000;
+ if (ppc64_elf_tdata (isec->owner)->has_small_toc_reloc)
+ limit = 0x10000;
+ if (off + isec->size > limit)
+ {
+ addr = (htab->toc_first_sec->output_offset
+ + htab->toc_first_sec->output_section->vma);
+ htab->toc_curr = addr;
+ }
+
+ /* toc_curr is the base address of this toc group. Set elf_gp
+ for the input section to be the offset relative to the
+ output toc base plus 0x8000. Making the input elf_gp an
+ offset allows us to move the toc as a whole without
+ recalculating input elf_gp. */
+ off = htab->toc_curr - elf_gp (isec->output_section->owner);
+ off += TOC_BASE_OFF;
+
+ /* Die if someone uses a linker script that doesn't keep input
+ file .toc and .got together. */
+ if (elf_gp (isec->owner) != 0
+ && elf_gp (isec->owner) != off)
+ return FALSE;
+
+ elf_gp (isec->owner) = off;
+ return TRUE;
+ }
+
+ /* During the second pass toc_first_sec points to the start of
+ a toc group, and toc_curr is used to track the old elf_gp.
+ We use toc_bfd to ensure we only look at each bfd once. */
+ if (htab->toc_bfd == isec->owner)
+ return TRUE;
+ htab->toc_bfd = isec->owner;
+
+ if (htab->toc_first_sec == NULL
+ || htab->toc_curr != elf_gp (isec->owner))
+ {
+ htab->toc_curr = elf_gp (isec->owner);
+ htab->toc_first_sec = isec;
+ }
+ addr = (htab->toc_first_sec->output_offset
+ + htab->toc_first_sec->output_section->vma);
+ off = addr - elf_gp (isec->output_section->owner) + TOC_BASE_OFF;
+ elf_gp (isec->owner) = off;
+
+ return TRUE;
+}
+
+/* Called via elf_link_hash_traverse to merge GOT entries for global
+ symbol H. */
+
+static bfd_boolean
+merge_global_got (struct elf_link_hash_entry *h, void *inf ATTRIBUTE_UNUSED)
+{
+ if (h->root.type == bfd_link_hash_indirect)
+ return TRUE;
+
+ merge_got_entries (&h->got.glist);
+
+ return TRUE;
+}
+
+/* Called via elf_link_hash_traverse to allocate GOT entries for global
+ symbol H. */
+
+static bfd_boolean
+reallocate_got (struct elf_link_hash_entry *h, void *inf)
+{
+ struct got_entry *gent;
+
+ if (h->root.type == bfd_link_hash_indirect)
+ return TRUE;
+
+ for (gent = h->got.glist; gent != NULL; gent = gent->next)
+ if (!gent->is_indirect)
+ allocate_got (h, (struct bfd_link_info *) inf, gent);
+ return TRUE;
+}
+
+/* Called on the first multitoc pass after the last call to
+ ppc64_elf_next_toc_section. This function removes duplicate GOT
+ entries. */
+
+bfd_boolean
+ppc64_elf_layout_multitoc (struct bfd_link_info *info)
+{
+ struct ppc_link_hash_table *htab = ppc_hash_table (info);
+ struct bfd *ibfd, *ibfd2;
+ bfd_boolean done_something;