+ if (h->plt.refcount <= 0
+ || ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0
+ && h->root.type != bfd_link_hash_defweak
+ && ! ((struct elf32_hppa_link_hash_entry *) h)->plabel
+ && (!info->shared || info->symbolic)))
+ {
+ /* The .plt entry is not needed when:
+ a) Garbage collection has removed all references to the
+ symbol, or
+ b) We know for certain the symbol is defined in this
+ object, and it's not a weak definition, nor is the symbol
+ used by a plabel relocation. Either this object is the
+ application or we are doing a shared symbolic link. */
+
+ /* As a special sop to the hppa ABI, we keep a .plt entry
+ for functions in sections containing PIC code. */
+ if (((struct elf32_hppa_link_hash_entry *) h)->maybe_pic_call)
+ ((struct elf32_hppa_link_hash_entry *) h)->pic_call = 1;
+ else
+ {
+ h->plt.offset = (bfd_vma) -1;
+ h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
+ return true;
+ }
+ }
+
+ /* Make an entry in the .plt section. */
+ s = hplink->splt;
+ h->plt.offset = s->_raw_size;
+ if (PLABEL_PLT_ENTRY_SIZE != PLT_ENTRY_SIZE
+ && ((struct elf32_hppa_link_hash_entry *) h)->plabel
+ && (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0)
+ {
+ /* Add some extra space for the dynamic linker to use. */
+ s->_raw_size += PLABEL_PLT_ENTRY_SIZE;
+ }
+ else
+ s->_raw_size += PLT_ENTRY_SIZE;
+
+ if (! ((struct elf32_hppa_link_hash_entry *) h)->pic_call)
+ {
+ /* Make sure this symbol is output as a dynamic symbol. */
+ if (h->dynindx == -1
+ && (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0)
+ {
+ if (! bfd_elf32_link_record_dynamic_symbol (info, h))
+ return false;
+ }
+
+ /* We also need to make an entry in the .rela.plt section. */
+ s = hplink->srelplt;
+ s->_raw_size += sizeof (Elf32_External_Rela);
+
+ hplink->need_plt_stub = 1;
+ }
+ return true;
+ }
+
+ /* If this is a weak symbol, and there is a real definition, the
+ processor independent code will have arranged for us to see the
+ real definition first, and we can just use the same value. */
+ if (h->weakdef != NULL)
+ {
+ BFD_ASSERT (h->weakdef->root.type == bfd_link_hash_defined
+ || h->weakdef->root.type == bfd_link_hash_defweak);
+ h->root.u.def.section = h->weakdef->root.u.def.section;
+ h->root.u.def.value = h->weakdef->root.u.def.value;
+ return true;
+ }
+
+ /* This is a reference to a symbol defined by a dynamic object which
+ is not a function. */
+
+ /* If we are creating a shared library, we must presume that the
+ only references to the symbol are via the global offset table.
+ For such cases we need not do anything here; the relocations will
+ be handled correctly by relocate_section. */
+ if (info->shared)
+ return true;
+
+ /* If there are no references to this symbol that do not use the
+ GOT, we don't need to generate a copy reloc. */
+ if ((h->elf_link_hash_flags & ELF_LINK_NON_GOT_REF) == 0)
+ return true;
+
+ /* We must allocate the symbol in our .dynbss section, which will
+ become part of the .bss section of the executable. There will be
+ an entry for this symbol in the .dynsym section. The dynamic
+ object will contain position independent code, so all references
+ from the dynamic object to this symbol will go through the global
+ offset table. The dynamic linker will use the .dynsym entry to
+ determine the address it must put in the global offset table, so
+ both the dynamic object and the regular object will refer to the
+ same memory location for the variable. */
+
+ s = hplink->sdynbss;
+
+ /* We must generate a COPY reloc to tell the dynamic linker to
+ copy the initial value out of the dynamic object and into the
+ runtime process image. We need to remember the offset into the
+ .rela.bss section we are going to use. */
+ if ((h->root.u.def.section->flags & SEC_ALLOC) != 0)
+ {
+ asection *srel;
+
+ srel = hplink->srelbss;
+ srel->_raw_size += sizeof (Elf32_External_Rela);
+ h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_COPY;
+ }
+
+ {
+ /* We need to figure out the alignment required for this symbol. I
+ have no idea how other ELF linkers handle this. */
+ unsigned int power_of_two;
+
+ power_of_two = bfd_log2 (h->size);
+ if (power_of_two > 3)
+ power_of_two = 3;
+
+ /* Apply the required alignment. */
+ s->_raw_size = BFD_ALIGN (s->_raw_size,
+ (bfd_size_type) (1 << power_of_two));
+ if (power_of_two > bfd_get_section_alignment (dynobj, s))
+ {
+ if (! bfd_set_section_alignment (dynobj, s, power_of_two))
+ return false;
+ }
+ }
+ /* Define the symbol as being at this point in the section. */
+ h->root.u.def.section = s;
+ h->root.u.def.value = s->_raw_size;
+
+ /* Increment the section size to make room for the symbol. */
+ s->_raw_size += h->size;
+
+ return true;
+}
+
+/* Called via elf_link_hash_traverse to create .plt entries for an
+ application that uses statically linked PIC functions. Similar to
+ the first part of elf32_hppa_adjust_dynamic_symbol. */
+
+static boolean
+hppa_handle_PIC_calls (h, inf)
+ struct elf_link_hash_entry *h;
+ PTR inf;
+{
+ struct bfd_link_info *info;
+ bfd *dynobj;
+ struct elf32_hppa_link_hash_table *hplink;
+ asection *s;
+
+ if (! (h->plt.refcount > 0
+ && (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ && (h->root.u.def.section->flags & SEC_HAS_GOT_REF) != 0))
+ {
+ h->plt.offset = (bfd_vma) -1;
+ h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
+ return true;
+ }
+
+ h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
+ ((struct elf32_hppa_link_hash_entry *) h)->maybe_pic_call = 1;
+ ((struct elf32_hppa_link_hash_entry *) h)->pic_call = 1;
+
+ info = (struct bfd_link_info *) inf;
+ hplink = hppa_link_hash_table (info);
+ dynobj = hplink->root.dynobj;
+
+ /* Make an entry in the .plt section. */
+ s = hplink->splt;
+ h->plt.offset = s->_raw_size;
+ s->_raw_size += PLT_ENTRY_SIZE;
+
+ return true;
+}
+
+#if ((! LONG_BRANCH_PIC_IN_SHLIB && LONG_BRANCH_VIA_PLT) \
+ || RELATIVE_DYNAMIC_RELOCS)
+/* This function is called via elf_link_hash_traverse to discard space
+ we allocated for relocs that it turned out we didn't need. */
+
+static boolean
+hppa_discard_copies (h, inf)
+ struct elf_link_hash_entry *h;
+ PTR inf;
+{
+ struct elf32_hppa_dyn_reloc_entry *s;
+ struct elf32_hppa_link_hash_entry *eh;
+ struct bfd_link_info *info;
+
+ eh = (struct elf32_hppa_link_hash_entry *) h;
+ info = (struct bfd_link_info *) inf;
+
+#if ! LONG_BRANCH_PIC_IN_SHLIB && LONG_BRANCH_VIA_PLT
+ /* Handle the stub reloc case. If we have a plt entry for the
+ function, we won't be needing long branch stubs. s->count will
+ only be zero for stub relocs, which provides a handy way of
+ flagging these relocs, and means we need do nothing special for
+ the forced local and symbolic link case. */
+ if (eh->stub_reloc_sec != NULL
+ && eh->elf.plt.offset != (bfd_vma) -1)
+ {
+ for (s = eh->reloc_entries; s != NULL; s = s->next)
+ if (s->count == 0)
+ s->section->_raw_size -= sizeof (Elf32_External_Rela);
+ }
+#endif
+
+#if RELATIVE_DYNAMIC_RELOCS
+ /* If a symbol has been forced local or we have found a regular
+ definition for the symbolic link case, then we won't be needing
+ any relocs. */
+ if (eh->elf.dynindx == -1
+ || ((eh->elf.elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0
+ && !is_absolute_reloc (r_type)
+ && info->symbolic))
+ {
+ for (s = eh->reloc_entries; s != NULL; s = s->next)
+ s->section->_raw_size -= s->count * sizeof (Elf32_External_Rela);
+ }
+#endif
+
+ return true;
+}
+#endif
+
+/* This function is called via elf_link_hash_traverse to force
+ millicode symbols local so they do not end up as globals in the
+ dynamic symbol table. We ought to be able to do this in
+ adjust_dynamic_symbol, but our adjust_dynamic_symbol is not called
+ for all dynamic symbols. Arguably, this is a bug in
+ elf_adjust_dynamic_symbol. */
+
+static boolean
+clobber_millicode_symbols (h, info)
+ struct elf_link_hash_entry *h;
+ struct bfd_link_info *info;
+{
+ /* Note! We only want to remove these from the dynamic symbol
+ table. Therefore we do not set ELF_LINK_FORCED_LOCAL. */
+ if (h->type == STT_PARISC_MILLI)
+ elf32_hppa_hide_symbol (info, h);
+ return true;
+}
+
+/* Set the sizes of the dynamic sections. */
+
+static boolean
+elf32_hppa_size_dynamic_sections (output_bfd, info)
+ bfd *output_bfd;
+ struct bfd_link_info *info;
+{
+ struct elf32_hppa_link_hash_table *hplink;
+ bfd *dynobj;
+ asection *s;
+ boolean relocs;
+ boolean reltext;
+
+ hplink = hppa_link_hash_table (info);
+ dynobj = hplink->root.dynobj;
+ BFD_ASSERT (dynobj != NULL);
+
+ if (hplink->root.dynamic_sections_created)
+ {
+ bfd *i;
+
+ /* Set the contents of the .interp section to the interpreter. */
+ if (! info->shared)
+ {
+ s = bfd_get_section_by_name (dynobj, ".interp");
+ BFD_ASSERT (s != NULL);
+ s->_raw_size = sizeof ELF_DYNAMIC_INTERPRETER;
+ s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
+ }
+
+ /* Force millicode symbols local. */
+ elf_link_hash_traverse (&hplink->root,
+ clobber_millicode_symbols,
+ info);
+
+ /* Set up .plt offsets for local plabels. */
+ for (i = info->input_bfds; i; i = i->link_next)
+ {
+ bfd_signed_vma *local_plt;
+ bfd_signed_vma *end_local_plt;
+ bfd_size_type locsymcount;
+ Elf_Internal_Shdr *symtab_hdr;
+
+ local_plt = elf_local_got_refcounts (i);
+ if (!local_plt)
+ continue;
+
+ symtab_hdr = &elf_tdata (i)->symtab_hdr;
+ locsymcount = symtab_hdr->sh_info;
+ local_plt += locsymcount;
+ end_local_plt = local_plt + locsymcount;
+
+ for (; local_plt < end_local_plt; ++local_plt)
+ {
+ if (*local_plt > 0)
+ {
+ s = hplink->splt;
+ *local_plt = s->_raw_size;
+ s->_raw_size += PLT_ENTRY_SIZE;
+ if (info->shared)
+ hplink->srelplt->_raw_size += sizeof (Elf32_External_Rela);
+ }
+ else
+ *local_plt = (bfd_vma) -1;
+ }
+ }
+ }
+ else
+ {
+ /* Run through the function symbols, looking for any that are
+ PIC, and allocate space for the necessary .plt entries so
+ that %r19 will be set up. */
+ if (! info->shared)
+ elf_link_hash_traverse (&hplink->root,
+ hppa_handle_PIC_calls,
+ info);
+
+ /* We may have created entries in the .rela.got section.
+ However, if we are not creating the dynamic sections, we will
+ not actually use these entries. Reset the size of .rela.got,
+ which will cause it to get stripped from the output file
+ below. */
+ hplink->srelgot->_raw_size = 0;
+ }
+
+#if ((! LONG_BRANCH_PIC_IN_SHLIB && LONG_BRANCH_VIA_PLT) \
+ || RELATIVE_DYNAMIC_RELOCS)
+ /* If this is a -Bsymbolic shared link, then we need to discard all
+ relocs against symbols defined in a regular object. We also need
+ to lose relocs we've allocated for long branch stubs if we know
+ we won't be generating a stub. */
+ if (info->shared)
+ elf_link_hash_traverse (&hplink->root,
+ hppa_discard_copies,
+ info);
+#endif
+
+ /* The check_relocs and adjust_dynamic_symbol entry points have
+ determined the sizes of the various dynamic sections. Allocate
+ memory for them. */
+ relocs = false;
+ reltext = false;
+ for (s = dynobj->sections; s != NULL; s = s->next)
+ {
+ const char *name;
+
+ if ((s->flags & SEC_LINKER_CREATED) == 0)
+ continue;
+
+ /* It's OK to base decisions on the section name, because none
+ of the dynobj section names depend upon the input files. */
+ name = bfd_get_section_name (dynobj, s);
+
+ if (strncmp (name, ".rela", 5) == 0)
+ {
+ if (s->_raw_size != 0)
+ {
+ asection *target;
+ const char *outname;
+
+ /* Remember whether there are any reloc sections other
+ than .rela.plt. */
+ if (strcmp (name+5, ".plt") != 0)
+ relocs = true;
+
+ /* If this relocation section applies to a read only
+ section, then we probably need a DT_TEXTREL entry. */
+ outname = bfd_get_section_name (output_bfd,
+ s->output_section);
+ target = bfd_get_section_by_name (output_bfd, outname + 5);
+ if (target != NULL
+ && (target->flags & SEC_READONLY) != 0
+ && (target->flags & SEC_ALLOC) != 0)
+ reltext = true;
+
+ /* We use the reloc_count field as a counter if we need
+ to copy relocs into the output file. */
+ s->reloc_count = 0;
+ }
+ }
+ else if (strcmp (name, ".plt") == 0)
+ {
+ if (hplink->need_plt_stub)
+ {
+ /* Make space for the plt stub at the end of the .plt
+ section. We want this stub right at the end, up
+ against the .got section. */
+ int gotalign = bfd_section_alignment (dynobj, hplink->sgot);
+ int pltalign = bfd_section_alignment (dynobj, s);
+ bfd_size_type mask;
+
+ if (gotalign > pltalign)
+ bfd_set_section_alignment (dynobj, s, gotalign);
+ mask = ((bfd_size_type) 1 << gotalign) - 1;
+ s->_raw_size = (s->_raw_size + sizeof (plt_stub) + mask) & ~mask;
+ }
+ }
+ else if (strcmp (name, ".got") == 0)
+ ;
+ else
+ {
+ /* It's not one of our sections, so don't allocate space. */
+ continue;
+ }
+
+ if (s->_raw_size == 0)
+ {
+ /* If we don't need this section, strip it from the
+ output file. This is mostly to handle .rela.bss and
+ .rela.plt. We must create both sections in
+ create_dynamic_sections, because they must be created
+ before the linker maps input sections to output
+ sections. The linker does that before
+ adjust_dynamic_symbol is called, and it is that
+ function which decides whether anything needs to go
+ into these sections. */
+ _bfd_strip_section_from_output (info, s);
+ continue;
+ }
+
+ /* Allocate memory for the section contents. Zero it, because
+ we may not fill in all the reloc sections. */
+ s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->_raw_size);
+ if (s->contents == NULL && s->_raw_size != 0)
+ return false;
+ }
+
+ if (hplink->root.dynamic_sections_created)
+ {
+ /* Like IA-64 and HPPA64, always create a DT_PLTGOT. It
+ actually has nothing to do with the PLT, it is how we
+ communicate the LTP value of a load module to the dynamic
+ linker. */
+ if (! bfd_elf32_add_dynamic_entry (info, DT_PLTGOT, 0))
+ return false;
+
+ /* Add some entries to the .dynamic section. We fill in the
+ values later, in elf32_hppa_finish_dynamic_sections, but we
+ must add the entries now so that we get the correct size for
+ the .dynamic section. The DT_DEBUG entry is filled in by the
+ dynamic linker and used by the debugger. */
+ if (! info->shared)
+ {
+ if (! bfd_elf32_add_dynamic_entry (info, DT_DEBUG, 0))
+ return false;
+ }
+
+ if (hplink->srelplt->_raw_size != 0)
+ {
+ if (! bfd_elf32_add_dynamic_entry (info, DT_PLTRELSZ, 0)
+ || ! bfd_elf32_add_dynamic_entry (info, DT_PLTREL, DT_RELA)
+ || ! bfd_elf32_add_dynamic_entry (info, DT_JMPREL, 0))
+ return false;
+ }
+
+ if (relocs)
+ {
+ if (! bfd_elf32_add_dynamic_entry (info, DT_RELA, 0)
+ || ! bfd_elf32_add_dynamic_entry (info, DT_RELASZ, 0)
+ || ! bfd_elf32_add_dynamic_entry (info, DT_RELAENT,
+ sizeof (Elf32_External_Rela)))
+ return false;
+ }
+
+ if (reltext)
+ {
+ if (! bfd_elf32_add_dynamic_entry (info, DT_TEXTREL, 0))
+ return false;
+ info->flags |= DF_TEXTREL;
+ }
+ }
+
+ return true;
+}
+
+/* External entry points for sizing and building linker stubs. */
+
+/* Determine and set the size of the stub section for a final link.
+
+ The basic idea here is to examine all the relocations looking for
+ PC-relative calls to a target that is unreachable with a "bl"
+ instruction. */
+
+boolean
+elf32_hppa_size_stubs (output_bfd, stub_bfd, info, multi_subspace, group_size,
+ add_stub_section, layout_sections_again)
+ bfd *output_bfd;
+ bfd *stub_bfd;
+ struct bfd_link_info *info;
+ boolean multi_subspace;
+ bfd_signed_vma group_size;
+ asection * (*add_stub_section) PARAMS ((const char *, asection *));
+ void (*layout_sections_again) PARAMS ((void));
+{
+ bfd *input_bfd;
+ asection *section;
+ asection **input_list, **list;
+ Elf_Internal_Sym *local_syms, **all_local_syms;
+ unsigned int bfd_indx, bfd_count;
+ int top_id, top_index;
+ struct elf32_hppa_link_hash_table *hplink;
+ bfd_size_type stub_group_size;
+ boolean stubs_always_before_branch;
+ boolean stub_changed = 0;
+ boolean ret = 0;
+
+ hplink = hppa_link_hash_table (info);
+
+ /* Stash our params away. */
+ hplink->stub_bfd = stub_bfd;
+ hplink->multi_subspace = multi_subspace;
+ hplink->add_stub_section = add_stub_section;
+ hplink->layout_sections_again = layout_sections_again;
+ stubs_always_before_branch = group_size < 0;
+ if (group_size < 0)
+ stub_group_size = -group_size;
+ else
+ stub_group_size = group_size;
+ if (stub_group_size == 1)
+ {
+ /* Default values. */
+ stub_group_size = 8000000;
+ if (hplink->has_17bit_branch || hplink->multi_subspace)
+ stub_group_size = 250000;
+ if (hplink->has_12bit_branch)
+ stub_group_size = 7812;
+ }
+
+ /* Count the number of input BFDs and find the top input section id. */
+ for (input_bfd = info->input_bfds, bfd_count = 0, top_id = 0;
+ input_bfd != NULL;
+ input_bfd = input_bfd->link_next)
+ {
+ bfd_count += 1;
+ for (section = input_bfd->sections;
+ section != NULL;
+ section = section->next)
+ {
+ if (top_id < section->id)
+ top_id = section->id;
+ }
+ }
+
+ hplink->stub_group
+ = (struct map_stub *) bfd_zmalloc (sizeof (struct map_stub) * (top_id + 1));
+ if (hplink->stub_group == NULL)
+ return false;
+
+ /* Make a list of input sections for each output section included in
+ the link.
+
+ We can't use output_bfd->section_count here to find the top output
+ section index as some sections may have been removed, and
+ _bfd_strip_section_from_output 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;
+ }
+
+ input_list
+ = (asection **) bfd_malloc (sizeof (asection *) * (top_index + 1));
+ if (input_list == NULL)
+ return false;
+
+ /* For sections we aren't interested in, mark their entries with a
+ value we can check later. */
+ list = input_list + top_index;
+ do
+ *list = bfd_abs_section_ptr;
+ while (list-- != input_list);
+
+ for (section = output_bfd->sections;
+ section != NULL;
+ section = section->next)
+ {
+ if ((section->flags & SEC_CODE) != 0)
+ input_list[section->index] = NULL;
+ }
+
+ /* Now actually build the lists. */
+ for (input_bfd = info->input_bfds;
+ input_bfd != NULL;
+ input_bfd = input_bfd->link_next)
+ {
+ for (section = input_bfd->sections;
+ section != NULL;
+ section = section->next)
+ {
+ if (section->output_section != NULL
+ && section->output_section->owner == output_bfd
+ && section->output_section->index <= top_index)
+ {
+ list = input_list + section->output_section->index;
+ if (*list != bfd_abs_section_ptr)
+ {
+ /* Steal the link_sec pointer for our list. */
+#define PREV_SEC(sec) (hplink->stub_group[(sec)->id].link_sec)
+ /* This happens to make the list in reverse order,
+ which is what we want. */
+ PREV_SEC (section) = *list;
+ *list = section;
+ }
+ }
+ }
+ }
+
+ /* See whether we can group stub sections together. Grouping stub
+ sections may result in fewer stubs. More importantly, we need to
+ put all .init* and .fini* stubs at the beginning of the .init or
+ .fini output sections respectively, because glibc splits the
+ _init and _fini functions into multiple parts. Putting a stub in
+ the middle of a function is not a good idea. */
+ list = input_list + top_index;
+ do
+ {
+ asection *tail = *list;
+ if (tail == bfd_abs_section_ptr)
+ continue;
+ while (tail != NULL)
+ {
+ asection *curr;
+ asection *prev;
+ bfd_size_type total;
+
+ curr = tail;
+ if (tail->_cooked_size)
+ total = tail->_cooked_size;
+ else
+ total = tail->_raw_size;
+ while ((prev = PREV_SEC (curr)) != NULL
+ && ((total += curr->output_offset - prev->output_offset)
+ < stub_group_size))
+ curr = prev;
+
+ /* OK, the size from the start of CURR to the end is less
+ than 250000 bytes and thus can be handled by one stub
+ section. (or the tail section is itself larger than
+ 250000 bytes, in which case we may be toast.)
+ We should really be keeping track of the total size of
+ stubs added here, as stubs contribute to the final output
+ section size. That's a little tricky, and this way will
+ only break if stubs added total more than 12144 bytes, or
+ 1518 long branch stubs. It seems unlikely for more than
+ 1518 different functions to be called, especially from
+ code only 250000 bytes long. */
+ do
+ {
+ prev = PREV_SEC (tail);
+ /* Set up this stub group. */
+ hplink->stub_group[tail->id].link_sec = curr;
+ }
+ while (tail != curr && (tail = prev) != NULL);
+
+ /* But wait, there's more! Input sections up to 250000
+ bytes before the stub section can be handled by it too. */
+ if (!stubs_always_before_branch)
+ {
+ total = 0;
+ while (prev != NULL
+ && ((total += tail->output_offset - prev->output_offset)
+ < stub_group_size))
+ {
+ tail = prev;
+ prev = PREV_SEC (tail);
+ hplink->stub_group[tail->id].link_sec = curr;
+ }
+ }
+ tail = prev;
+ }
+ }
+ while (list-- != input_list);
+ free (input_list);
+#undef PREV_SEC
+
+ /* We want to read in symbol extension records only once. To do this
+ we need to read in the local symbols in parallel and save them for
+ later use; so hold pointers to the local symbols in an array. */
+ all_local_syms
+ = (Elf_Internal_Sym **) bfd_zmalloc (sizeof (Elf_Internal_Sym *)
+ * bfd_count);
+ if (all_local_syms == NULL)
+ return false;
+
+ /* Walk over all the input BFDs, swapping in local symbols.
+ If we are creating a shared library, create hash entries for the
+ export stubs. */
+ for (input_bfd = info->input_bfds, bfd_indx = 0;
+ input_bfd != NULL;
+ input_bfd = input_bfd->link_next, bfd_indx++)
+ {
+ Elf_Internal_Shdr *symtab_hdr;
+ Elf_Internal_Sym *isym;
+ Elf32_External_Sym *ext_syms, *esym, *end_sy;
+
+ /* We'll need the symbol table in a second. */
+ symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+ if (symtab_hdr->sh_info == 0)
+ continue;
+
+ /* We need an array of the local symbols attached to the input bfd.
+ Unfortunately, we're going to have to read & swap them in. */
+ local_syms = (Elf_Internal_Sym *)
+ bfd_malloc (symtab_hdr->sh_info * sizeof (Elf_Internal_Sym));
+ if (local_syms == NULL)
+ {
+ goto error_ret_free_local;
+ }
+ all_local_syms[bfd_indx] = local_syms;
+ ext_syms = (Elf32_External_Sym *)
+ bfd_malloc (symtab_hdr->sh_info * sizeof (Elf32_External_Sym));
+ if (ext_syms == NULL)
+ {
+ goto error_ret_free_local;
+ }
+
+ if (bfd_seek (input_bfd, symtab_hdr->sh_offset, SEEK_SET) != 0
+ || (bfd_read (ext_syms, 1,
+ (symtab_hdr->sh_info * sizeof (Elf32_External_Sym)),
+ input_bfd)
+ != (symtab_hdr->sh_info * sizeof (Elf32_External_Sym))))
+ {
+ free (ext_syms);
+ goto error_ret_free_local;
+ }
+
+ /* Swap the local symbols in. */
+ isym = local_syms;
+ esym = ext_syms;
+ for (end_sy = esym + symtab_hdr->sh_info; esym < end_sy; esym++, isym++)
+ bfd_elf32_swap_symbol_in (input_bfd, esym, isym);
+
+ /* Now we can free the external symbols. */
+ free (ext_syms);
+
+#if ! LONG_BRANCH_PIC_IN_SHLIB
+ /* If this is a shared link, find all the stub reloc sections. */
+ if (info->shared)
+ for (section = input_bfd->sections;
+ section != NULL;
+ section = section->next)
+ {
+ char *name;
+ asection *reloc_sec;
+
+ name = bfd_malloc (strlen (section->name)
+ + sizeof STUB_SUFFIX
+ + 5);
+ if (name == NULL)
+ return false;
+ sprintf (name, ".rela%s%s", section->name, STUB_SUFFIX);
+ reloc_sec = bfd_get_section_by_name (hplink->root.dynobj, name);
+ hplink->stub_group[section->id].reloc_sec = reloc_sec;
+ free (name);
+ }
+#endif
+
+ if (info->shared && hplink->multi_subspace)
+ {
+ struct elf_link_hash_entry **sym_hashes;
+ struct elf_link_hash_entry **end_hashes;
+ unsigned int symcount;
+
+ symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)
+ - symtab_hdr->sh_info);
+ sym_hashes = elf_sym_hashes (input_bfd);
+ end_hashes = sym_hashes + symcount;
+
+ /* Look through the global syms for functions; We need to
+ build export stubs for all globally visible functions. */
+ for (; sym_hashes < end_hashes; sym_hashes++)
+ {
+ struct elf32_hppa_link_hash_entry *hash;
+
+ hash = (struct elf32_hppa_link_hash_entry *) *sym_hashes;
+
+ while (hash->elf.root.type == bfd_link_hash_indirect
+ || hash->elf.root.type == bfd_link_hash_warning)
+ hash = ((struct elf32_hppa_link_hash_entry *)
+ hash->elf.root.u.i.link);
+
+ /* At this point in the link, undefined syms have been
+ resolved, so we need to check that the symbol was
+ defined in this BFD. */
+ if ((hash->elf.root.type == bfd_link_hash_defined
+ || hash->elf.root.type == bfd_link_hash_defweak)
+ && hash->elf.type == STT_FUNC
+ && hash->elf.root.u.def.section->output_section != NULL
+ && (hash->elf.root.u.def.section->output_section->owner
+ == output_bfd)
+ && hash->elf.root.u.def.section->owner == input_bfd
+ && (hash->elf.elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)
+ && !(hash->elf.elf_link_hash_flags & ELF_LINK_FORCED_LOCAL)
+ && ELF_ST_VISIBILITY (hash->elf.other) == STV_DEFAULT)
+ {
+ asection *sec;
+ const char *stub_name;
+ struct elf32_hppa_stub_hash_entry *stub_entry;
+
+ sec = hash->elf.root.u.def.section;
+ stub_name = hash->elf.root.root.string;
+ stub_entry = hppa_stub_hash_lookup (&hplink->stub_hash_table,
+ stub_name,
+ false, false);
+ if (stub_entry == NULL)
+ {
+ stub_entry = hppa_add_stub (stub_name, sec, hplink);
+ if (!stub_entry)
+ goto error_ret_free_local;
+
+ stub_entry->target_value = hash->elf.root.u.def.value;
+ stub_entry->target_section = hash->elf.root.u.def.section;
+ stub_entry->stub_type = hppa_stub_export;
+ stub_entry->h = hash;
+ stub_changed = 1;
+ }
+ else
+ {
+ (*_bfd_error_handler) (_("%s: duplicate export stub %s"),
+ bfd_get_filename (input_bfd),
+ stub_name);
+ }
+ }
+ }
+ }
+ }
+
+ while (1)
+ {
+ asection *stub_sec;
+
+ for (input_bfd = info->input_bfds, bfd_indx = 0;
+ input_bfd != NULL;
+ input_bfd = input_bfd->link_next, bfd_indx++)
+ {
+ Elf_Internal_Shdr *symtab_hdr;
+
+ /* We'll need the symbol table in a second. */
+ symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+ if (symtab_hdr->sh_info == 0)
+ continue;
+
+ local_syms = all_local_syms[bfd_indx];
+
+ /* Walk over each section attached to the input bfd. */
+ for (section = input_bfd->sections;
+ section != NULL;
+ section = section->next)
+ {
+ Elf_Internal_Shdr *input_rel_hdr;
+ Elf32_External_Rela *external_relocs, *erelaend, *erela;
+ 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->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;
+
+ /* Allocate space for the external relocations. */
+ external_relocs
+ = ((Elf32_External_Rela *)
+ bfd_malloc (section->reloc_count
+ * sizeof (Elf32_External_Rela)));
+ if (external_relocs == NULL)
+ {
+ goto error_ret_free_local;
+ }
+
+ /* Likewise for the internal relocations. */
+ internal_relocs = ((Elf_Internal_Rela *)
+ bfd_malloc (section->reloc_count
+ * sizeof (Elf_Internal_Rela)));
+ if (internal_relocs == NULL)
+ {
+ free (external_relocs);
+ goto error_ret_free_local;
+ }
+
+ /* Read in the external relocs. */
+ input_rel_hdr = &elf_section_data (section)->rel_hdr;
+ if (bfd_seek (input_bfd, input_rel_hdr->sh_offset, SEEK_SET) != 0
+ || bfd_read (external_relocs, 1,
+ input_rel_hdr->sh_size,
+ input_bfd) != input_rel_hdr->sh_size)
+ {
+ free (external_relocs);
+ error_ret_free_internal:
+ free (internal_relocs);
+ goto error_ret_free_local;
+ }
+
+ /* Swap in the relocs. */
+ erela = external_relocs;
+ erelaend = erela + section->reloc_count;
+ irela = internal_relocs;
+ for (; erela < erelaend; erela++, irela++)
+ bfd_elf32_swap_reloca_in (input_bfd, erela, irela);
+
+ /* We're done with the external relocs, free them. */
+ free (external_relocs);
+
+ /* Now examine each relocation. */
+ irela = internal_relocs;
+ irelaend = irela + section->reloc_count;
+ for (; irela < irelaend; irela++)
+ {
+ unsigned int r_type, r_indx;
+ enum elf32_hppa_stub_type stub_type;
+ struct elf32_hppa_stub_hash_entry *stub_entry;
+ asection *sym_sec;
+ bfd_vma sym_value;
+ bfd_vma destination;
+ struct elf32_hppa_link_hash_entry *hash;
+ char *stub_name;
+ const asection *id_sec;
+
+ r_type = ELF32_R_TYPE (irela->r_info);
+ r_indx = ELF32_R_SYM (irela->r_info);
+
+ if (r_type >= (unsigned int) R_PARISC_UNIMPLEMENTED)
+ {
+ bfd_set_error (bfd_error_bad_value);
+ goto error_ret_free_internal;
+ }
+
+ /* Only look for stubs on call instructions. */
+ if (r_type != (unsigned int) R_PARISC_PCREL12F
+ && r_type != (unsigned int) R_PARISC_PCREL17F
+ && r_type != (unsigned int) R_PARISC_PCREL22F)
+ continue;
+
+ /* Now determine the call target, its name, value,
+ section. */
+ sym_sec = NULL;
+ sym_value = 0;
+ destination = 0;
+ hash = NULL;
+ if (r_indx < symtab_hdr->sh_info)
+ {
+ /* It's a local symbol. */
+ Elf_Internal_Sym *sym;
+ Elf_Internal_Shdr *hdr;
+
+ sym = local_syms + r_indx;
+ hdr = elf_elfsections (input_bfd)[sym->st_shndx];
+ sym_sec = hdr->bfd_section;
+ if (ELF_ST_TYPE (sym->st_info) != STT_SECTION)
+ sym_value = sym->st_value;
+ destination = (sym_value + irela->r_addend
+ + sym_sec->output_offset
+ + sym_sec->output_section->vma);
+ }
+ else
+ {
+ /* It's an external symbol. */
+ int e_indx;
+
+ e_indx = r_indx - symtab_hdr->sh_info;
+ hash = ((struct elf32_hppa_link_hash_entry *)
+ elf_sym_hashes (input_bfd)[e_indx]);
+
+ while (hash->elf.root.type == bfd_link_hash_indirect
+ || hash->elf.root.type == bfd_link_hash_warning)
+ hash = ((struct elf32_hppa_link_hash_entry *)
+ hash->elf.root.u.i.link);
+
+ if (hash->elf.root.type == bfd_link_hash_defined
+ || hash->elf.root.type == bfd_link_hash_defweak)
+ {
+ sym_sec = hash->elf.root.u.def.section;
+ sym_value = hash->elf.root.u.def.value;
+ if (sym_sec->output_section != NULL)
+ destination = (sym_value + irela->r_addend
+ + sym_sec->output_offset
+ + sym_sec->output_section->vma);
+ }
+ else if (hash->elf.root.type == bfd_link_hash_undefweak)
+ {
+ if (! info->shared)
+ continue;
+ }
+ else if (hash->elf.root.type == bfd_link_hash_undefined)
+ {
+ if (! (info->shared
+ && !info->no_undefined
+ && (ELF_ST_VISIBILITY (hash->elf.other)
+ == STV_DEFAULT)))
+ continue;
+ }
+ else
+ {
+ bfd_set_error (bfd_error_bad_value);
+ goto error_ret_free_internal;
+ }
+ }
+
+ /* Determine what (if any) linker stub is needed. */
+ stub_type = hppa_type_of_stub (section, irela, hash,
+ destination);
+ if (stub_type == hppa_stub_none)
+ continue;
+
+ /* Support for grouping stub sections. */
+ id_sec = hplink->stub_group[section->id].link_sec;
+
+ /* Get the name of this stub. */
+ stub_name = hppa_stub_name (id_sec, sym_sec, hash, irela);
+ if (!stub_name)
+ goto error_ret_free_internal;
+
+ stub_entry = hppa_stub_hash_lookup (&hplink->stub_hash_table,
+ stub_name,
+ false, false);
+ if (stub_entry != NULL)
+ {
+ /* The proper stub has already been created. */
+ free (stub_name);
+ continue;
+ }
+
+ stub_entry = hppa_add_stub (stub_name, section, hplink);
+ if (stub_entry == NULL)
+ {
+ free (stub_name);
+ goto error_ret_free_local;
+ }
+
+ stub_entry->target_value = sym_value;
+ stub_entry->target_section = sym_sec;
+ stub_entry->stub_type = stub_type;
+ if (info->shared)
+ {
+ if (stub_type == hppa_stub_import)
+ stub_entry->stub_type = hppa_stub_import_shared;
+ else if (stub_type == hppa_stub_long_branch
+ && (LONG_BRANCH_PIC_IN_SHLIB || hash == NULL))
+ stub_entry->stub_type = hppa_stub_long_branch_shared;
+ }
+ stub_entry->h = hash;
+ stub_changed = 1;
+ }
+
+ /* We're done with the internal relocs, free them. */
+ free (internal_relocs);
+ }
+ }
+
+ if (!stub_changed)
+ break;
+
+ /* OK, we've added some stubs. Find out the new size of the
+ stub sections. */
+ for (stub_sec = hplink->stub_bfd->sections;
+ stub_sec != NULL;
+ stub_sec = stub_sec->next)
+ {
+ stub_sec->_raw_size = 0;
+ stub_sec->_cooked_size = 0;
+ }
+#if ! LONG_BRANCH_PIC_IN_SHLIB
+ {
+ int i;
+
+ for (i = top_id; i >= 0; --i)
+ {
+ /* This will probably hit the same section many times.. */
+ stub_sec = hplink->stub_group[i].reloc_sec;
+ if (stub_sec != NULL)
+ {
+ stub_sec->_raw_size = 0;
+ stub_sec->_cooked_size = 0;
+ }
+ }
+ }
+#endif
+
+ bfd_hash_traverse (&hplink->stub_hash_table,
+ hppa_size_one_stub,
+ hplink);
+
+ /* Ask the linker to do its stuff. */
+ (*hplink->layout_sections_again) ();
+ stub_changed = 0;
+ }
+
+ ret = 1;
+
+ error_ret_free_local:
+ while (bfd_count-- > 0)
+ if (all_local_syms[bfd_count])
+ free (all_local_syms[bfd_count]);
+ free (all_local_syms);
+
+ return ret;
+}
+
+/* For a final link, this function is called after we have sized the
+ stubs to provide a value for __gp. */
+
+boolean
+elf32_hppa_set_gp (abfd, info)
+ bfd *abfd;
+ struct bfd_link_info *info;
+{
+ struct elf32_hppa_link_hash_table *hplink;
+ struct elf_link_hash_entry *h;
+ asection *sec;
+ bfd_vma gp_val;
+
+ hplink = hppa_link_hash_table (info);
+ h = elf_link_hash_lookup (&hplink->root, "$global$",
+ false, false, false);
+
+ if (h != NULL
+ && (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak))
+ {
+ gp_val = h->root.u.def.value;
+ sec = h->root.u.def.section;
+ }
+ else
+ {
+ /* Choose to point our LTP at, in this order, one of .plt, .got,
+ or .data, if these sections exist. In the case of choosing
+ .plt try to make the LTP ideal for addressing anywhere in the
+ .plt or .got with a 14 bit signed offset. Typically, the end
+ of the .plt is the start of the .got, so choose .plt + 0x2000
+ if either the .plt or .got is larger than 0x2000. If both
+ the .plt and .got are smaller than 0x2000, choose the end of
+ the .plt section. */
+
+ sec = hplink->splt;
+ if (sec != NULL)
+ {
+ gp_val = sec->_raw_size;
+ if (gp_val > 0x2000
+ || (hplink->sgot && hplink->sgot->_raw_size > 0x2000))
+ {
+ gp_val = 0x2000;
+ }
+ }
+ else
+ {
+ gp_val = 0;
+ sec = hplink->sgot;
+ if (sec != NULL)
+ {
+ /* We know we don't have a .plt. If .got is large,
+ offset our LTP. */
+ if (sec->_raw_size > 0x2000)
+ gp_val = 0x2000;
+ }
+ else
+ {
+ /* No .plt or .got. Who cares what the LTP is? */
+ sec = bfd_get_section_by_name (abfd, ".data");
+ }
+ }
+
+ if (h != NULL)
+ {
+ h->root.type = bfd_link_hash_defined;
+ h->root.u.def.value = gp_val;
+ if (sec != NULL)
+ h->root.u.def.section = sec;
+ else
+ h->root.u.def.section = bfd_abs_section_ptr;
+ }
+ }
+
+ if (sec != NULL && sec->output_section != NULL)
+ gp_val += sec->output_section->vma + sec->output_offset;
+
+ elf_gp (abfd) = gp_val;
+ return true;
+}
+
+/* Build all the stubs associated with the current output file. The
+ stubs are kept in a hash table attached to the main linker hash
+ table. We also set up the .plt entries for statically linked PIC
+ functions here. This function is called via hppaelf_finish in the
+ linker. */
+
+boolean
+elf32_hppa_build_stubs (info)
+ struct bfd_link_info *info;
+{
+ asection *stub_sec;
+ struct bfd_hash_table *table;
+ struct elf32_hppa_link_hash_table *hplink;
+
+ hplink = hppa_link_hash_table (info);
+
+ for (stub_sec = hplink->stub_bfd->sections;
+ stub_sec != NULL;
+ stub_sec = stub_sec->next)
+ {
+ size_t size;
+
+ /* Allocate memory to hold the linker stubs. */
+ size = stub_sec->_raw_size;
+ stub_sec->contents = (unsigned char *) bfd_zalloc (hplink->stub_bfd,
+ size);
+ if (stub_sec->contents == NULL && size != 0)
+ return false;
+ stub_sec->_raw_size = 0;
+ }
+
+ /* Build the stubs as directed by the stub hash table. */
+ table = &hplink->stub_hash_table;
+ bfd_hash_traverse (table, hppa_build_one_stub, info);
+
+ return true;
+}
+
+/* Perform a final link. */
+
+static boolean
+elf32_hppa_final_link (abfd, info)
+ bfd *abfd;
+ struct bfd_link_info *info;
+{
+ asection *s;
+
+ /* Invoke the regular ELF garbage collecting linker to do all the
+ work. */
+ if (!_bfd_elf32_gc_common_final_link (abfd, info))
+ return false;
+
+ /* If we're producing a final executable, sort the contents of the
+ unwind section. Magic section names, but this is much safer than
+ having elf32_hppa_relocate_section remember where SEGREL32 relocs
+ occurred. Consider what happens if someone inept creates a
+ linker script that puts unwind information in .text. */
+ s = bfd_get_section_by_name (abfd, ".PARISC.unwind");
+ if (s != NULL)
+ {
+ bfd_size_type size;
+ char *contents;
+
+ size = s->_raw_size;
+ contents = bfd_malloc (size);
+ if (contents == NULL)
+ return false;
+
+ if (! bfd_get_section_contents (abfd, s, contents, (file_ptr) 0, size))
+ return false;
+
+ qsort (contents, size / 16, 16, hppa_unwind_entry_compare);
+
+ if (! bfd_set_section_contents (abfd, s, contents, (file_ptr) 0, size))
+ return false;
+ }
+ return true;
+}
+
+/* Record the lowest address for the data and text segments. */
+
+static void
+hppa_record_segment_addr (abfd, section, data)
+ bfd *abfd ATTRIBUTE_UNUSED;
+ asection *section;
+ PTR data;
+{
+ struct elf32_hppa_link_hash_table *hplink;
+
+ hplink = (struct elf32_hppa_link_hash_table *) data;
+
+ if ((section->flags & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD))
+ {
+ bfd_vma value = section->vma - section->filepos;
+
+ if ((section->flags & SEC_READONLY) != 0)
+ {
+ if (value < hplink->text_segment_base)
+ hplink->text_segment_base = value;
+ }
+ else
+ {
+ if (value < hplink->data_segment_base)
+ hplink->data_segment_base = value;
+ }
+ }
+}
+
+/* Perform a relocation as part of a final link. */
+
+static bfd_reloc_status_type
+final_link_relocate (input_section, contents, rel, value, hplink, sym_sec, h)
+ asection *input_section;
+ bfd_byte *contents;
+ const Elf_Internal_Rela *rel;
+ bfd_vma value;
+ struct elf32_hppa_link_hash_table *hplink;
+ asection *sym_sec;
+ struct elf32_hppa_link_hash_entry *h;
+{
+ int insn;
+ unsigned int r_type = ELF32_R_TYPE (rel->r_info);
+ reloc_howto_type *howto = elf_hppa_howto_table + r_type;
+ int r_format = howto->bitsize;
+ enum hppa_reloc_field_selector_type_alt r_field;
+ bfd *input_bfd = input_section->owner;
+ bfd_vma offset = rel->r_offset;
+ bfd_vma max_branch_offset = 0;
+ bfd_byte *hit_data = contents + offset;
+ bfd_signed_vma addend = rel->r_addend;
+ bfd_vma location;
+ struct elf32_hppa_stub_hash_entry *stub_entry = NULL;
+ int val;
+
+ if (r_type == R_PARISC_NONE)
+ return bfd_reloc_ok;
+
+ insn = bfd_get_32 (input_bfd, hit_data);
+
+ /* Find out where we are and where we're going. */
+ location = (offset +
+ input_section->output_offset +
+ input_section->output_section->vma);
+
+ switch (r_type)
+ {
+ case R_PARISC_PCREL12F:
+ case R_PARISC_PCREL17F:
+ case R_PARISC_PCREL22F:
+ /* If this is a call to a function defined in another dynamic
+ library, or if it is a call to a PIC function in the same
+ object, or if this is a shared link and it is a call to a
+ weak symbol which may or may not be in the same object, then
+ find the import stub in the stub hash. */
+ if (sym_sec == NULL
+ || sym_sec->output_section == NULL
+ || (h != NULL
+ && ((h->maybe_pic_call
+ && !(input_section->flags & SEC_HAS_GOT_REF))
+ || (h->elf.root.type == bfd_link_hash_defweak
+ && h->elf.dynindx != -1
+ && h->elf.plt.offset != (bfd_vma) -1))))
+ {
+ stub_entry = hppa_get_stub_entry (input_section, sym_sec,
+ h, rel, hplink);
+ if (stub_entry != NULL)
+ {
+ value = (stub_entry->stub_offset
+ + stub_entry->stub_sec->output_offset
+ + stub_entry->stub_sec->output_section->vma);
+ addend = 0;
+ }
+ else if (sym_sec == NULL && h != NULL
+ && h->elf.root.type == bfd_link_hash_undefweak)
+ {
+ /* It's OK if undefined weak. Make undefined weak
+ branches go nowhere. */
+ value = location;
+ addend = 0;
+ }
+ else
+ return bfd_reloc_notsupported;
+ }
+ /* Fall thru. */
+
+ case R_PARISC_PCREL21L:
+ case R_PARISC_PCREL17C:
+ case R_PARISC_PCREL17R:
+ case R_PARISC_PCREL14R:
+ case R_PARISC_PCREL14F:
+ /* Make it a pc relative offset. */
+ value -= location;
+ addend -= 8;
+ break;
+
+ case R_PARISC_DPREL21L:
+ case R_PARISC_DPREL14R:
+ case R_PARISC_DPREL14F:
+ /* For all the DP relative relocations, we need to examine the symbol's
+ section. If it's a code section, then "data pointer relative" makes
+ no sense. In that case we don't adjust the "value", and for 21 bit
+ addil instructions, we change the source addend register from %dp to
+ %r0. This situation commonly arises when a variable's "constness"
+ is declared differently from the way the variable is defined. For
+ instance: "extern int foo" with foo defined as "const int foo". */
+ if (sym_sec == NULL)
+ break;
+ if ((sym_sec->flags & SEC_CODE) != 0)
+ {
+ if ((insn & ((0x3f << 26) | (0x1f << 21)))
+ == (((int) OP_ADDIL << 26) | (27 << 21)))
+ {
+ insn &= ~ (0x1f << 21);
+#if 1 /* debug them. */
+ (*_bfd_error_handler)
+ (_("%s(%s+0x%lx): fixing %s"),
+ bfd_get_filename (input_bfd),
+ input_section->name,
+ (long) rel->r_offset,
+ howto->name);
+#endif
+ }
+ /* Now try to make things easy for the dynamic linker. */
+
+ break;
+ }
+ /* Fall thru. */
+
+ case R_PARISC_DLTIND21L:
+ case R_PARISC_DLTIND14R:
+ case R_PARISC_DLTIND14F:
+ value -= elf_gp (input_section->output_section->owner);
+ break;
+
+ case R_PARISC_SEGREL32:
+ if ((sym_sec->flags & SEC_CODE) != 0)
+ value -= hplink->text_segment_base;
+ else
+ value -= hplink->data_segment_base;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (r_type)
+ {
+ case R_PARISC_DIR32:
+ case R_PARISC_DIR14F:
+ case R_PARISC_DIR17F:
+ case R_PARISC_PCREL17C:
+ case R_PARISC_PCREL14F:
+ case R_PARISC_DPREL14F:
+ case R_PARISC_PLABEL32:
+ case R_PARISC_DLTIND14F:
+ case R_PARISC_SEGBASE:
+ case R_PARISC_SEGREL32:
+ r_field = e_fsel;
+ break;
+
+ case R_PARISC_DIR21L:
+ case R_PARISC_PCREL21L:
+ case R_PARISC_DPREL21L:
+ case R_PARISC_PLABEL21L:
+ case R_PARISC_DLTIND21L:
+ r_field = e_lrsel;
+ break;
+
+ case R_PARISC_DIR17R:
+ case R_PARISC_PCREL17R:
+ case R_PARISC_DIR14R:
+ case R_PARISC_PCREL14R:
+ case R_PARISC_DPREL14R:
+ case R_PARISC_PLABEL14R:
+ case R_PARISC_DLTIND14R:
+ r_field = e_rrsel;
+ break;
+
+ case R_PARISC_PCREL12F:
+ case R_PARISC_PCREL17F:
+ case R_PARISC_PCREL22F:
+ r_field = e_fsel;
+
+ if (r_type == (unsigned int) R_PARISC_PCREL17F)
+ {
+ max_branch_offset = (1 << (17-1)) << 2;
+ }
+ else if (r_type == (unsigned int) R_PARISC_PCREL12F)
+ {
+ max_branch_offset = (1 << (12-1)) << 2;
+ }
+ else
+ {
+ max_branch_offset = (1 << (22-1)) << 2;
+ }
+
+ /* sym_sec is NULL on undefined weak syms or when shared on
+ undefined syms. We've already checked for a stub for the
+ shared undefined case. */
+ if (sym_sec == NULL)
+ break;
+
+ /* If the branch is out of reach, then redirect the
+ call to the local stub for this function. */
+ if (value + addend + max_branch_offset >= 2*max_branch_offset)
+ {
+ stub_entry = hppa_get_stub_entry (input_section, sym_sec,
+ h, rel, hplink);
+ if (stub_entry == NULL)
+ return bfd_reloc_notsupported;
+
+ /* Munge up the value and addend so that we call the stub
+ rather than the procedure directly. */
+ value = (stub_entry->stub_offset
+ + stub_entry->stub_sec->output_offset
+ + stub_entry->stub_sec->output_section->vma
+ - location);
+ addend = -8;
+ }
+ break;
+
+ /* Something we don't know how to handle. */
+ default:
+ return bfd_reloc_notsupported;
+ }
+
+ /* Make sure we can reach the stub. */
+ if (max_branch_offset != 0
+ && value + addend + max_branch_offset >= 2*max_branch_offset)
+ {
+ (*_bfd_error_handler)
+ (_("%s(%s+0x%lx): cannot reach %s, recompile with -ffunction-sections"),
+ bfd_get_filename (input_bfd),
+ input_section->name,
+ (long) rel->r_offset,
+ stub_entry->root.string);
+ return bfd_reloc_notsupported;
+ }
+
+ val = hppa_field_adjust (value, addend, r_field);
+
+ switch (r_type)
+ {
+ case R_PARISC_PCREL12F:
+ case R_PARISC_PCREL17C:
+ case R_PARISC_PCREL17F:
+ case R_PARISC_PCREL17R:
+ case R_PARISC_PCREL22F:
+ case R_PARISC_DIR17F:
+ case R_PARISC_DIR17R:
+ /* This is a branch. Divide the offset by four.
+ Note that we need to decide whether it's a branch or
+ otherwise by inspecting the reloc. Inspecting insn won't
+ work as insn might be from a .word directive. */
+ val >>= 2;
+ break;
+
+ default:
+ break;
+ }
+
+ insn = hppa_rebuild_insn (insn, val, r_format);
+
+ /* Update the instruction word. */
+ bfd_put_32 (input_bfd, (bfd_vma) insn, hit_data);
+ return bfd_reloc_ok;
+}
+
+/* Relocate an HPPA ELF section. */
+
+static boolean
+elf32_hppa_relocate_section (output_bfd, info, input_bfd, input_section,
+ contents, relocs, local_syms, local_sections)
+ 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;
+{
+ bfd *dynobj;
+ bfd_vma *local_got_offsets;
+ struct elf32_hppa_link_hash_table *hplink;
+ Elf_Internal_Shdr *symtab_hdr;
+ Elf_Internal_Rela *rel;
+ Elf_Internal_Rela *relend;
+ asection *sreloc;
+
+ symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+
+ hplink = hppa_link_hash_table (info);
+ dynobj = hplink->root.dynobj;
+ local_got_offsets = elf_local_got_offsets (input_bfd);
+ sreloc = NULL;
+
+ rel = relocs;
+ relend = relocs + input_section->reloc_count;
+ for (; rel < relend; rel++)
+ {
+ unsigned int r_type;
+ reloc_howto_type *howto;
+ unsigned int r_symndx;
+ struct elf32_hppa_link_hash_entry *h;
+ Elf_Internal_Sym *sym;
+ asection *sym_sec;
+ bfd_vma relocation;
+ bfd_reloc_status_type r;
+ const char *sym_name;
+ boolean plabel;
+
+ r_type = ELF32_R_TYPE (rel->r_info);
+ if (r_type >= (unsigned int) R_PARISC_UNIMPLEMENTED)
+ {
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+ }
+ if (r_type == (unsigned int) R_PARISC_GNU_VTENTRY
+ || r_type == (unsigned int) R_PARISC_GNU_VTINHERIT)
+ continue;
+
+ r_symndx = ELF32_R_SYM (rel->r_info);
+
+ if (info->relocateable)
+ {
+ /* This is a relocateable link. We don't have to change
+ anything, unless the reloc is against a section symbol,
+ in which case we have to adjust according to where the
+ section symbol winds up in the output section. */
+ if (r_symndx < symtab_hdr->sh_info)
+ {
+ sym = local_syms + r_symndx;
+ if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
+ {
+ sym_sec = local_sections[r_symndx];
+ rel->r_addend += sym_sec->output_offset;
+ }
+ }
+ continue;
+ }
+
+ /* This is a final link. */
+ h = NULL;
+ sym = NULL;
+ sym_sec = NULL;
+ if (r_symndx < symtab_hdr->sh_info)
+ {
+ /* This is a local symbol, h defaults to NULL. */
+ sym = local_syms + r_symndx;
+ sym_sec = local_sections[r_symndx];
+ relocation = ((ELF_ST_TYPE (sym->st_info) == STT_SECTION
+ ? 0 : sym->st_value)
+ + sym_sec->output_offset
+ + sym_sec->output_section->vma);
+ }
+ else
+ {
+ int indx;
+
+ /* It's a global; Find its entry in the link hash. */
+ indx = r_symndx - symtab_hdr->sh_info;
+ h = ((struct elf32_hppa_link_hash_entry *)
+ elf_sym_hashes (input_bfd)[indx]);
+ while (h->elf.root.type == bfd_link_hash_indirect
+ || h->elf.root.type == bfd_link_hash_warning)
+ h = (struct elf32_hppa_link_hash_entry *) h->elf.root.u.i.link;
+
+ relocation = 0;
+ if (h->elf.root.type == bfd_link_hash_defined
+ || h->elf.root.type == bfd_link_hash_defweak)
+ {
+ sym_sec = h->elf.root.u.def.section;
+ /* If sym_sec->output_section is NULL, then it's a
+ symbol defined in a shared library. */
+ if (sym_sec->output_section != NULL)
+ relocation = (h->elf.root.u.def.value
+ + sym_sec->output_offset
+ + sym_sec->output_section->vma);
+ }
+ else if (h->elf.root.type == bfd_link_hash_undefweak)
+ ;
+ else if (info->shared && !info->no_undefined
+ && ELF_ST_VISIBILITY (h->elf.other) == STV_DEFAULT)
+ {
+ if (info->symbolic)
+ if (!((*info->callbacks->undefined_symbol)
+ (info, h->elf.root.root.string, input_bfd,
+ input_section, rel->r_offset, false)))
+ return false;
+ }
+ else
+ {
+ if (!((*info->callbacks->undefined_symbol)
+ (info, h->elf.root.root.string, input_bfd,
+ input_section, rel->r_offset, true)))
+ return false;
+ }
+ }
+
+ /* Do any required modifications to the relocation value, and
+ determine what types of dynamic info we need to output, if
+ any. */
+ plabel = 0;
+ switch (r_type)
+ {
+ case R_PARISC_DLTIND14F:
+ case R_PARISC_DLTIND14R:
+ case R_PARISC_DLTIND21L:
+ /* Relocation is to the entry for this symbol in the global
+ offset table. */
+ if (h != NULL)
+ {
+ bfd_vma off;
+
+ off = h->elf.got.offset;
+ BFD_ASSERT (off != (bfd_vma) -1);
+
+ if (! hplink->root.dynamic_sections_created
+ || (info->shared
+ && (info->symbolic || h->elf.dynindx == -1)
+ && (h->elf.elf_link_hash_flags
+ & ELF_LINK_HASH_DEF_REGULAR) != 0))
+ {
+ /* This is actually a static link, or it is a
+ -Bsymbolic link and the symbol is defined
+ locally, or the symbol was forced to be local
+ because of a version file. We must initialize
+ this entry in the global offset table. Since the
+ offset must always be a multiple of 4, we use the
+ least significant bit to record whether we have
+ initialized it already.
+
+ When doing a dynamic link, we create a .rela.got
+ relocation entry to initialize the value. This
+ is done in the finish_dynamic_symbol routine. */
+ if ((off & 1) != 0)
+ off &= ~1;
+ else
+ {
+ bfd_put_32 (output_bfd, relocation,
+ hplink->sgot->contents + off);
+ h->elf.got.offset |= 1;
+ }
+ }
+
+ relocation = off;
+ }
+ else
+ {
+ /* Local symbol case. */
+ bfd_vma off;
+
+ BFD_ASSERT (local_got_offsets != NULL
+ && local_got_offsets[r_symndx] != (bfd_vma) -1);
+
+ off = local_got_offsets[r_symndx];
+
+ /* The offset must always be a multiple of 4. We use
+ the least significant bit to record whether we have
+ already generated the necessary reloc. */
+ if ((off & 1) != 0)
+ off &= ~1;
+ else
+ {
+ bfd_put_32 (output_bfd, relocation,
+ hplink->sgot->contents + off);
+
+ if (info->shared)
+ {
+ /* Output a dynamic *ABS* relocation for this
+ GOT entry. In this case it is relative to
+ the base of the object because the symbol
+ index is zero. */
+ Elf_Internal_Rela outrel;
+ asection *srelgot = hplink->srelgot;
+
+ outrel.r_offset = (off
+ + hplink->sgot->output_offset
+ + hplink->sgot->output_section->vma);
+ outrel.r_info = ELF32_R_INFO (0, R_PARISC_DIR32);
+ outrel.r_addend = relocation;
+ bfd_elf32_swap_reloca_out (output_bfd, &outrel,
+ ((Elf32_External_Rela *)
+ srelgot->contents
+ + srelgot->reloc_count));
+ ++srelgot->reloc_count;
+ }
+
+ local_got_offsets[r_symndx] |= 1;
+ }
+
+ relocation = off;
+ }
+
+ /* Add the base of the GOT to the relocation value. */
+ relocation += (hplink->sgot->output_offset
+ + hplink->sgot->output_section->vma);
+ break;
+
+ case R_PARISC_SEGREL32:
+ /* If this is the first SEGREL relocation, then initialize
+ the segment base values. */
+ if (hplink->text_segment_base == (bfd_vma) -1)
+ bfd_map_over_sections (output_bfd,
+ hppa_record_segment_addr,
+ hplink);
+ break;