+}
+
+/* Hashtable callbacks for mips_elf_la25_stubs. */
+
+static hashval_t
+mips_elf_la25_stub_hash (const void *entry_)
+{
+ const struct mips_elf_la25_stub *entry;
+
+ entry = (struct mips_elf_la25_stub *) entry_;
+ return entry->h->root.root.u.def.section->id
+ + entry->h->root.root.u.def.value;
+}
+
+static int
+mips_elf_la25_stub_eq (const void *entry1_, const void *entry2_)
+{
+ const struct mips_elf_la25_stub *entry1, *entry2;
+
+ entry1 = (struct mips_elf_la25_stub *) entry1_;
+ entry2 = (struct mips_elf_la25_stub *) entry2_;
+ return ((entry1->h->root.root.u.def.section
+ == entry2->h->root.root.u.def.section)
+ && (entry1->h->root.root.u.def.value
+ == entry2->h->root.root.u.def.value));
+}
+
+/* Called by the linker to set up the la25 stub-creation code. FN is
+ the linker's implementation of add_stub_function. Return true on
+ success. */
+
+bfd_boolean
+_bfd_mips_elf_init_stubs (struct bfd_link_info *info,
+ asection *(*fn) (const char *, asection *,
+ asection *))
+{
+ struct mips_elf_link_hash_table *htab;
+
+ htab = mips_elf_hash_table (info);
+ if (htab == NULL)
+ return FALSE;
+
+ htab->add_stub_section = fn;
+ htab->la25_stubs = htab_try_create (1, mips_elf_la25_stub_hash,
+ mips_elf_la25_stub_eq, NULL);
+ if (htab->la25_stubs == NULL)
+ return FALSE;
+
+ return TRUE;
+}
+
+/* Return true if H is a locally-defined PIC function, in the sense
+ that it might need $25 to be valid on entry. Note that MIPS16
+ functions never need $25 to be valid on entry; they set up $gp
+ using PC-relative instructions instead. */
+
+static bfd_boolean
+mips_elf_local_pic_function_p (struct mips_elf_link_hash_entry *h)
+{
+ return ((h->root.root.type == bfd_link_hash_defined
+ || h->root.root.type == bfd_link_hash_defweak)
+ && h->root.def_regular
+ && !bfd_is_abs_section (h->root.root.u.def.section)
+ && !ELF_ST_IS_MIPS16 (h->root.other)
+ && (PIC_OBJECT_P (h->root.root.u.def.section->owner)
+ || ELF_ST_IS_MIPS_PIC (h->root.other)));
+}
+
+/* STUB describes an la25 stub that we have decided to implement
+ by inserting an LUI/ADDIU pair before the target function.
+ Create the section and redirect the function symbol to it. */
+
+static bfd_boolean
+mips_elf_add_la25_intro (struct mips_elf_la25_stub *stub,
+ struct bfd_link_info *info)
+{
+ struct mips_elf_link_hash_table *htab;
+ char *name;
+ asection *s, *input_section;
+ unsigned int align;
+
+ htab = mips_elf_hash_table (info);
+ if (htab == NULL)
+ return FALSE;
+
+ /* Create a unique name for the new section. */
+ name = bfd_malloc (11 + sizeof (".text.stub."));
+ if (name == NULL)
+ return FALSE;
+ sprintf (name, ".text.stub.%d", (int) htab_elements (htab->la25_stubs));
+
+ /* Create the section. */
+ input_section = stub->h->root.root.u.def.section;
+ s = htab->add_stub_section (name, input_section,
+ input_section->output_section);
+ if (s == NULL)
+ return FALSE;
+
+ /* Make sure that any padding goes before the stub. */
+ align = input_section->alignment_power;
+ if (!bfd_set_section_alignment (s->owner, s, align))
+ return FALSE;
+ if (align > 3)
+ s->size = (1 << align) - 8;
+
+ /* Create a symbol for the stub. */
+ mips_elf_create_stub_symbol (info, stub->h, ".pic.", s, s->size, 8);
+ stub->stub_section = s;
+ stub->offset = s->size;
+
+ /* Allocate room for it. */
+ s->size += 8;
+ return TRUE;
+}
+
+/* STUB describes an la25 stub that we have decided to implement
+ with a separate trampoline. Allocate room for it and redirect
+ the function symbol to it. */
+
+static bfd_boolean
+mips_elf_add_la25_trampoline (struct mips_elf_la25_stub *stub,
+ struct bfd_link_info *info)
+{
+ struct mips_elf_link_hash_table *htab;
+ asection *s;
+
+ htab = mips_elf_hash_table (info);
+ if (htab == NULL)
+ return FALSE;
+
+ /* Create a trampoline section, if we haven't already. */
+ s = htab->strampoline;
+ if (s == NULL)
+ {
+ asection *input_section = stub->h->root.root.u.def.section;
+ s = htab->add_stub_section (".text", NULL,
+ input_section->output_section);
+ if (s == NULL || !bfd_set_section_alignment (s->owner, s, 4))
+ return FALSE;
+ htab->strampoline = s;
+ }
+
+ /* Create a symbol for the stub. */
+ mips_elf_create_stub_symbol (info, stub->h, ".pic.", s, s->size, 16);
+ stub->stub_section = s;
+ stub->offset = s->size;
+
+ /* Allocate room for it. */
+ s->size += 16;
+ return TRUE;
+}
+
+/* H describes a symbol that needs an la25 stub. Make sure that an
+ appropriate stub exists and point H at it. */
+
+static bfd_boolean
+mips_elf_add_la25_stub (struct bfd_link_info *info,
+ struct mips_elf_link_hash_entry *h)
+{
+ struct mips_elf_link_hash_table *htab;
+ struct mips_elf_la25_stub search, *stub;
+ bfd_boolean use_trampoline_p;
+ asection *s;
+ bfd_vma value;
+ void **slot;
+
+ /* Prefer to use LUI/ADDIU stubs if the function is at the beginning
+ of the section and if we would need no more than 2 nops. */
+ s = h->root.root.u.def.section;
+ value = h->root.root.u.def.value;
+ use_trampoline_p = (value != 0 || s->alignment_power > 4);
+
+ /* Describe the stub we want. */
+ search.stub_section = NULL;
+ search.offset = 0;
+ search.h = h;
+
+ /* See if we've already created an equivalent stub. */
+ htab = mips_elf_hash_table (info);
+ if (htab == NULL)
+ return FALSE;
+
+ slot = htab_find_slot (htab->la25_stubs, &search, INSERT);
+ if (slot == NULL)
+ return FALSE;
+
+ stub = (struct mips_elf_la25_stub *) *slot;
+ if (stub != NULL)
+ {
+ /* We can reuse the existing stub. */
+ h->la25_stub = stub;
+ return TRUE;
+ }
+
+ /* Create a permanent copy of ENTRY and add it to the hash table. */
+ stub = bfd_malloc (sizeof (search));
+ if (stub == NULL)
+ return FALSE;
+ *stub = search;
+ *slot = stub;
+
+ h->la25_stub = stub;
+ return (use_trampoline_p
+ ? mips_elf_add_la25_trampoline (stub, info)
+ : mips_elf_add_la25_intro (stub, info));
+}
+
+/* A mips_elf_link_hash_traverse callback that is called before sizing
+ sections. DATA points to a mips_htab_traverse_info structure. */
+
+static bfd_boolean
+mips_elf_check_symbols (struct mips_elf_link_hash_entry *h, void *data)
+{
+ struct mips_htab_traverse_info *hti;
+
+ hti = (struct mips_htab_traverse_info *) data;
+ if (h->root.root.type == bfd_link_hash_warning)
+ h = (struct mips_elf_link_hash_entry *) h->root.root.u.i.link;