diff options
Diffstat (limited to 'bfd/elf64-hppa.c')
-rw-r--r-- | bfd/elf64-hppa.c | 2718 |
1 files changed, 0 insertions, 2718 deletions
diff --git a/bfd/elf64-hppa.c b/bfd/elf64-hppa.c deleted file mode 100644 index 4a87358c9df..00000000000 --- a/bfd/elf64-hppa.c +++ /dev/null @@ -1,2718 +0,0 @@ -/* Support for HPPA 64-bit ELF - Copyright 1999, 2000, 2001 Free Software Foundation, Inc. - -This file is part of BFD, the Binary File Descriptor library. - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -#include "alloca-conf.h" -#include "bfd.h" -#include "sysdep.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/hppa.h" -#include "libhppa.h" -#include "elf64-hppa.h" -#define ARCH_SIZE 64 - -#define PLT_ENTRY_SIZE 0x10 -#define DLT_ENTRY_SIZE 0x8 -#define OPD_ENTRY_SIZE 0x20 - -#define ELF_DYNAMIC_INTERPRETER "/usr/lib/pa20_64/dld.sl" - -/* The stub is supposed to load the target address and target's DP - value out of the PLT, then do an external branch to the target - address. - - LDD PLTOFF(%r27),%r1 - BVE (%r1) - LDD PLTOFF+8(%r27),%r27 - - Note that we must use the LDD with a 14 bit displacement, not the one - with a 5 bit displacement. */ -static char plt_stub[] = {0x53, 0x61, 0x00, 0x00, 0xe8, 0x20, 0xd0, 0x00, - 0x53, 0x7b, 0x00, 0x00 }; - -struct elf64_hppa_dyn_hash_entry -{ - struct bfd_hash_entry root; - - /* Offsets for this symbol in various linker sections. */ - bfd_vma dlt_offset; - bfd_vma plt_offset; - bfd_vma opd_offset; - bfd_vma stub_offset; - - /* The symbol table entry, if any, that this was derived from. */ - struct elf_link_hash_entry *h; - - /* The index of the (possibly local) symbol in the input bfd and its - associated BFD. Needed so that we can have relocs against local - symbols in shared libraries. */ - unsigned long sym_indx; - bfd *owner; - - /* Dynamic symbols may need to have two different values. One for - the dynamic symbol table, one for the normal symbol table. - - In such cases we store the symbol's real value and section - index here so we can restore the real value before we write - the normal symbol table. */ - bfd_vma st_value; - int st_shndx; - - /* Used to count non-got, non-plt relocations for delayed sizing - of relocation sections. */ - struct elf64_hppa_dyn_reloc_entry - { - /* Next relocation in the chain. */ - struct elf64_hppa_dyn_reloc_entry *next; - - /* The type of the relocation. */ - int type; - - /* The input section of the relocation. */ - asection *sec; - - /* The index of the section symbol for the input section of - the relocation. Only needed when building shared libraries. */ - int sec_symndx; - - /* The offset within the input section of the relocation. */ - bfd_vma offset; - - /* The addend for the relocation. */ - bfd_vma addend; - - } *reloc_entries; - - /* Nonzero if this symbol needs an entry in one of the linker - sections. */ - unsigned want_dlt; - unsigned want_plt; - unsigned want_opd; - unsigned want_stub; -}; - -struct elf64_hppa_dyn_hash_table -{ - struct bfd_hash_table root; -}; - -struct elf64_hppa_link_hash_table -{ - struct elf_link_hash_table root; - - /* Shortcuts to get to the various linker defined sections. */ - asection *dlt_sec; - asection *dlt_rel_sec; - asection *plt_sec; - asection *plt_rel_sec; - asection *opd_sec; - asection *opd_rel_sec; - asection *other_rel_sec; - - /* Offset of __gp within .plt section. When the PLT gets large we want - to slide __gp into the PLT section so that we can continue to use - single DP relative instructions to load values out of the PLT. */ - bfd_vma gp_offset; - - /* Note this is not strictly correct. We should create a stub section for - each input section with calls. The stub section should be placed before - the section with the call. */ - asection *stub_sec; - - bfd_vma text_segment_base; - bfd_vma data_segment_base; - - struct elf64_hppa_dyn_hash_table dyn_hash_table; - - /* We build tables to map from an input section back to its - symbol index. This is the BFD for which we currently have - a map. */ - bfd *section_syms_bfd; - - /* Array of symbol numbers for each input section attached to the - current BFD. */ - int *section_syms; -}; - -#define elf64_hppa_hash_table(p) \ - ((struct elf64_hppa_link_hash_table *) ((p)->hash)) - -typedef struct bfd_hash_entry *(*new_hash_entry_func) - PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); - -static boolean elf64_hppa_dyn_hash_table_init - PARAMS ((struct elf64_hppa_dyn_hash_table *ht, bfd *abfd, - new_hash_entry_func new)); -static struct bfd_hash_entry *elf64_hppa_new_dyn_hash_entry - PARAMS ((struct bfd_hash_entry *entry, struct bfd_hash_table *table, - const char *string)); -static struct bfd_link_hash_table *elf64_hppa_hash_table_create - PARAMS ((bfd *abfd)); -static struct elf64_hppa_dyn_hash_entry *elf64_hppa_dyn_hash_lookup - PARAMS ((struct elf64_hppa_dyn_hash_table *table, const char *string, - boolean create, boolean copy)); -static void elf64_hppa_dyn_hash_traverse - PARAMS ((struct elf64_hppa_dyn_hash_table *table, - boolean (*func) (struct elf64_hppa_dyn_hash_entry *, PTR), - PTR info)); - -static const char *get_dyn_name - PARAMS ((asection *, struct elf_link_hash_entry *, - const Elf_Internal_Rela *, char **, size_t *)); - -/* This must follow the definitions of the various derived linker - hash tables and shared functions. */ -#include "elf-hppa.h" - -static boolean elf64_hppa_object_p - PARAMS ((bfd *)); - -static boolean elf64_hppa_section_from_shdr - PARAMS ((bfd *, Elf64_Internal_Shdr *, char *)); - -static void elf64_hppa_post_process_headers - PARAMS ((bfd *, struct bfd_link_info *)); - -static boolean elf64_hppa_create_dynamic_sections - PARAMS ((bfd *, struct bfd_link_info *)); - -static boolean elf64_hppa_adjust_dynamic_symbol - PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *)); - -static boolean elf64_hppa_size_dynamic_sections - PARAMS ((bfd *, struct bfd_link_info *)); - -static boolean elf64_hppa_finish_dynamic_symbol - PARAMS ((bfd *, struct bfd_link_info *, - struct elf_link_hash_entry *, Elf_Internal_Sym *)); - -static boolean elf64_hppa_finish_dynamic_sections - PARAMS ((bfd *, struct bfd_link_info *)); - -static boolean elf64_hppa_check_relocs - PARAMS ((bfd *, struct bfd_link_info *, - asection *, const Elf_Internal_Rela *)); - -static boolean elf64_hppa_dynamic_symbol_p - PARAMS ((struct elf_link_hash_entry *, struct bfd_link_info *)); - -static boolean elf64_hppa_mark_exported_functions - PARAMS ((struct elf_link_hash_entry *, PTR)); - -static boolean elf64_hppa_finalize_opd - PARAMS ((struct elf64_hppa_dyn_hash_entry *, PTR)); - -static boolean elf64_hppa_finalize_dlt - PARAMS ((struct elf64_hppa_dyn_hash_entry *, PTR)); - -static boolean allocate_global_data_dlt - PARAMS ((struct elf64_hppa_dyn_hash_entry *, PTR)); - -static boolean allocate_global_data_plt - PARAMS ((struct elf64_hppa_dyn_hash_entry *, PTR)); - -static boolean allocate_global_data_stub - PARAMS ((struct elf64_hppa_dyn_hash_entry *, PTR)); - -static boolean allocate_global_data_opd - PARAMS ((struct elf64_hppa_dyn_hash_entry *, PTR)); - -static boolean get_reloc_section - PARAMS ((bfd *, struct elf64_hppa_link_hash_table *, asection *)); - -static boolean count_dyn_reloc - PARAMS ((bfd *, struct elf64_hppa_dyn_hash_entry *, - int, asection *, int, bfd_vma, bfd_vma)); - -static boolean allocate_dynrel_entries - PARAMS ((struct elf64_hppa_dyn_hash_entry *, PTR)); - -static boolean elf64_hppa_finalize_dynreloc - PARAMS ((struct elf64_hppa_dyn_hash_entry *, PTR)); - -static boolean get_opd - PARAMS ((bfd *, struct bfd_link_info *, struct elf64_hppa_link_hash_table *)); - -static boolean get_plt - PARAMS ((bfd *, struct bfd_link_info *, struct elf64_hppa_link_hash_table *)); - -static boolean get_dlt - PARAMS ((bfd *, struct bfd_link_info *, struct elf64_hppa_link_hash_table *)); - -static boolean get_stub - PARAMS ((bfd *, struct bfd_link_info *, struct elf64_hppa_link_hash_table *)); - -static int elf64_hppa_elf_get_symbol_type - PARAMS ((Elf_Internal_Sym *, int)); - -static boolean -elf64_hppa_dyn_hash_table_init (ht, abfd, new) - struct elf64_hppa_dyn_hash_table *ht; - bfd *abfd ATTRIBUTE_UNUSED; - new_hash_entry_func new; -{ - memset (ht, 0, sizeof (*ht)); - return bfd_hash_table_init (&ht->root, new); -} - -static struct bfd_hash_entry* -elf64_hppa_new_dyn_hash_entry (entry, table, string) - struct bfd_hash_entry *entry; - struct bfd_hash_table *table; - const char *string; -{ - struct elf64_hppa_dyn_hash_entry *ret; - ret = (struct elf64_hppa_dyn_hash_entry *) entry; - - /* Allocate the structure if it has not already been allocated by a - subclass. */ - if (!ret) - ret = bfd_hash_allocate (table, sizeof (*ret)); - - if (!ret) - return 0; - - /* Initialize our local data. All zeros, and definitely easier - than setting 8 bit fields. */ - memset (ret, 0, sizeof (*ret)); - - /* Call the allocation method of the superclass. */ - ret = ((struct elf64_hppa_dyn_hash_entry *) - bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string)); - - return &ret->root; -} - -/* Create the derived linker hash table. The PA64 ELF port uses this - derived hash table to keep information specific to the PA ElF - linker (without using static variables). */ - -static struct bfd_link_hash_table* -elf64_hppa_hash_table_create (abfd) - bfd *abfd; -{ - struct elf64_hppa_link_hash_table *ret; - - ret = bfd_zalloc (abfd, sizeof (*ret)); - if (!ret) - return 0; - if (!_bfd_elf_link_hash_table_init (&ret->root, abfd, - _bfd_elf_link_hash_newfunc)) - { - bfd_release (abfd, ret); - return 0; - } - - if (!elf64_hppa_dyn_hash_table_init (&ret->dyn_hash_table, abfd, - elf64_hppa_new_dyn_hash_entry)) - return 0; - return &ret->root.root; -} - -/* Look up an entry in a PA64 ELF linker hash table. */ - -static struct elf64_hppa_dyn_hash_entry * -elf64_hppa_dyn_hash_lookup(table, string, create, copy) - struct elf64_hppa_dyn_hash_table *table; - const char *string; - boolean create, copy; -{ - return ((struct elf64_hppa_dyn_hash_entry *) - bfd_hash_lookup (&table->root, string, create, copy)); -} - -/* Traverse a PA64 ELF linker hash table. */ - -static void -elf64_hppa_dyn_hash_traverse (table, func, info) - struct elf64_hppa_dyn_hash_table *table; - boolean (*func) PARAMS ((struct elf64_hppa_dyn_hash_entry *, PTR)); - PTR info; -{ - (bfd_hash_traverse - (&table->root, - (boolean (*) PARAMS ((struct bfd_hash_entry *, PTR))) func, - info)); -} - -/* Return nonzero if ABFD represents a PA2.0 ELF64 file. - - Additionally we set the default architecture and machine. */ -static boolean -elf64_hppa_object_p (abfd) - bfd *abfd; -{ - Elf_Internal_Ehdr * i_ehdrp; - unsigned int flags; - - i_ehdrp = elf_elfheader (abfd); - if (strcmp (bfd_get_target (abfd), "elf64-hppa-linux") == 0) - { - if (i_ehdrp->e_ident[EI_OSABI] != ELFOSABI_LINUX) - return false; - } - else - { - if (i_ehdrp->e_ident[EI_OSABI] != ELFOSABI_HPUX) - return false; - } - - flags = i_ehdrp->e_flags; - switch (flags & (EF_PARISC_ARCH | EF_PARISC_WIDE)) - { - case EFA_PARISC_1_0: - return bfd_default_set_arch_mach (abfd, bfd_arch_hppa, 10); - case EFA_PARISC_1_1: - return bfd_default_set_arch_mach (abfd, bfd_arch_hppa, 11); - case EFA_PARISC_2_0: - return bfd_default_set_arch_mach (abfd, bfd_arch_hppa, 20); - case EFA_PARISC_2_0 | EF_PARISC_WIDE: - return bfd_default_set_arch_mach (abfd, bfd_arch_hppa, 25); - } - /* Don't be fussy. */ - return true; -} - -/* Given section type (hdr->sh_type), return a boolean indicating - whether or not the section is an elf64-hppa specific section. */ -static boolean -elf64_hppa_section_from_shdr (abfd, hdr, name) - bfd *abfd; - Elf64_Internal_Shdr *hdr; - char *name; -{ - asection *newsect; - - switch (hdr->sh_type) - { - case SHT_PARISC_EXT: - if (strcmp (name, ".PARISC.archext") != 0) - return false; - break; - case SHT_PARISC_UNWIND: - if (strcmp (name, ".PARISC.unwind") != 0) - return false; - break; - case SHT_PARISC_DOC: - case SHT_PARISC_ANNOT: - default: - return false; - } - - if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name)) - return false; - newsect = hdr->bfd_section; - - return true; -} - -/* Construct a string for use in the elf64_hppa_dyn_hash_table. The - name describes what was once potentially anonymous memory. We - allocate memory as necessary, possibly reusing PBUF/PLEN. */ - -static const char * -get_dyn_name (sec, h, rel, pbuf, plen) - asection *sec; - struct elf_link_hash_entry *h; - const Elf_Internal_Rela *rel; - char **pbuf; - size_t *plen; -{ - size_t nlen, tlen; - char *buf; - size_t len; - - if (h && rel->r_addend == 0) - return h->root.root.string; - - if (h) - nlen = strlen (h->root.root.string); - else - nlen = 8 + 1 + sizeof (rel->r_info) * 2 - 8; - tlen = nlen + 1 + sizeof (rel->r_addend) * 2 + 1; - - len = *plen; - buf = *pbuf; - if (len < tlen) - { - if (buf) - free (buf); - *pbuf = buf = malloc (tlen); - *plen = len = tlen; - if (!buf) - return NULL; - } - - if (h) - { - memcpy (buf, h->root.root.string, nlen); - buf[nlen++] = '+'; - sprintf_vma (buf + nlen, rel->r_addend); - } - else - { - nlen = sprintf (buf, "%x:%lx", - sec->id & 0xffffffff, - (long) ELF64_R_SYM (rel->r_info)); - if (rel->r_addend) - { - buf[nlen++] = '+'; - sprintf_vma (buf + nlen, rel->r_addend); - } - } - - return buf; -} - -/* SEC is a section containing relocs for an input BFD when linking; return - a suitable section for holding relocs in the output BFD for a link. */ - -static boolean -get_reloc_section (abfd, hppa_info, sec) - bfd *abfd; - struct elf64_hppa_link_hash_table *hppa_info; - asection *sec; -{ - const char *srel_name; - asection *srel; - bfd *dynobj; - - srel_name = (bfd_elf_string_from_elf_section - (abfd, elf_elfheader(abfd)->e_shstrndx, - elf_section_data(sec)->rel_hdr.sh_name)); - if (srel_name == NULL) - return false; - - BFD_ASSERT ((strncmp (srel_name, ".rela", 5) == 0 - && strcmp (bfd_get_section_name (abfd, sec), - srel_name+5) == 0) - || (strncmp (srel_name, ".rel", 4) == 0 - && strcmp (bfd_get_section_name (abfd, sec), - srel_name+4) == 0)); - - dynobj = hppa_info->root.dynobj; - if (!dynobj) - hppa_info->root.dynobj = dynobj = abfd; - - srel = bfd_get_section_by_name (dynobj, srel_name); - if (srel == NULL) - { - srel = bfd_make_section (dynobj, srel_name); - if (srel == NULL - || !bfd_set_section_flags (dynobj, srel, - (SEC_ALLOC - | SEC_LOAD - | SEC_HAS_CONTENTS - | SEC_IN_MEMORY - | SEC_LINKER_CREATED - | SEC_READONLY)) - || !bfd_set_section_alignment (dynobj, srel, 3)) - return false; - } - - hppa_info->other_rel_sec = srel; - return true; -} - -/* Add a new entry to the list of dynamic relocations against DYN_H. - - We use this to keep a record of all the FPTR relocations against a - particular symbol so that we can create FPTR relocations in the - output file. */ - -static boolean -count_dyn_reloc (abfd, dyn_h, type, sec, sec_symndx, offset, addend) - bfd *abfd; - struct elf64_hppa_dyn_hash_entry *dyn_h; - int type; - asection *sec; - int sec_symndx; - bfd_vma offset; - bfd_vma addend; -{ - struct elf64_hppa_dyn_reloc_entry *rent; - - rent = (struct elf64_hppa_dyn_reloc_entry *) - bfd_alloc (abfd, sizeof (*rent)); - if (!rent) - return false; - - rent->next = dyn_h->reloc_entries; - rent->type = type; - rent->sec = sec; - rent->sec_symndx = sec_symndx; - rent->offset = offset; - rent->addend = addend; - dyn_h->reloc_entries = rent; - - return true; -} - -/* Scan the RELOCS and record the type of dynamic entries that each - referenced symbol needs. */ - -static boolean -elf64_hppa_check_relocs (abfd, info, sec, relocs) - bfd *abfd; - struct bfd_link_info *info; - asection *sec; - const Elf_Internal_Rela *relocs; -{ - struct elf64_hppa_link_hash_table *hppa_info; - const Elf_Internal_Rela *relend; - Elf_Internal_Shdr *symtab_hdr; - const Elf_Internal_Rela *rel; - asection *dlt, *plt, *stubs; - char *buf; - size_t buf_len; - int sec_symndx; - - if (info->relocateable) - return true; - - /* If this is the first dynamic object found in the link, create - the special sections required for dynamic linking. */ - if (! elf_hash_table (info)->dynamic_sections_created) - { - if (! bfd_elf64_link_create_dynamic_sections (abfd, info)) - return false; - } - - hppa_info = elf64_hppa_hash_table (info); - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - - /* If necessary, build a new table holding section symbols indices - for this BFD. This is disgusting. */ - - if (info->shared && hppa_info->section_syms_bfd != abfd) - { - unsigned long i; - int highest_shndx; - Elf_Internal_Sym *local_syms, *isym; - Elf64_External_Sym *ext_syms, *esym; - - /* We're done with the old cache of section index to section symbol - index information. Free it. - - ?!? Note we leak the last section_syms array. Presumably we - could free it in one of the later routines in this file. */ - if (hppa_info->section_syms) - free (hppa_info->section_syms); - - /* Allocate memory for the internal and external symbols. */ - local_syms - = (Elf_Internal_Sym *) bfd_malloc (symtab_hdr->sh_info - * sizeof (Elf_Internal_Sym)); - if (local_syms == NULL) - return false; - - ext_syms - = (Elf64_External_Sym *) bfd_malloc (symtab_hdr->sh_info - * sizeof (Elf64_External_Sym)); - if (ext_syms == NULL) - { - free (local_syms); - return false; - } - - /* Read in the local symbols. */ - if (bfd_seek (abfd, symtab_hdr->sh_offset, SEEK_SET) != 0 - || bfd_read (ext_syms, 1, - (symtab_hdr->sh_info - * sizeof (Elf64_External_Sym)), abfd) - != (symtab_hdr->sh_info * sizeof (Elf64_External_Sym))) - { - free (local_syms); - free (ext_syms); - return false; - } - - /* Swap in the local symbols, also record the highest section index - referenced by the local symbols. */ - isym = local_syms; - esym = ext_syms; - highest_shndx = 0; - for (i = 0; i < symtab_hdr->sh_info; i++, esym++, isym++) - { - bfd_elf64_swap_symbol_in (abfd, esym, isym); - if (isym->st_shndx > highest_shndx) - highest_shndx = isym->st_shndx; - } - - /* Now we can free the external symbols. */ - free (ext_syms); - - /* Allocate an array to hold the section index to section symbol index - mapping. Bump by one since we start counting at zero. */ - highest_shndx++; - hppa_info->section_syms = (int *) bfd_malloc (highest_shndx - * sizeof (int)); - - /* Now walk the local symbols again. If we find a section symbol, - record the index of the symbol into the section_syms array. */ - for (isym = local_syms, i = 0; i < symtab_hdr->sh_info; i++, isym++) - { - if (ELF_ST_TYPE (isym->st_info) == STT_SECTION) - hppa_info->section_syms[isym->st_shndx] = i; - } - - /* We are finished with the local symbols. Get rid of them. */ - free (local_syms); - - /* Record which BFD we built the section_syms mapping for. */ - hppa_info->section_syms_bfd = abfd; - } - - /* Record the symbol index for this input section. We may need it for - relocations when building shared libraries. When not building shared - libraries this value is never really used, but assign it to zero to - prevent out of bounds memory accesses in other routines. */ - if (info->shared) - { - sec_symndx = _bfd_elf_section_from_bfd_section (abfd, sec); - - /* If we did not find a section symbol for this section, then - something went terribly wrong above. */ - if (sec_symndx == -1) - return false; - - sec_symndx = hppa_info->section_syms[sec_symndx]; - } - else - sec_symndx = 0; - - dlt = plt = stubs = NULL; - buf = NULL; - buf_len = 0; - - relend = relocs + sec->reloc_count; - for (rel = relocs; rel < relend; ++rel) - { - enum { - NEED_DLT = 1, - NEED_PLT = 2, - NEED_STUB = 4, - NEED_OPD = 8, - NEED_DYNREL = 16, - }; - - struct elf_link_hash_entry *h = NULL; - unsigned long r_symndx = ELF64_R_SYM (rel->r_info); - struct elf64_hppa_dyn_hash_entry *dyn_h; - int need_entry; - const char *addr_name; - boolean maybe_dynamic; - int dynrel_type = R_PARISC_NONE; - static reloc_howto_type *howto; - - if (r_symndx >= symtab_hdr->sh_info) - { - /* We're dealing with a global symbol -- find its hash entry - and mark it as being referenced. */ - long indx = r_symndx - symtab_hdr->sh_info; - h = elf_sym_hashes (abfd)[indx]; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - - h->elf_link_hash_flags |= ELF_LINK_HASH_REF_REGULAR; - } - - /* We can only get preliminary data on whether a symbol is - locally or externally defined, as not all of the input files - have yet been processed. Do something with what we know, as - this may help reduce memory usage and processing time later. */ - maybe_dynamic = false; - if (h && ((info->shared && ! info->symbolic) - || ! (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) - || h->root.type == bfd_link_hash_defweak)) - maybe_dynamic = true; - - howto = elf_hppa_howto_table + ELF64_R_TYPE (rel->r_info); - need_entry = 0; - switch (howto->type) - { - /* These are simple indirect references to symbols through the - DLT. We need to create a DLT entry for any symbols which - appears in a DLTIND relocation. */ - case R_PARISC_DLTIND21L: - case R_PARISC_DLTIND14R: - case R_PARISC_DLTIND14F: - case R_PARISC_DLTIND14WR: - case R_PARISC_DLTIND14DR: - need_entry = NEED_DLT; - break; - - /* ?!? These need a DLT entry. But I have no idea what to do with - the "link time TP value. */ - case R_PARISC_LTOFF_TP21L: - case R_PARISC_LTOFF_TP14R: - case R_PARISC_LTOFF_TP14F: - case R_PARISC_LTOFF_TP64: - case R_PARISC_LTOFF_TP14WR: - case R_PARISC_LTOFF_TP14DR: - case R_PARISC_LTOFF_TP16F: - case R_PARISC_LTOFF_TP16WF: - case R_PARISC_LTOFF_TP16DF: - need_entry = NEED_DLT; - break; - - /* These are function calls. Depending on their precise target we - may need to make a stub for them. The stub uses the PLT, so we - need to create PLT entries for these symbols too. */ - case R_PARISC_PCREL12F: - case R_PARISC_PCREL17F: - case R_PARISC_PCREL22F: - case R_PARISC_PCREL32: - case R_PARISC_PCREL64: - case R_PARISC_PCREL21L: - case R_PARISC_PCREL17R: - case R_PARISC_PCREL17C: - case R_PARISC_PCREL14R: - case R_PARISC_PCREL14F: - case R_PARISC_PCREL22C: - case R_PARISC_PCREL14WR: - case R_PARISC_PCREL14DR: - case R_PARISC_PCREL16F: - case R_PARISC_PCREL16WF: - case R_PARISC_PCREL16DF: - need_entry = (NEED_PLT | NEED_STUB); - break; - - case R_PARISC_PLTOFF21L: - case R_PARISC_PLTOFF14R: - case R_PARISC_PLTOFF14F: - case R_PARISC_PLTOFF14WR: - case R_PARISC_PLTOFF14DR: - case R_PARISC_PLTOFF16F: - case R_PARISC_PLTOFF16WF: - case R_PARISC_PLTOFF16DF: - need_entry = (NEED_PLT); - break; - - case R_PARISC_DIR64: - if (info->shared || maybe_dynamic) - need_entry = (NEED_DYNREL); - dynrel_type = R_PARISC_DIR64; - break; - - /* This is an indirect reference through the DLT to get the address - of a OPD descriptor. Thus we need to make a DLT entry that points - to an OPD entry. */ - case R_PARISC_LTOFF_FPTR21L: - case R_PARISC_LTOFF_FPTR14R: - case R_PARISC_LTOFF_FPTR14WR: - case R_PARISC_LTOFF_FPTR14DR: - case R_PARISC_LTOFF_FPTR32: - case R_PARISC_LTOFF_FPTR64: - case R_PARISC_LTOFF_FPTR16F: - case R_PARISC_LTOFF_FPTR16WF: - case R_PARISC_LTOFF_FPTR16DF: - if (info->shared || maybe_dynamic) - need_entry = (NEED_DLT | NEED_OPD); - else - need_entry = (NEED_DLT | NEED_OPD); - dynrel_type = R_PARISC_FPTR64; - break; - - /* This is a simple OPD entry. */ - case R_PARISC_FPTR64: - if (info->shared || maybe_dynamic) - need_entry = (NEED_OPD | NEED_DYNREL); - else - need_entry = (NEED_OPD); - dynrel_type = R_PARISC_FPTR64; - break; - - /* Add more cases as needed. */ - } - - if (!need_entry) - continue; - - /* Collect a canonical name for this address. */ - addr_name = get_dyn_name (sec, h, rel, &buf, &buf_len); - - /* Collect the canonical entry data for this address. */ - dyn_h = elf64_hppa_dyn_hash_lookup (&hppa_info->dyn_hash_table, - addr_name, true, true); - BFD_ASSERT (dyn_h); - - /* Stash away enough information to be able to find this symbol - regardless of whether or not it is local or global. */ - dyn_h->h = h; - dyn_h->owner = abfd; - dyn_h->sym_indx = r_symndx; - - /* ?!? We may need to do some error checking in here. */ - /* Create what's needed. */ - if (need_entry & NEED_DLT) - { - if (! hppa_info->dlt_sec - && ! get_dlt (abfd, info, hppa_info)) - goto err_out; - dyn_h->want_dlt = 1; - } - - if (need_entry & NEED_PLT) - { - if (! hppa_info->plt_sec - && ! get_plt (abfd, info, hppa_info)) - goto err_out; - dyn_h->want_plt = 1; - } - - if (need_entry & NEED_STUB) - { - if (! hppa_info->stub_sec - && ! get_stub (abfd, info, hppa_info)) - goto err_out; - dyn_h->want_stub = 1; - } - - if (need_entry & NEED_OPD) - { - if (! hppa_info->opd_sec - && ! get_opd (abfd, info, hppa_info)) - goto err_out; - - dyn_h->want_opd = 1; - - /* FPTRs are not allocated by the dynamic linker for PA64, though - it is possible that will change in the future. */ - - /* This could be a local function that had its address taken, in - which case H will be NULL. */ - if (h) - h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT; - } - - /* Add a new dynamic relocation to the chain of dynamic - relocations for this symbol. */ - if ((need_entry & NEED_DYNREL) && (sec->flags & SEC_ALLOC)) - { - if (! hppa_info->other_rel_sec - && ! get_reloc_section (abfd, hppa_info, sec)) - goto err_out; - - if (!count_dyn_reloc (abfd, dyn_h, dynrel_type, sec, - sec_symndx, rel->r_offset, rel->r_addend)) - goto err_out; - - /* If we are building a shared library and we just recorded - a dynamic R_PARISC_FPTR64 relocation, then make sure the - section symbol for this section ends up in the dynamic - symbol table. */ - if (info->shared && dynrel_type == R_PARISC_FPTR64 - && ! (_bfd_elf64_link_record_local_dynamic_symbol - (info, abfd, sec_symndx))) - return false; - } - } - - if (buf) - free (buf); - return true; - - err_out: - if (buf) - free (buf); - return false; -} - -struct elf64_hppa_allocate_data -{ - struct bfd_link_info *info; - bfd_size_type ofs; -}; - -/* Should we do dynamic things to this symbol? */ - -static boolean -elf64_hppa_dynamic_symbol_p (h, info) - struct elf_link_hash_entry *h; - struct bfd_link_info *info; -{ - if (h == NULL) - return false; - - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - - if (h->dynindx == -1) - return false; - - if (h->root.type == bfd_link_hash_undefweak - || h->root.type == bfd_link_hash_defweak) - return true; - - if (h->root.root.string[0] == '$' && h->root.root.string[1] == '$') - return false; - - if ((info->shared && !info->symbolic) - || ((h->elf_link_hash_flags - & (ELF_LINK_HASH_DEF_DYNAMIC | ELF_LINK_HASH_REF_REGULAR)) - == (ELF_LINK_HASH_DEF_DYNAMIC | ELF_LINK_HASH_REF_REGULAR))) - return true; - - return false; -} - -/* Mark all funtions exported by this file so that we can later allocate - entries in .opd for them. */ - -static boolean -elf64_hppa_mark_exported_functions (h, data) - struct elf_link_hash_entry *h; - PTR data; -{ - struct bfd_link_info *info = (struct bfd_link_info *)data; - struct elf64_hppa_link_hash_table *hppa_info; - - hppa_info = elf64_hppa_hash_table (info); - - if (h - && (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - && h->root.u.def.section->output_section != NULL - && h->type == STT_FUNC) - { - struct elf64_hppa_dyn_hash_entry *dyn_h; - - /* Add this symbol to the PA64 linker hash table. */ - dyn_h = elf64_hppa_dyn_hash_lookup (&hppa_info->dyn_hash_table, - h->root.root.string, true, true); - BFD_ASSERT (dyn_h); - dyn_h->h = h; - - if (! hppa_info->opd_sec - && ! get_opd (hppa_info->root.dynobj, info, hppa_info)) - return false; - - dyn_h->want_opd = 1; - /* Put a flag here for output_symbol_hook. */ - dyn_h->st_shndx = -1; - h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT; - } - - return true; -} - -/* Allocate space for a DLT entry. */ - -static boolean -allocate_global_data_dlt (dyn_h, data) - struct elf64_hppa_dyn_hash_entry *dyn_h; - PTR data; -{ - struct elf64_hppa_allocate_data *x = (struct elf64_hppa_allocate_data *)data; - - if (dyn_h->want_dlt) - { - struct elf_link_hash_entry *h = dyn_h->h; - - if (x->info->shared) - { - /* Possibly add the symbol to the local dynamic symbol - table since we might need to create a dynamic relocation - against it. */ - if (! h - || (h && h->dynindx == -1)) - { - bfd *owner; - owner = (h ? h->root.u.def.section->owner : dyn_h->owner); - - if (!_bfd_elf64_link_record_local_dynamic_symbol - (x->info, owner, dyn_h->sym_indx)) - return false; - } - } - - dyn_h->dlt_offset = x->ofs; - x->ofs += DLT_ENTRY_SIZE; - } - return true; -} - -/* Allocate space for a DLT.PLT entry. */ - -static boolean -allocate_global_data_plt (dyn_h, data) - struct elf64_hppa_dyn_hash_entry *dyn_h; - PTR data; -{ - struct elf64_hppa_allocate_data *x = (struct elf64_hppa_allocate_data *)data; - - if (dyn_h->want_plt - && elf64_hppa_dynamic_symbol_p (dyn_h->h, x->info) - && !((dyn_h->h->root.type == bfd_link_hash_defined - || dyn_h->h->root.type == bfd_link_hash_defweak) - && dyn_h->h->root.u.def.section->output_section != NULL)) - { - dyn_h->plt_offset = x->ofs; - x->ofs += PLT_ENTRY_SIZE; - if (dyn_h->plt_offset < 0x2000) - elf64_hppa_hash_table (x->info)->gp_offset = dyn_h->plt_offset; - } - else - dyn_h->want_plt = 0; - - return true; -} - -/* Allocate space for a STUB entry. */ - -static boolean -allocate_global_data_stub (dyn_h, data) - struct elf64_hppa_dyn_hash_entry *dyn_h; - PTR data; -{ - struct elf64_hppa_allocate_data *x = (struct elf64_hppa_allocate_data *)data; - - if (dyn_h->want_stub - && elf64_hppa_dynamic_symbol_p (dyn_h->h, x->info) - && !((dyn_h->h->root.type == bfd_link_hash_defined - || dyn_h->h->root.type == bfd_link_hash_defweak) - && dyn_h->h->root.u.def.section->output_section != NULL)) - { - dyn_h->stub_offset = x->ofs; - x->ofs += sizeof (plt_stub); - } - else - dyn_h->want_stub = 0; - return true; -} - -/* Allocate space for a FPTR entry. */ - -static boolean -allocate_global_data_opd (dyn_h, data) - struct elf64_hppa_dyn_hash_entry *dyn_h; - PTR data; -{ - struct elf64_hppa_allocate_data *x = (struct elf64_hppa_allocate_data *)data; - - if (dyn_h->want_opd) - { - struct elf_link_hash_entry *h = dyn_h->h; - - if (h) - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - - /* We never need an opd entry for a symbol which is not - defined by this output file. */ - if (h && h->root.type == bfd_link_hash_undefined) - dyn_h->want_opd = 0; - - /* If we are creating a shared library, took the address of a local - function or might export this function from this object file, then - we have to create an opd descriptor. */ - else if (x->info->shared - || h == NULL - || h->dynindx == -1 - || ((h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - && h->root.u.def.section->output_section != NULL)) - { - /* If we are creating a shared library, then we will have to - create a runtime relocation for the symbol to properly - initialize the .opd entry. Make sure the symbol gets - added to the dynamic symbol table. */ - if (x->info->shared - && (h == NULL || (h->dynindx == -1))) - { - bfd *owner; - owner = (h ? h->root.u.def.section->owner : dyn_h->owner); - - if (!_bfd_elf64_link_record_local_dynamic_symbol - (x->info, owner, dyn_h->sym_indx)) - return false; - } - - /* This may not be necessary or desirable anymore now that - we have some support for dealing with section symbols - in dynamic relocs. But name munging does make the result - much easier to debug. ie, the EPLT reloc will reference - a symbol like .foobar, instead of .text + offset. */ - if (x->info->shared && h) - { - char *new_name; - struct elf_link_hash_entry *nh; - - new_name = alloca (strlen (h->root.root.string) + 2); - new_name[0] = '.'; - strcpy (new_name + 1, h->root.root.string); - - nh = elf_link_hash_lookup (elf_hash_table (x->info), - new_name, true, true, true); - - nh->root.type = h->root.type; - nh->root.u.def.value = h->root.u.def.value; - nh->root.u.def.section = h->root.u.def.section; - - if (! bfd_elf64_link_record_dynamic_symbol (x->info, nh)) - return false; - - } - dyn_h->opd_offset = x->ofs; - x->ofs += OPD_ENTRY_SIZE; - } - - /* Otherwise we do not need an opd entry. */ - else - dyn_h->want_opd = 0; - } - return true; -} - -/* HP requires the EI_OSABI field to be filled in. The assignment to - EI_ABIVERSION may not be strictly necessary. */ - -static void -elf64_hppa_post_process_headers (abfd, link_info) - bfd * abfd; - struct bfd_link_info * link_info ATTRIBUTE_UNUSED; -{ - Elf_Internal_Ehdr * i_ehdrp; - - i_ehdrp = elf_elfheader (abfd); - - if (strcmp (bfd_get_target (abfd), "elf64-hppa-linux") == 0) - { - i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_LINUX; - } - else - { - i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_HPUX; - i_ehdrp->e_ident[EI_ABIVERSION] = 1; - } -} - -/* Create function descriptor section (.opd). This section is called .opd - because it contains "official prodecure descriptors". The "official" - refers to the fact that these descriptors are used when taking the address - of a procedure, thus ensuring a unique address for each procedure. */ - -static boolean -get_opd (abfd, info, hppa_info) - bfd *abfd; - struct bfd_link_info *info ATTRIBUTE_UNUSED; - struct elf64_hppa_link_hash_table *hppa_info; -{ - asection *opd; - bfd *dynobj; - - opd = hppa_info->opd_sec; - if (!opd) - { - dynobj = hppa_info->root.dynobj; - if (!dynobj) - hppa_info->root.dynobj = dynobj = abfd; - - opd = bfd_make_section (dynobj, ".opd"); - if (!opd - || !bfd_set_section_flags (dynobj, opd, - (SEC_ALLOC - | SEC_LOAD - | SEC_HAS_CONTENTS - | SEC_IN_MEMORY - | SEC_LINKER_CREATED)) - || !bfd_set_section_alignment (abfd, opd, 3)) - { - BFD_ASSERT (0); - return false; - } - - hppa_info->opd_sec = opd; - } - - return true; -} - -/* Create the PLT section. */ - -static boolean -get_plt (abfd, info, hppa_info) - bfd *abfd; - struct bfd_link_info *info ATTRIBUTE_UNUSED; - struct elf64_hppa_link_hash_table *hppa_info; -{ - asection *plt; - bfd *dynobj; - - plt = hppa_info->plt_sec; - if (!plt) - { - dynobj = hppa_info->root.dynobj; - if (!dynobj) - hppa_info->root.dynobj = dynobj = abfd; - - plt = bfd_make_section (dynobj, ".plt"); - if (!plt - || !bfd_set_section_flags (dynobj, plt, - (SEC_ALLOC - | SEC_LOAD - | SEC_HAS_CONTENTS - | SEC_IN_MEMORY - | SEC_LINKER_CREATED)) - || !bfd_set_section_alignment (abfd, plt, 3)) - { - BFD_ASSERT (0); - return false; - } - - hppa_info->plt_sec = plt; - } - - return true; -} - -/* Create the DLT section. */ - -static boolean -get_dlt (abfd, info, hppa_info) - bfd *abfd; - struct bfd_link_info *info ATTRIBUTE_UNUSED; - struct elf64_hppa_link_hash_table *hppa_info; -{ - asection *dlt; - bfd *dynobj; - - dlt = hppa_info->dlt_sec; - if (!dlt) - { - dynobj = hppa_info->root.dynobj; - if (!dynobj) - hppa_info->root.dynobj = dynobj = abfd; - - dlt = bfd_make_section (dynobj, ".dlt"); - if (!dlt - || !bfd_set_section_flags (dynobj, dlt, - (SEC_ALLOC - | SEC_LOAD - | SEC_HAS_CONTENTS - | SEC_IN_MEMORY - | SEC_LINKER_CREATED)) - || !bfd_set_section_alignment (abfd, dlt, 3)) - { - BFD_ASSERT (0); - return false; - } - - hppa_info->dlt_sec = dlt; - } - - return true; -} - -/* Create the stubs section. */ - -static boolean -get_stub (abfd, info, hppa_info) - bfd *abfd; - struct bfd_link_info *info ATTRIBUTE_UNUSED; - struct elf64_hppa_link_hash_table *hppa_info; -{ - asection *stub; - bfd *dynobj; - - stub = hppa_info->stub_sec; - if (!stub) - { - dynobj = hppa_info->root.dynobj; - if (!dynobj) - hppa_info->root.dynobj = dynobj = abfd; - - stub = bfd_make_section (dynobj, ".stub"); - if (!stub - || !bfd_set_section_flags (dynobj, stub, - (SEC_ALLOC - | SEC_LOAD - | SEC_HAS_CONTENTS - | SEC_IN_MEMORY - | SEC_READONLY - | SEC_LINKER_CREATED)) - || !bfd_set_section_alignment (abfd, stub, 3)) - { - BFD_ASSERT (0); - return false; - } - - hppa_info->stub_sec = stub; - } - - return true; -} - -/* Create sections necessary for dynamic linking. This is only a rough - cut and will likely change as we learn more about the somewhat - unusual dynamic linking scheme HP uses. - - .stub: - Contains code to implement cross-space calls. The first time one - of the stubs is used it will call into the dynamic linker, later - calls will go straight to the target. - - The only stub we support right now looks like - - ldd OFFSET(%dp),%r1 - bve %r0(%r1) - ldd OFFSET+8(%dp),%dp - - Other stubs may be needed in the future. We may want the remove - the break/nop instruction. It is only used right now to keep the - offset of a .plt entry and a .stub entry in sync. - - .dlt: - This is what most people call the .got. HP used a different name. - Losers. - - .rela.dlt: - Relocations for the DLT. - - .plt: - Function pointers as address,gp pairs. - - .rela.plt: - Should contain dynamic IPLT (and EPLT?) relocations. - - .opd: - FPTRS - - .rela.opd: - EPLT relocations for symbols exported from shared libraries. */ - -static boolean -elf64_hppa_create_dynamic_sections (abfd, info) - bfd *abfd; - struct bfd_link_info *info; -{ - asection *s; - - if (! get_stub (abfd, info, elf64_hppa_hash_table (info))) - return false; - - if (! get_dlt (abfd, info, elf64_hppa_hash_table (info))) - return false; - - if (! get_plt (abfd, info, elf64_hppa_hash_table (info))) - return false; - - if (! get_opd (abfd, info, elf64_hppa_hash_table (info))) - return false; - - s = bfd_make_section(abfd, ".rela.dlt"); - if (s == NULL - || !bfd_set_section_flags (abfd, s, (SEC_ALLOC | SEC_LOAD - | SEC_HAS_CONTENTS - | SEC_IN_MEMORY - | SEC_READONLY - | SEC_LINKER_CREATED)) - || !bfd_set_section_alignment (abfd, s, 3)) - return false; - elf64_hppa_hash_table (info)->dlt_rel_sec = s; - - s = bfd_make_section(abfd, ".rela.plt"); - if (s == NULL - || !bfd_set_section_flags (abfd, s, (SEC_ALLOC | SEC_LOAD - | SEC_HAS_CONTENTS - | SEC_IN_MEMORY - | SEC_READONLY - | SEC_LINKER_CREATED)) - || !bfd_set_section_alignment (abfd, s, 3)) - return false; - elf64_hppa_hash_table (info)->plt_rel_sec = s; - - s = bfd_make_section(abfd, ".rela.data"); - if (s == NULL - || !bfd_set_section_flags (abfd, s, (SEC_ALLOC | SEC_LOAD - | SEC_HAS_CONTENTS - | SEC_IN_MEMORY - | SEC_READONLY - | SEC_LINKER_CREATED)) - || !bfd_set_section_alignment (abfd, s, 3)) - return false; - elf64_hppa_hash_table (info)->other_rel_sec = s; - - s = bfd_make_section(abfd, ".rela.opd"); - if (s == NULL - || !bfd_set_section_flags (abfd, s, (SEC_ALLOC | SEC_LOAD - | SEC_HAS_CONTENTS - | SEC_IN_MEMORY - | SEC_READONLY - | SEC_LINKER_CREATED)) - || !bfd_set_section_alignment (abfd, s, 3)) - return false; - elf64_hppa_hash_table (info)->opd_rel_sec = s; - - return true; -} - -/* Allocate dynamic relocations for those symbols that turned out - to be dynamic. */ - -static boolean -allocate_dynrel_entries (dyn_h, data) - struct elf64_hppa_dyn_hash_entry *dyn_h; - PTR data; -{ - struct elf64_hppa_allocate_data *x = (struct elf64_hppa_allocate_data *)data; - struct elf64_hppa_link_hash_table *hppa_info; - struct elf64_hppa_dyn_reloc_entry *rent; - boolean dynamic_symbol, shared; - - hppa_info = elf64_hppa_hash_table (x->info); - dynamic_symbol = elf64_hppa_dynamic_symbol_p (dyn_h->h, x->info); - shared = x->info->shared; - - /* We may need to allocate relocations for a non-dynamic symbol - when creating a shared library. */ - if (!dynamic_symbol && !shared) - return true; - - /* Take care of the normal data relocations. */ - - for (rent = dyn_h->reloc_entries; rent; rent = rent->next) - { - switch (rent->type) - { - case R_PARISC_FPTR64: - /* Allocate one iff we are not building a shared library and - !want_opd, which by this point will be true only if we're - actually allocating one statically in the main executable. */ - if (!x->info->shared && dyn_h->want_opd) - continue; - break; - } - hppa_info->other_rel_sec->_raw_size += sizeof (Elf64_External_Rela); - - /* Make sure this symbol gets into the dynamic symbol table if it is - not already recorded. ?!? This should not be in the loop since - the symbol need only be added once. */ - if (dyn_h->h == 0 || dyn_h->h->dynindx == -1) - if (!_bfd_elf64_link_record_local_dynamic_symbol - (x->info, rent->sec->owner, dyn_h->sym_indx)) - return false; - } - - /* Take care of the GOT and PLT relocations. */ - - if ((dynamic_symbol || shared) && dyn_h->want_dlt) - hppa_info->dlt_rel_sec->_raw_size += sizeof (Elf64_External_Rela); - - /* If we are building a shared library, then every symbol that has an - opd entry will need an EPLT relocation to relocate the symbol's address - and __gp value based on the runtime load address. */ - if (shared && dyn_h->want_opd) - hppa_info->opd_rel_sec->_raw_size += sizeof (Elf64_External_Rela); - - if (dyn_h->want_plt && dynamic_symbol) - { - bfd_size_type t = 0; - - /* Dynamic symbols get one IPLT relocation. Local symbols in - shared libraries get two REL relocations. Local symbols in - main applications get nothing. */ - if (dynamic_symbol) - t = sizeof (Elf64_External_Rela); - else if (shared) - t = 2 * sizeof (Elf64_External_Rela); - - hppa_info->plt_rel_sec->_raw_size += t; - } - - return true; -} - -/* Adjust a symbol defined by a dynamic object and referenced by a - regular object. */ - -static boolean -elf64_hppa_adjust_dynamic_symbol (info, h) - struct bfd_link_info *info ATTRIBUTE_UNUSED; - struct elf_link_hash_entry *h; -{ - /* ??? Undefined symbols with PLT entries should be re-defined - to be the PLT entry. */ - - /* 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; - } - - /* If this is a reference to a symbol defined by a dynamic object which - is not a function, we might allocate the symbol in our .dynbss section - and allocate a COPY dynamic relocation. - - But PA64 code is canonically PIC, so as a rule we can avoid this sort - of hackery. */ - - return true; -} - -/* Set the final sizes of the dynamic sections and allocate memory for - the contents of our special sections. */ - -static boolean -elf64_hppa_size_dynamic_sections (output_bfd, info) - bfd *output_bfd; - struct bfd_link_info *info; -{ - bfd *dynobj; - asection *s; - boolean plt; - boolean relocs; - boolean reltext; - struct elf64_hppa_allocate_data data; - struct elf64_hppa_link_hash_table *hppa_info; - - hppa_info = elf64_hppa_hash_table (info); - - dynobj = elf_hash_table (info)->dynobj; - BFD_ASSERT (dynobj != NULL); - - if (elf_hash_table (info)->dynamic_sections_created) - { - /* 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; - } - } - else - { - /* 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.dlt, - which will cause it to get stripped from the output file - below. */ - s = bfd_get_section_by_name (dynobj, ".rela.dlt"); - if (s != NULL) - s->_raw_size = 0; - } - - /* Allocate the GOT entries. */ - - data.info = info; - if (elf64_hppa_hash_table (info)->dlt_sec) - { - data.ofs = 0x0; - elf64_hppa_dyn_hash_traverse (&hppa_info->dyn_hash_table, - allocate_global_data_dlt, &data); - hppa_info->dlt_sec->_raw_size = data.ofs; - - data.ofs = 0x0; - elf64_hppa_dyn_hash_traverse (&hppa_info->dyn_hash_table, - allocate_global_data_plt, &data); - hppa_info->plt_sec->_raw_size = data.ofs; - - data.ofs = 0x0; - elf64_hppa_dyn_hash_traverse (&hppa_info->dyn_hash_table, - allocate_global_data_stub, &data); - hppa_info->stub_sec->_raw_size = data.ofs; - } - - /* Mark each function this program exports so that we will allocate - space in the .opd section for each function's FPTR. - - We have to traverse the main linker hash table since we have to - find functions which may not have been mentioned in any relocs. */ - elf_link_hash_traverse (elf_hash_table (info), - elf64_hppa_mark_exported_functions, - info); - - /* Allocate space for entries in the .opd section. */ - if (elf64_hppa_hash_table (info)->opd_sec) - { - data.ofs = 0; - elf64_hppa_dyn_hash_traverse (&hppa_info->dyn_hash_table, - allocate_global_data_opd, &data); - hppa_info->opd_sec->_raw_size = data.ofs; - } - - /* Now allocate space for dynamic relocations, if necessary. */ - if (hppa_info->root.dynamic_sections_created) - elf64_hppa_dyn_hash_traverse (&hppa_info->dyn_hash_table, - allocate_dynrel_entries, &data); - - /* The sizes of all the sections are set. Allocate memory for them. */ - plt = false; - relocs = false; - reltext = false; - for (s = dynobj->sections; s != NULL; s = s->next) - { - const char *name; - boolean strip; - - 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); - - strip = 0; - - if (strcmp (name, ".plt") == 0) - { - if (s->_raw_size == 0) - { - /* Strip this section if we don't need it; see the - comment below. */ - strip = true; - } - else - { - /* Remember whether there is a PLT. */ - plt = true; - } - } - else if (strcmp (name, ".dlt") == 0) - { - if (s->_raw_size == 0) - { - /* Strip this section if we don't need it; see the - comment below. */ - strip = true; - } - } - else if (strcmp (name, ".opd") == 0) - { - if (s->_raw_size == 0) - { - /* Strip this section if we don't need it; see the - comment below. */ - strip = true; - } - } - else if (strncmp (name, ".rela", 4) == 0) - { - 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. */ - strip = true; - } - else - { - asection *target; - - /* Remember whether there are any reloc sections other - than .rela.plt. */ - if (strcmp (name, ".rela.plt") != 0) - { - const char *outname; - - relocs = true; - - /* If this relocation section applies to a read only - section, then we probably need a DT_TEXTREL - entry. The entries in the .rela.plt section - really apply to the .got section, which we - created ourselves and so know is not readonly. */ - outname = bfd_get_section_name (output_bfd, - s->output_section); - target = bfd_get_section_by_name (output_bfd, outname + 4); - 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 (strncmp (name, ".dlt", 4) != 0 - && strcmp (name, ".stub") != 0 - && strcmp (name, ".got") != 0) - { - /* It's not one of our sections, so don't allocate space. */ - continue; - } - - if (strip) - { - _bfd_strip_section_from_output (info, s); - continue; - } - - /* Allocate memory for the section contents if it has not - been allocated already. We use bfd_zalloc here in case - unused entries are not reclaimed before the section's - contents are written out. This should not happen, but this - way if it does, we get a R_PARISC_NONE reloc instead of - garbage. */ - if (s->contents == NULL) - { - s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->_raw_size); - if (s->contents == NULL && s->_raw_size != 0) - return false; - } - } - - if (elf_hash_table (info)->dynamic_sections_created) - { - /* Always create a DT_PLTGOT. It actually has nothing to do with - the PLT, it is how we communicate the __gp value of a load - module to the dynamic linker. */ - if (! bfd_elf64_add_dynamic_entry (info, DT_HP_DLD_FLAGS, 0) - || ! bfd_elf64_add_dynamic_entry (info, DT_PLTGOT, 0)) - return false; - - /* Add some entries to the .dynamic section. We fill in the - values later, in elf64_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_elf64_add_dynamic_entry (info, DT_DEBUG, 0) - || ! bfd_elf64_add_dynamic_entry (info, DT_HP_DLD_HOOK, 0) - || ! bfd_elf64_add_dynamic_entry (info, DT_HP_LOAD_MAP, 0)) - return false; - } - - if (plt) - { - if (! bfd_elf64_add_dynamic_entry (info, DT_PLTRELSZ, 0) - || ! bfd_elf64_add_dynamic_entry (info, DT_PLTREL, DT_RELA) - || ! bfd_elf64_add_dynamic_entry (info, DT_JMPREL, 0)) - return false; - } - - if (relocs) - { - if (! bfd_elf64_add_dynamic_entry (info, DT_RELA, 0) - || ! bfd_elf64_add_dynamic_entry (info, DT_RELASZ, 0) - || ! bfd_elf64_add_dynamic_entry (info, DT_RELAENT, - sizeof (Elf64_External_Rela))) - return false; - } - - if (reltext) - { - if (! bfd_elf64_add_dynamic_entry (info, DT_TEXTREL, 0)) - return false; - info->flags |= DF_TEXTREL; - } - } - - return true; -} - -/* Called after we have output the symbol into the dynamic symbol - table, but before we output the symbol into the normal symbol - table. - - For some symbols we had to change their address when outputting - the dynamic symbol table. We undo that change here so that - the symbols have their expected value in the normal symbol - table. Ick. */ - -static boolean -elf64_hppa_link_output_symbol_hook (abfd, info, name, sym, input_sec) - bfd *abfd ATTRIBUTE_UNUSED; - struct bfd_link_info *info; - const char *name; - Elf_Internal_Sym *sym; - asection *input_sec ATTRIBUTE_UNUSED; -{ - struct elf64_hppa_link_hash_table *hppa_info; - struct elf64_hppa_dyn_hash_entry *dyn_h; - - /* We may be called with the file symbol or section symbols. - They never need munging, so it is safe to ignore them. */ - if (!name) - return true; - - /* Get the PA dyn_symbol (if any) associated with NAME. */ - hppa_info = elf64_hppa_hash_table (info); - dyn_h = elf64_hppa_dyn_hash_lookup (&hppa_info->dyn_hash_table, - name, false, false); - - /* Function symbols for which we created .opd entries *may* have been - munged by finish_dynamic_symbol and have to be un-munged here. - - Note that finish_dynamic_symbol sometimes turns dynamic symbols - into non-dynamic ones, so we initialize st_shndx to -1 in - mark_exported_functions and check to see if it was overwritten - here instead of just checking dyn_h->h->dynindx. */ - if (dyn_h && dyn_h->want_opd && dyn_h->st_shndx != -1) - { - /* Restore the saved value and section index. */ - sym->st_value = dyn_h->st_value; - sym->st_shndx = dyn_h->st_shndx; - } - - return true; -} - -/* Finish up dynamic symbol handling. We set the contents of various - dynamic sections here. */ - -static boolean -elf64_hppa_finish_dynamic_symbol (output_bfd, info, h, sym) - bfd *output_bfd; - struct bfd_link_info *info; - struct elf_link_hash_entry *h; - Elf_Internal_Sym *sym; -{ - asection *stub, *splt, *sdlt, *sopd, *spltrel, *sdltrel; - struct elf64_hppa_link_hash_table *hppa_info; - struct elf64_hppa_dyn_hash_entry *dyn_h; - - hppa_info = elf64_hppa_hash_table (info); - dyn_h = elf64_hppa_dyn_hash_lookup (&hppa_info->dyn_hash_table, - h->root.root.string, false, false); - - stub = hppa_info->stub_sec; - splt = hppa_info->plt_sec; - sdlt = hppa_info->dlt_sec; - sopd = hppa_info->opd_sec; - spltrel = hppa_info->plt_rel_sec; - sdltrel = hppa_info->dlt_rel_sec; - - BFD_ASSERT (stub != NULL && splt != NULL - && sopd != NULL && sdlt != NULL) - - /* Incredible. It is actually necessary to NOT use the symbol's real - value when building the dynamic symbol table for a shared library. - At least for symbols that refer to functions. - - We will store a new value and section index into the symbol long - enough to output it into the dynamic symbol table, then we restore - the original values (in elf64_hppa_link_output_symbol_hook). */ - if (dyn_h && dyn_h->want_opd) - { - /* Save away the original value and section index so that we - can restore them later. */ - dyn_h->st_value = sym->st_value; - dyn_h->st_shndx = sym->st_shndx; - - /* For the dynamic symbol table entry, we want the value to be - address of this symbol's entry within the .opd section. */ - sym->st_value = (dyn_h->opd_offset - + sopd->output_offset - + sopd->output_section->vma); - sym->st_shndx = _bfd_elf_section_from_bfd_section (output_bfd, - sopd->output_section); - } - - /* Initialize a .plt entry if requested. */ - if (dyn_h && dyn_h->want_plt - && elf64_hppa_dynamic_symbol_p (dyn_h->h, info)) - { - bfd_vma value; - Elf_Internal_Rela rel; - - /* We do not actually care about the value in the PLT entry - if we are creating a shared library and the symbol is - still undefined, we create a dynamic relocation to fill - in the correct value. */ - if (info->shared && h->root.type == bfd_link_hash_undefined) - value = 0; - else - value = (h->root.u.def.value + h->root.u.def.section->vma); - - /* Fill in the entry in the procedure linkage table. - - The format of a plt entry is - <funcaddr> <__gp>. - - plt_offset is the offset within the PLT section at which to - install the PLT entry. - - We are modifying the in-memory PLT contents here, so we do not add - in the output_offset of the PLT section. */ - - bfd_put_64 (splt->owner, value, splt->contents + dyn_h->plt_offset); - value = _bfd_get_gp_value (splt->output_section->owner); - bfd_put_64 (splt->owner, value, splt->contents + dyn_h->plt_offset + 0x8); - - /* Create a dynamic IPLT relocation for this entry. - - We are creating a relocation in the output file's PLT section, - which is included within the DLT secton. So we do need to include - the PLT's output_offset in the computation of the relocation's - address. */ - rel.r_offset = (dyn_h->plt_offset + splt->output_offset - + splt->output_section->vma); - rel.r_info = ELF64_R_INFO (h->dynindx, R_PARISC_IPLT); - rel.r_addend = 0; - - bfd_elf64_swap_reloca_out (splt->output_section->owner, &rel, - (((Elf64_External_Rela *) - spltrel->contents) - + spltrel->reloc_count)); - spltrel->reloc_count++; - } - - /* Initialize an external call stub entry if requested. */ - if (dyn_h && dyn_h->want_stub - && elf64_hppa_dynamic_symbol_p (dyn_h->h, info)) - { - bfd_vma value; - int insn; - unsigned int max_offset; - - /* Install the generic stub template. - - We are modifying the contents of the stub section, so we do not - need to include the stub section's output_offset here. */ - memcpy (stub->contents + dyn_h->stub_offset, plt_stub, sizeof (plt_stub)); - - /* Fix up the first ldd instruction. - - We are modifying the contents of the STUB section in memory, - so we do not need to include its output offset in this computation. - - Note the plt_offset value is the value of the PLT entry relative to - the start of the PLT section. These instructions will reference - data relative to the value of __gp, which may not necessarily have - the same address as the start of the PLT section. - - gp_offset contains the offset of __gp within the PLT section. */ - value = dyn_h->plt_offset - hppa_info->gp_offset; - - insn = bfd_get_32 (stub->owner, stub->contents + dyn_h->stub_offset); - if (output_bfd->arch_info->mach >= 25) - { - /* Wide mode allows 16 bit offsets. */ - max_offset = 32768; - insn &= ~ 0xfff1; - insn |= re_assemble_16 (value); - } - else - { - max_offset = 8192; - insn &= ~ 0x3ff1; - insn |= re_assemble_14 (value); - } - - if ((value & 7) || value + max_offset >= 2*max_offset - 8) - { - (*_bfd_error_handler) (_("stub entry for %s cannot load .plt, dp offset = %ld"), - dyn_h->root.string, - (long) value); - return false; - } - - bfd_put_32 (stub->owner, insn, - stub->contents + dyn_h->stub_offset); - - /* Fix up the second ldd instruction. */ - value += 8; - insn = bfd_get_32 (stub->owner, stub->contents + dyn_h->stub_offset + 8); - if (output_bfd->arch_info->mach >= 25) - { - insn &= ~ 0xfff1; - insn |= re_assemble_16 (value); - } - else - { - insn &= ~ 0x3ff1; - insn |= re_assemble_14 (value); - } - bfd_put_32 (stub->owner, insn, - stub->contents + dyn_h->stub_offset + 8); - } - - /* Millicode symbols should not be put in the dynamic - symbol table under any circumstances. */ - if (ELF_ST_TYPE (sym->st_info) == STT_PARISC_MILLI) - h->dynindx = -1; - - return true; -} - -/* The .opd section contains FPTRs for each function this file - exports. Initialize the FPTR entries. */ - -static boolean -elf64_hppa_finalize_opd (dyn_h, data) - struct elf64_hppa_dyn_hash_entry *dyn_h; - PTR data; -{ - struct bfd_link_info *info = (struct bfd_link_info *)data; - struct elf64_hppa_link_hash_table *hppa_info; - struct elf_link_hash_entry *h = dyn_h->h; - asection *sopd; - asection *sopdrel; - - hppa_info = elf64_hppa_hash_table (info); - sopd = hppa_info->opd_sec; - sopdrel = hppa_info->opd_rel_sec; - - if (h && dyn_h && dyn_h->want_opd) - { - bfd_vma value; - - /* The first two words of an .opd entry are zero. - - We are modifying the contents of the OPD section in memory, so we - do not need to include its output offset in this computation. */ - memset (sopd->contents + dyn_h->opd_offset, 0, 16); - - value = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - - /* The next word is the address of the function. */ - bfd_put_64 (sopd->owner, value, sopd->contents + dyn_h->opd_offset + 16); - - /* The last word is our local __gp value. */ - value = _bfd_get_gp_value (sopd->output_section->owner); - bfd_put_64 (sopd->owner, value, sopd->contents + dyn_h->opd_offset + 24); - } - - /* If we are generating a shared library, we must generate EPLT relocations - for each entry in the .opd, even for static functions (they may have - had their address taken). */ - if (info->shared && dyn_h && dyn_h->want_opd) - { - Elf64_Internal_Rela rel; - int dynindx; - - /* We may need to do a relocation against a local symbol, in - which case we have to look up it's dynamic symbol index off - the local symbol hash table. */ - if (h && h->dynindx != -1) - dynindx = h->dynindx; - else - dynindx - = _bfd_elf_link_lookup_local_dynindx (info, dyn_h->owner, - dyn_h->sym_indx); - - /* The offset of this relocation is the absolute address of the - .opd entry for this symbol. */ - rel.r_offset = (dyn_h->opd_offset + sopd->output_offset - + sopd->output_section->vma); - - /* If H is non-null, then we have an external symbol. - - It is imperative that we use a different dynamic symbol for the - EPLT relocation if the symbol has global scope. - - In the dynamic symbol table, the function symbol will have a value - which is address of the function's .opd entry. - - Thus, we can not use that dynamic symbol for the EPLT relocation - (if we did, the data in the .opd would reference itself rather - than the actual address of the function). Instead we have to use - a new dynamic symbol which has the same value as the original global - function symbol. - - We prefix the original symbol with a "." and use the new symbol in - the EPLT relocation. This new symbol has already been recorded in - the symbol table, we just have to look it up and use it. - - We do not have such problems with static functions because we do - not make their addresses in the dynamic symbol table point to - the .opd entry. Ultimately this should be safe since a static - function can not be directly referenced outside of its shared - library. - - We do have to play similar games for FPTR relocations in shared - libraries, including those for static symbols. See the FPTR - handling in elf64_hppa_finalize_dynreloc. */ - if (h) - { - char *new_name; - struct elf_link_hash_entry *nh; - - new_name = alloca (strlen (h->root.root.string) + 2); - new_name[0] = '.'; - strcpy (new_name + 1, h->root.root.string); - - nh = elf_link_hash_lookup (elf_hash_table (info), - new_name, false, false, false); - - /* All we really want from the new symbol is its dynamic - symbol index. */ - dynindx = nh->dynindx; - } - - rel.r_addend = 0; - rel.r_info = ELF64_R_INFO (dynindx, R_PARISC_EPLT); - - bfd_elf64_swap_reloca_out (sopd->output_section->owner, &rel, - (((Elf64_External_Rela *) - sopdrel->contents) - + sopdrel->reloc_count)); - sopdrel->reloc_count++; - } - return true; -} - -/* The .dlt section contains addresses for items referenced through the - dlt. Note that we can have a DLTIND relocation for a local symbol, thus - we can not depend on finish_dynamic_symbol to initialize the .dlt. */ - -static boolean -elf64_hppa_finalize_dlt (dyn_h, data) - struct elf64_hppa_dyn_hash_entry *dyn_h; - PTR data; -{ - struct bfd_link_info *info = (struct bfd_link_info *)data; - struct elf64_hppa_link_hash_table *hppa_info; - asection *sdlt, *sdltrel; - struct elf_link_hash_entry *h = dyn_h->h; - - hppa_info = elf64_hppa_hash_table (info); - - sdlt = hppa_info->dlt_sec; - sdltrel = hppa_info->dlt_rel_sec; - - /* H/DYN_H may refer to a local variable and we know it's - address, so there is no need to create a relocation. Just install - the proper value into the DLT, note this shortcut can not be - skipped when building a shared library. */ - if (! info->shared && h && dyn_h && dyn_h->want_dlt) - { - bfd_vma value; - - /* If we had an LTOFF_FPTR style relocation we want the DLT entry - to point to the FPTR entry in the .opd section. - - We include the OPD's output offset in this computation as - we are referring to an absolute address in the resulting - object file. */ - if (dyn_h->want_opd) - { - value = (dyn_h->opd_offset - + hppa_info->opd_sec->output_offset - + hppa_info->opd_sec->output_section->vma); - } - else - { - value = (h->root.u.def.value - + h->root.u.def.section->output_offset); - - if (h->root.u.def.section->output_section) - value += h->root.u.def.section->output_section->vma; - else - value += h->root.u.def.section->vma; - } - - /* We do not need to include the output offset of the DLT section - here because we are modifying the in-memory contents. */ - bfd_put_64 (sdlt->owner, value, sdlt->contents + dyn_h->dlt_offset); - } - - /* Create a relocation for the DLT entry assocated with this symbol. - When building a shared library the symbol does not have to be dynamic. */ - if (dyn_h->want_dlt - && (elf64_hppa_dynamic_symbol_p (dyn_h->h, info) || info->shared)) - { - Elf64_Internal_Rela rel; - int dynindx; - - /* We may need to do a relocation against a local symbol, in - which case we have to look up it's dynamic symbol index off - the local symbol hash table. */ - if (h && h->dynindx != -1) - dynindx = h->dynindx; - else - dynindx - = _bfd_elf_link_lookup_local_dynindx (info, dyn_h->owner, - dyn_h->sym_indx); - - /* Create a dynamic relocation for this entry. Do include the output - offset of the DLT entry since we need an absolute address in the - resulting object file. */ - rel.r_offset = (dyn_h->dlt_offset + sdlt->output_offset - + sdlt->output_section->vma); - if (h && h->type == STT_FUNC) - rel.r_info = ELF64_R_INFO (dynindx, R_PARISC_FPTR64); - else - rel.r_info = ELF64_R_INFO (dynindx, R_PARISC_DIR64); - rel.r_addend = 0; - - bfd_elf64_swap_reloca_out (sdlt->output_section->owner, &rel, - (((Elf64_External_Rela *) - sdltrel->contents) - + sdltrel->reloc_count)); - sdltrel->reloc_count++; - } - return true; -} - -/* Finalize the dynamic relocations. Specifically the FPTR relocations - for dynamic functions used to initialize static data. */ - -static boolean -elf64_hppa_finalize_dynreloc (dyn_h, data) - struct elf64_hppa_dyn_hash_entry *dyn_h; - PTR data; -{ - struct bfd_link_info *info = (struct bfd_link_info *)data; - struct elf64_hppa_link_hash_table *hppa_info; - struct elf_link_hash_entry *h; - int dynamic_symbol; - - dynamic_symbol = elf64_hppa_dynamic_symbol_p (dyn_h->h, info); - - if (!dynamic_symbol && !info->shared) - return true; - - if (dyn_h->reloc_entries) - { - struct elf64_hppa_dyn_reloc_entry *rent; - int dynindx; - - hppa_info = elf64_hppa_hash_table (info); - h = dyn_h->h; - - /* We may need to do a relocation against a local symbol, in - which case we have to look up it's dynamic symbol index off - the local symbol hash table. */ - if (h && h->dynindx != -1) - dynindx = h->dynindx; - else - dynindx - = _bfd_elf_link_lookup_local_dynindx (info, dyn_h->owner, - dyn_h->sym_indx); - - for (rent = dyn_h->reloc_entries; rent; rent = rent->next) - { - Elf64_Internal_Rela rel; - - switch (rent->type) - { - case R_PARISC_FPTR64: - /* Allocate one iff we are not building a shared library and - !want_opd, which by this point will be true only if we're - actually allocating one statically in the main executable. */ - if (!info->shared && dyn_h->want_opd) - continue; - break; - } - - /* Create a dynamic relocation for this entry. - - We need the output offset for the reloc's section because - we are creating an absolute address in the resulting object - file. */ - rel.r_offset = (rent->offset + rent->sec->output_offset - + rent->sec->output_section->vma); - - /* An FPTR64 relocation implies that we took the address of - a function and that the function has an entry in the .opd - section. We want the FPTR64 relocation to reference the - entry in .opd. - - We could munge the symbol value in the dynamic symbol table - (in fact we already do for functions with global scope) to point - to the .opd entry. Then we could use that dynamic symbol in - this relocation. - - Or we could do something sensible, not munge the symbol's - address and instead just use a different symbol to reference - the .opd entry. At least that seems sensible until you - realize there's no local dynamic symbols we can use for that - purpose. Thus the hair in the check_relocs routine. - - We use a section symbol recorded by check_relocs as the - base symbol for the relocation. The addend is the difference - between the section symbol and the address of the .opd entry. */ - if (info->shared && rent->type == R_PARISC_FPTR64) - { - bfd_vma value, value2; - - /* First compute the address of the opd entry for this symbol. */ - value = (dyn_h->opd_offset - + hppa_info->opd_sec->output_section->vma - + hppa_info->opd_sec->output_offset); - - /* Compute the value of the start of the section with - the relocation. */ - value2 = (rent->sec->output_section->vma - + rent->sec->output_offset); - - /* Compute the difference between the start of the section - with the relocation and the opd entry. */ - value -= value2; - - /* The result becomes the addend of the relocation. */ - rel.r_addend = value; - - /* The section symbol becomes the symbol for the dynamic - relocation. */ - dynindx - = _bfd_elf_link_lookup_local_dynindx (info, - rent->sec->owner, - rent->sec_symndx); - } - else - rel.r_addend = rent->addend; - - rel.r_info = ELF64_R_INFO (dynindx, rent->type); - - bfd_elf64_swap_reloca_out (hppa_info->other_rel_sec->output_section->owner, - &rel, - (((Elf64_External_Rela *) - hppa_info->other_rel_sec->contents) - + hppa_info->other_rel_sec->reloc_count)); - hppa_info->other_rel_sec->reloc_count++; - } - } - - return true; -} - -/* Finish up the dynamic sections. */ - -static boolean -elf64_hppa_finish_dynamic_sections (output_bfd, info) - bfd *output_bfd; - struct bfd_link_info *info; -{ - bfd *dynobj; - asection *sdyn; - struct elf64_hppa_link_hash_table *hppa_info; - - hppa_info = elf64_hppa_hash_table (info); - - /* Finalize the contents of the .opd section. */ - elf64_hppa_dyn_hash_traverse (&hppa_info->dyn_hash_table, - elf64_hppa_finalize_opd, - info); - - elf64_hppa_dyn_hash_traverse (&hppa_info->dyn_hash_table, - elf64_hppa_finalize_dynreloc, - info); - - /* Finalize the contents of the .dlt section. */ - dynobj = elf_hash_table (info)->dynobj; - /* Finalize the contents of the .dlt section. */ - elf64_hppa_dyn_hash_traverse (&hppa_info->dyn_hash_table, - elf64_hppa_finalize_dlt, - info); - - sdyn = bfd_get_section_by_name (dynobj, ".dynamic"); - - if (elf_hash_table (info)->dynamic_sections_created) - { - Elf64_External_Dyn *dyncon, *dynconend; - - BFD_ASSERT (sdyn != NULL); - - dyncon = (Elf64_External_Dyn *) sdyn->contents; - dynconend = (Elf64_External_Dyn *) (sdyn->contents + sdyn->_raw_size); - for (; dyncon < dynconend; dyncon++) - { - Elf_Internal_Dyn dyn; - asection *s; - - bfd_elf64_swap_dyn_in (dynobj, dyncon, &dyn); - - switch (dyn.d_tag) - { - default: - break; - - case DT_HP_LOAD_MAP: - /* Compute the absolute address of 16byte scratchpad area - for the dynamic linker. - - By convention the linker script will allocate the scratchpad - area at the start of the .data section. So all we have to - to is find the start of the .data section. */ - s = bfd_get_section_by_name (output_bfd, ".data"); - dyn.d_un.d_ptr = s->vma; - bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - - case DT_PLTGOT: - /* HP's use PLTGOT to set the GOT register. */ - dyn.d_un.d_ptr = _bfd_get_gp_value (output_bfd); - bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - - case DT_JMPREL: - s = hppa_info->plt_rel_sec; - dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; - bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - - case DT_PLTRELSZ: - s = hppa_info->plt_rel_sec; - dyn.d_un.d_val = s->_raw_size; - bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - - case DT_RELA: - s = hppa_info->other_rel_sec; - if (! s) - s = hppa_info->dlt_rel_sec; - dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; - bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - - case DT_RELASZ: - s = hppa_info->other_rel_sec; - dyn.d_un.d_val = s->_raw_size; - s = hppa_info->dlt_rel_sec; - dyn.d_un.d_val += s->_raw_size; - s = hppa_info->opd_rel_sec; - dyn.d_un.d_val += s->_raw_size; - /* There is some question about whether or not the size of - the PLT relocs should be included here. HP's tools do - it, so we'll emulate them. */ - s = hppa_info->plt_rel_sec; - dyn.d_un.d_val += s->_raw_size; - bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - - } - } - } - - return true; -} - -/* Return the number of additional phdrs we will need. - - The generic ELF code only creates PT_PHDRs for executables. The HP - dynamic linker requires PT_PHDRs for dynamic libraries too. - - This routine indicates that the backend needs one additional program - header for that case. - - Note we do not have access to the link info structure here, so we have - to guess whether or not we are building a shared library based on the - existence of a .interp section. */ - -static int -elf64_hppa_additional_program_headers (abfd) - bfd *abfd; -{ - asection *s; - - /* If we are creating a shared library, then we have to create a - PT_PHDR segment. HP's dynamic linker chokes without it. */ - s = bfd_get_section_by_name (abfd, ".interp"); - if (! s) - return 1; - return 0; -} - -/* Allocate and initialize any program headers required by this - specific backend. - - The generic ELF code only creates PT_PHDRs for executables. The HP - dynamic linker requires PT_PHDRs for dynamic libraries too. - - This allocates the PT_PHDR and initializes it in a manner suitable - for the HP linker. - - Note we do not have access to the link info structure here, so we have - to guess whether or not we are building a shared library based on the - existence of a .interp section. */ - -static boolean -elf64_hppa_modify_segment_map (abfd) - bfd *abfd; -{ - struct elf_segment_map *m; - asection *s; - - s = bfd_get_section_by_name (abfd, ".interp"); - if (! s) - { - for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next) - if (m->p_type == PT_PHDR) - break; - if (m == NULL) - { - m = (struct elf_segment_map *) bfd_zalloc (abfd, sizeof *m); - if (m == NULL) - return false; - - m->p_type = PT_PHDR; - m->p_flags = PF_R | PF_X; - m->p_flags_valid = 1; - m->p_paddr_valid = 1; - m->includes_phdrs = 1; - - m->next = elf_tdata (abfd)->segment_map; - elf_tdata (abfd)->segment_map = m; - } - } - - for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next) - if (m->p_type == PT_LOAD) - { - unsigned int i; - - for (i = 0; i < m->count; i++) - { - /* The code "hint" is not really a hint. It is a requirement - for certain versions of the HP dynamic linker. Worse yet, - it must be set even if the shared library does not have - any code in its "text" segment (thus the check for .hash - to catch this situation). */ - if (m->sections[i]->flags & SEC_CODE - || (strcmp (m->sections[i]->name, ".hash") == 0)) - m->p_flags |= (PF_X | PF_HP_CODE); - } - } - - return true; -} - -/* Called when writing out an object file to decide the type of a - symbol. */ -static int -elf64_hppa_elf_get_symbol_type (elf_sym, type) - Elf_Internal_Sym *elf_sym; - int type; -{ - if (ELF_ST_TYPE (elf_sym->st_info) == STT_PARISC_MILLI) - return STT_PARISC_MILLI; - else - return type; -} - -/* The hash bucket size is the standard one, namely 4. */ - -const struct elf_size_info hppa64_elf_size_info = -{ - sizeof (Elf64_External_Ehdr), - sizeof (Elf64_External_Phdr), - sizeof (Elf64_External_Shdr), - sizeof (Elf64_External_Rel), - sizeof (Elf64_External_Rela), - sizeof (Elf64_External_Sym), - sizeof (Elf64_External_Dyn), - sizeof (Elf_External_Note), - 4, - 1, - 64, 8, - ELFCLASS64, EV_CURRENT, - bfd_elf64_write_out_phdrs, - bfd_elf64_write_shdrs_and_ehdr, - bfd_elf64_write_relocs, - bfd_elf64_swap_symbol_out, - bfd_elf64_slurp_reloc_table, - bfd_elf64_slurp_symbol_table, - bfd_elf64_swap_dyn_in, - bfd_elf64_swap_dyn_out, - NULL, - NULL, - NULL, - NULL -}; - -#define TARGET_BIG_SYM bfd_elf64_hppa_vec -#define TARGET_BIG_NAME "elf64-hppa" -#define ELF_ARCH bfd_arch_hppa -#define ELF_MACHINE_CODE EM_PARISC -/* This is not strictly correct. The maximum page size for PA2.0 is - 64M. But everything still uses 4k. */ -#define ELF_MAXPAGESIZE 0x1000 -#define bfd_elf64_bfd_reloc_type_lookup elf_hppa_reloc_type_lookup -#define bfd_elf64_bfd_is_local_label_name elf_hppa_is_local_label_name -#define elf_info_to_howto elf_hppa_info_to_howto -#define elf_info_to_howto_rel elf_hppa_info_to_howto_rel - -#define elf_backend_section_from_shdr elf64_hppa_section_from_shdr -#define elf_backend_object_p elf64_hppa_object_p -#define elf_backend_final_write_processing \ - elf_hppa_final_write_processing -#define elf_backend_fake_sections elf_hppa_fake_sections -#define elf_backend_add_symbol_hook elf_hppa_add_symbol_hook - -#define elf_backend_relocate_section elf_hppa_relocate_section - -#define bfd_elf64_bfd_final_link elf_hppa_final_link - -#define elf_backend_create_dynamic_sections \ - elf64_hppa_create_dynamic_sections -#define elf_backend_post_process_headers elf64_hppa_post_process_headers - -#define elf_backend_adjust_dynamic_symbol \ - elf64_hppa_adjust_dynamic_symbol - -#define elf_backend_size_dynamic_sections \ - elf64_hppa_size_dynamic_sections - -#define elf_backend_finish_dynamic_symbol \ - elf64_hppa_finish_dynamic_symbol -#define elf_backend_finish_dynamic_sections \ - elf64_hppa_finish_dynamic_sections - -/* Stuff for the BFD linker: */ -#define bfd_elf64_bfd_link_hash_table_create \ - elf64_hppa_hash_table_create - -#define elf_backend_check_relocs \ - elf64_hppa_check_relocs - -#define elf_backend_size_info \ - hppa64_elf_size_info - -#define elf_backend_additional_program_headers \ - elf64_hppa_additional_program_headers - -#define elf_backend_modify_segment_map \ - elf64_hppa_modify_segment_map - -#define elf_backend_link_output_symbol_hook \ - elf64_hppa_link_output_symbol_hook - -#define elf_backend_want_got_plt 0 -#define elf_backend_plt_readonly 0 -#define elf_backend_want_plt_sym 0 -#define elf_backend_got_header_size 0 -#define elf_backend_plt_header_size 0 -#define elf_backend_type_change_ok true -#define elf_backend_get_symbol_type elf64_hppa_elf_get_symbol_type - -#include "elf64-target.h" - -#undef TARGET_BIG_SYM -#define TARGET_BIG_SYM bfd_elf64_hppa_linux_vec -#undef TARGET_BIG_NAME -#define TARGET_BIG_NAME "elf64-hppa-linux" - -#define INCLUDED_TARGET_FILE 1 -#include "elf64-target.h" |