diff options
author | Alan Modra <amodra@gmail.com> | 2000-09-14 12:55:45 +0000 |
---|---|---|
committer | Alan Modra <amodra@gmail.com> | 2000-09-14 12:55:45 +0000 |
commit | 74d1c347e92b42c9d546fbe67d7a572a72c54a41 (patch) | |
tree | 9fb5b055353c682763c04636b16eebe1e51d6470 | |
parent | bf514e21545d180ded6d754fda60875d7dd0d3ae (diff) | |
download | fsf-binutils-gdb-74d1c347e92b42c9d546fbe67d7a572a72c54a41.zip fsf-binutils-gdb-74d1c347e92b42c9d546fbe67d7a572a72c54a41.tar.gz fsf-binutils-gdb-74d1c347e92b42c9d546fbe67d7a572a72c54a41.tar.bz2 |
Lots of bug fixes. .plt entries for DT_INIT, DT_FINI, and any
local function that has a plabel. Size the stub reloc sections
as we size the stubs.
-rw-r--r-- | bfd/ChangeLog | 76 | ||||
-rw-r--r-- | bfd/elf32-hppa.c | 819 |
2 files changed, 655 insertions, 240 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 066ccb7..d1d8b5b 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,79 @@ +2000-09-14 Alan Modra <alan@linuxcare.com.au> + + * elf32-hppa.c (elf32_hppa_link_hash_entry): Make pic_call + packed. Add plabel, plt_abs packed booleans. + (hppa_link_hash_newfunc): Init new fields. + (PLABEL_PLT_ENTRY_SIZE): Define. + (hppa_stub_name): Use size_t len vars. + (hppa_add_stub): Likewise. + (elf32_hppa_build_stubs): Likewise. + (hppa_build_one_stub): Kill some compiler warnings. + (elf32_hppa_check_relocs): Always generate a plt entry for PLABELs + if dynamic linking. Munge the local plt offsets into + local_got_refcounts. Set h->plabel for all global PLABELs. Use + size_t len vars. Add assert for plabel addend. + (elf32_hppa_gc_sweep_hook): Sweep local plt entries too. + (elf32_hppa_hide_symbol): New function. + (elf_backend_hide_symbol): Define. + (elf32_hppa_adjust_dynamic_symbol): Don't throw away plt entries + with h->plabel set. Don't make plt entries to have dynamic syms + when they have been forced local. If plt entry is used by a + plabel, make it PLABEL_PLT_ENTRY_SIZE. + (elf32_hppa_size_dynamic_sections): Set plt_abs for init fns. + Set up .plt offsets for local syms. + (elf32_hppa_relocate_section): Initialise plt entries for local + syms. Leave weak undefined plabels zero. Make global plabel + relocs against function symbol, and leave the addend zero. + Use *ABS* DIR32 relocs instead of SEGREL32 for dynamic got relocs. + (elf32_hppa_finish_dynamic_symbol): Set up IPLT relocs for + non-dynamic syms. Init extra plt for plabels. Use *ABS* DIR32 + relocs instead of SEGREL32 for dynamic got relocs. + (elf32_hppa_finish_dynamic_sections): Reserve one more .got entry. + (elf_backend_got_header_size): Adjust. + (elf32_hppa_set_gp): Calculate an "ideal" LTP. + + * elf32-hppa.c (LONG_BRANCH_VIA_PLT): Define. + (hppa_type_of_stub): Use it instead of #if 0 + (hppa_discard_copies): Use it here too. + (elf32_hppa_size_dynamic_sections): And here. + + * elf32-hppa.c (elf32_hppa_link_hash_table): Remove `offset' field. + (elf32_hppa_link_hash_table_create): And here. + (hppa_build_one_stub): And here. Instead keep track of stub + offset using _raw_size. + (elf32_hppa_size_stubs): Likewise. + (elf32_hppa_build_stubs): Likewise. + (hppa_size_one_stub): Likewise. Resize reloc section too. + + * elf32-hppa.c (hppa_add_stub): Correct first_init_sec and + first_fini_sec handling. Don't search for reloc section or set + hplink->reloc_section_created here. + (elf32_hppa_size_stubs): Instead search for reloc sections, and + set reloc_section_created here. + (hppa_handle_PIC_calls): Set ELF_LINK_HASH_NEEDS_PLT. + (elf32_hppa_size_dynamic_sections): Make a .plt entry for DT_INIT + and DT_FINI. + (elf32_hppa_finish_dynamic_sections): Set DT_INIT and DT_FINI. + + * elf32-hppa.c (hppa_build_one_stub): Replace `elf_hash_table (info)' + with `hplink->root.'. + (elf32_hppa_check_relocs): Likewise. + (elf32_hppa_gc_sweep_hook): Likewise. + (elf32_hppa_adjust_dynamic_symbol): Likewise. + (hppa_handle_PIC_calls): Likewise. + (elf32_hppa_size_dynamic_sections): Likewise. + (elf32_hppa_set_gp): Likewise. + (elf32_hppa_relocate_section): Likewise. + (elf32_hppa_finish_dynamic_symbol): Likewise. + (elf32_hppa_finish_dynamic_sections): Likewise. + + From David Huggins-Daines <dhd@linuxcare.com> + * elf32-hppa.c (hppa_type_of_stub): Generate import stubs for + defined weak symbols in shared links. + (final_link_relocate): Calls to defined weak symbols in shared + objects must go via import stubs, as the target might not be known + at link time. + 2000-09-14 Alexandre Oliva <aoliva@redhat.com> * elf32-sh.c (sh_elf_howto_table): Moved R_SH_GOT32, R_SH_PLT32, diff --git a/bfd/elf32-hppa.c b/bfd/elf32-hppa.c index b645b5f..e2f7e10 100644 --- a/bfd/elf32-hppa.c +++ b/bfd/elf32-hppa.c @@ -36,6 +36,18 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "elf32-hppa.h" +/* In order to gain some understanding of code in this file without + knowing all the intricate details of the linker, note the + following: + + Functions named elf32_hppa_* are called by external routines, other + functions are only called locally. elf32_hppa_* functions appear + in this file more or less in the order in which they are called + from external routines. eg. elf32_hppa_check_relocs is called + early in the link process, elf32_hppa_finish_dynamic_sections is + one of the last functions. */ + + /* We use two hash tables to hold information for linking PA ELF objects. The first is the elf32_hppa_link_hash_table which is derived @@ -101,10 +113,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ : ldw -24(%sp),%rp ; restore the original rp : ldsid (%rp),%r1 : mtsp %r1,%sr0 - : be,n 0(%sr0,%rp) ; inter-space return -*/ + : be,n 0(%sr0,%rp) ; inter-space return */ #define PLT_ENTRY_SIZE 8 +#define PLABEL_PLT_ENTRY_SIZE PLT_ENTRY_SIZE #define GOT_ENTRY_SIZE 4 #define ELF_DYNAMIC_INTERPRETER "/lib/ld.so.1" @@ -119,6 +131,13 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #define LONG_BRANCH_PIC_IN_SHLIB 1 #endif +/* Set this non-zero to use import stubs instead of long branch stubs + where a .plt entry exists for the symbol. This is a fairly useless + option as import stubs are bigger than PIC long branch stubs. */ +#ifndef LONG_BRANCH_VIA_PLT +#define LONG_BRANCH_VIA_PLT 0 +#endif + /* We don't need to copy any PC- or GP-relative dynamic relocs into a shared object's dynamic section. */ #ifndef RELATIVE_DYNAMIC_RELOCS @@ -198,7 +217,14 @@ struct elf32_hppa_link_hash_entry { #endif /* Set during a static link if we detect a function is PIC. */ - boolean pic_call; + unsigned int pic_call:1; + + /* Set if this symbol is used by a plabel reloc. */ + unsigned int plabel:1; + + /* Set if this symbol is an init or fini function and thus should + use an absolute reloc. */ + unsigned int plt_abs:1; }; @@ -228,9 +254,6 @@ struct elf32_hppa_link_hash_table { int first_init_sec; int first_fini_sec; - /* Current offsets in the stub sections. */ - bfd_vma *offset; - /* Short-cuts to get to dynamic linker sections. */ asection *sgot; asection *srelgot; @@ -241,14 +264,6 @@ struct elf32_hppa_link_hash_table { }; -/* Functions named elf32_hppa_* are called by external routines, other - functions are only called locally. elf32_hppa_* functions appear - in this file more or less in the order in which they are called - from external routines. eg. elf32_hppa_check_relocs is called - early in the link process, elf32_hppa_finish_dynamic_sections is - one of the last functions. */ - - /* Various hash macros and functions. */ #define hppa_link_hash_table(p) \ ((struct elf32_hppa_link_hash_table *) ((p)->hash)) @@ -315,13 +330,17 @@ static boolean elf32_hppa_gc_sweep_hook PARAMS ((bfd *, struct bfd_link_info *, asection *, const Elf_Internal_Rela *)); +static void elf32_hppa_hide_symbol + PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *)); + static boolean elf32_hppa_adjust_dynamic_symbol PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *)); static boolean hppa_handle_PIC_calls PARAMS ((struct elf_link_hash_entry *, PTR)); -#if ! LONG_BRANCH_PIC_IN_SHLIB || RELATIVE_DYNAMIC_RELOCS +#if ((! LONG_BRANCH_PIC_IN_SHLIB && LONG_BRANCH_VIA_PLT) \ + || RELATIVE_DYNAMIC_RELOCS) static boolean hppa_discard_copies PARAMS ((struct elf_link_hash_entry *, PTR)); #endif @@ -436,6 +455,8 @@ hppa_link_hash_newfunc (entry, table, string) ret->reloc_entries = NULL; #endif ret->pic_call = 0; + ret->plabel = 0; + ret->plt_abs = 0; } return (struct bfd_hash_entry *) ret; @@ -476,7 +497,6 @@ elf32_hppa_link_hash_table_create (abfd) #endif ret->first_init_sec = 0; ret->first_fini_sec = 0; - ret->offset = NULL; ret->sgot = NULL; ret->srelgot = NULL; ret->splt = NULL; @@ -498,7 +518,7 @@ hppa_stub_name (input_section, sym_sec, hash, rel) const Elf_Internal_Rela *rel; { char *stub_name; - unsigned int len; + size_t len; if (hash) { @@ -594,9 +614,6 @@ hppa_add_stub (stub_name, section, sec_count, info) struct bfd_link_info *info; { asection *stub_sec; -#if ! LONG_BRANCH_PIC_IN_SHLIB - asection *reloc_sec; -#endif struct elf32_hppa_stub_hash_entry *stub_entry; struct elf32_hppa_link_hash_table *hplink; @@ -615,17 +632,19 @@ hppa_add_stub (stub_name, section, sec_count, info) to be merged. It's more linker work though. */ if (strncmp (section->name, ".init", 5) == 0) { - stub_sec = hplink->stub_section_created[hplink->first_init_sec]; + if (hplink->first_init_sec != 0) + stub_sec = hplink->stub_section_created[hplink->first_init_sec-1]; special_sec = 1; } else if (strncmp (section->name, ".fini", 5) == 0) { - stub_sec = hplink->stub_section_created[hplink->first_fini_sec]; + if (hplink->first_fini_sec != 0) + stub_sec = hplink->stub_section_created[hplink->first_fini_sec-1]; special_sec = 2; } if (stub_sec == NULL) { - int len; + size_t len; char *s_name; len = strlen (section->name) + sizeof (STUB_SUFFIX); @@ -642,32 +661,14 @@ hppa_add_stub (stub_name, section, sec_count, info) if (special_sec != 0) { if (special_sec == 1) - hplink->first_init_sec = sec_count; + hplink->first_init_sec = sec_count + 1; else - hplink->first_fini_sec = sec_count; + hplink->first_fini_sec = sec_count + 1; } } hplink->stub_section_created[sec_count] = stub_sec; } -#if ! LONG_BRANCH_PIC_IN_SHLIB - reloc_sec = hplink->reloc_section_created[sec_count]; - if (reloc_sec == NULL && info->shared) - { - char *name; - - name = bfd_malloc (sizeof ".rela" + strlen (stub_sec->name)); - if (name == NULL) - return NULL; - strcpy (name, ".rela"); - strcpy (name + sizeof ".rela" - 1, stub_sec->name); - reloc_sec = bfd_get_section_by_name (elf_hash_table (info)->dynobj, - name); - hplink->reloc_section_created[sec_count] = reloc_sec; - free (name); - } -#endif - /* Enter this entry into the linker stub hash table. */ stub_entry = hppa_stub_hash_lookup (&hplink->stub_hash_table, stub_name, true, false); @@ -681,7 +682,7 @@ hppa_add_stub (stub_name, section, sec_count, info) stub_entry->stub_sec = stub_sec; #if ! LONG_BRANCH_PIC_IN_SHLIB - stub_entry->reloc_sec = reloc_sec; + stub_entry->reloc_sec = hplink->reloc_section_created[sec_count]; #endif stub_entry->stub_offset = 0; stub_entry->input_section = section; @@ -705,17 +706,20 @@ hppa_type_of_stub (input_sec, rel, hash, destination) if (hash != NULL && (((hash->elf.root.type == bfd_link_hash_defined - || hash->elf.root.type == bfd_link_hash_defweak) - && hash->elf.root.u.def.section->output_section == NULL) + || hash->elf.root.type == bfd_link_hash_defweak) + && hash->elf.root.u.def.section->output_section == NULL) + || (hash->elf.root.type == bfd_link_hash_defweak + && hash->elf.dynindx != -1 + && hash->elf.plt.offset != (bfd_vma) -1) || hash->elf.root.type == bfd_link_hash_undefweak || hash->elf.root.type == bfd_link_hash_undefined || hash->pic_call)) { /* If output_section is NULL, then it's a symbol defined in a shared library. We will need an import stub. Decide between - hppa_stub_import and hppa_stub_import_shared later. - For shared links we need stubs for undefined syms too; They - will presumably be resolved by the dynamic linker. */ + hppa_stub_import and hppa_stub_import_shared later. For + shared links we need stubs for undefined or weak syms too; + They will presumably be resolved by the dynamic linker. */ return hppa_stub_import; } @@ -739,14 +743,14 @@ hppa_type_of_stub (input_sec, rel, hash, destination) { max_branch_offset = (1 << (12-1)) << 2; } - else /* R_PARISC_PCREL22F */ + else /* R_PARISC_PCREL22F */ { max_branch_offset = (1 << (22-1)) << 2; } if (branch_offset + max_branch_offset >= 2*max_branch_offset) { -#if 0 +#if LONG_BRANCH_VIA_PLT if (hash != NULL && hash->elf.dynindx != -1 && hash->elf.plt.offset != (bfd_vma) -1) @@ -814,7 +818,8 @@ hppa_build_one_stub (gen_entry, in_arg) bfd *stub_bfd; bfd_byte *loc; bfd_vma sym_value; - unsigned int insn; + bfd_vma insn; + int val; int size; /* Massage our args to the form they really have. */ @@ -825,7 +830,7 @@ hppa_build_one_stub (gen_entry, in_arg) stub_sec = stub_entry->stub_sec; /* Make a note of the offset within the stubs for this entry. */ - stub_entry->stub_offset = hplink->offset[stub_sec->index]; + stub_entry->stub_offset = stub_sec->_raw_size; loc = stub_sec->contents + stub_entry->stub_offset; stub_bfd = stub_sec->owner; @@ -841,14 +846,12 @@ hppa_build_one_stub (gen_entry, in_arg) + stub_entry->target_section->output_offset + stub_entry->target_section->output_section->vma); - insn = hppa_rebuild_insn ((int) LDIL_R1, - hppa_field_adjust (sym_value, 0, e_lrsel), - 21); + val = hppa_field_adjust (sym_value, (bfd_signed_vma) 0, e_lrsel); + insn = hppa_rebuild_insn ((int) LDIL_R1, val, 21); bfd_put_32 (stub_bfd, insn, loc); - insn = hppa_rebuild_insn ((int) BE_SR4_R1, - hppa_field_adjust (sym_value, 0, e_rrsel) >> 2, - 17); + val = hppa_field_adjust (sym_value, (bfd_signed_vma) 0, e_rrsel) >> 2; + insn = hppa_rebuild_insn ((int) BE_SR4_R1, val, 17); bfd_put_32 (stub_bfd, insn, loc + 4); #if ! LONG_BRANCH_PIC_IN_SHLIB @@ -910,15 +913,13 @@ hppa_build_one_stub (gen_entry, in_arg) + stub_sec->output_offset + stub_sec->output_section->vma); - bfd_put_32 (stub_bfd, (unsigned int) BL_R1, loc); - insn = hppa_rebuild_insn ((int) ADDIL_R1, - hppa_field_adjust (sym_value, -8, e_lsel), - 21); + bfd_put_32 (stub_bfd, (bfd_vma) BL_R1, loc); + val = hppa_field_adjust (sym_value, (bfd_signed_vma) -8, e_lsel); + insn = hppa_rebuild_insn ((int) ADDIL_R1, val, 21); bfd_put_32 (stub_bfd, insn, loc + 4); - insn = hppa_rebuild_insn ((int) BE_SR4_R1, - hppa_field_adjust (sym_value, -8, e_rsel) >> 2, - 17); + val = hppa_field_adjust (sym_value, (bfd_signed_vma) -8, e_rsel) >> 2; + insn = hppa_rebuild_insn ((int) BE_SR4_R1, val, 17); bfd_put_32 (stub_bfd, insn, loc + 8); size = 12; break; @@ -935,36 +936,32 @@ hppa_build_one_stub (gen_entry, in_arg) if (stub_entry->stub_type == hppa_stub_import_shared) insn = ADDIL_R19; #endif - insn = hppa_rebuild_insn ((int) insn, - hppa_field_adjust (sym_value, 0, e_lsel), - 21); + val = hppa_field_adjust (sym_value, (bfd_signed_vma) 0, e_lsel), + insn = hppa_rebuild_insn ((int) insn, val, 21); bfd_put_32 (stub_bfd, insn, loc); - insn = hppa_rebuild_insn ((int) LDW_R1_R21, - hppa_field_adjust (sym_value, 0, e_rsel), - 14); + val = hppa_field_adjust (sym_value, (bfd_signed_vma) 0, e_rsel); + insn = hppa_rebuild_insn ((int) LDW_R1_R21, val, 14); bfd_put_32 (stub_bfd, insn, loc + 4); if (hplink->multi_subspace) { - insn = hppa_rebuild_insn ((int) LDW_R1_DLT, - hppa_field_adjust (sym_value, 4, e_rsel), - 14); + val = hppa_field_adjust (sym_value, (bfd_signed_vma) 4, e_rsel); + insn = hppa_rebuild_insn ((int) LDW_R1_DLT, val, 14); bfd_put_32 (stub_bfd, insn, loc + 8); - bfd_put_32 (stub_bfd, (unsigned int) LDSID_R21_R1, loc + 12); - bfd_put_32 (stub_bfd, (unsigned int) MTSP_R1, loc + 16); - bfd_put_32 (stub_bfd, (unsigned int) BE_SR0_R21, loc + 20); - bfd_put_32 (stub_bfd, (unsigned int) STW_RP, loc + 24); + bfd_put_32 (stub_bfd, (bfd_vma) LDSID_R21_R1, loc + 12); + bfd_put_32 (stub_bfd, (bfd_vma) MTSP_R1, loc + 16); + bfd_put_32 (stub_bfd, (bfd_vma) BE_SR0_R21, loc + 20); + bfd_put_32 (stub_bfd, (bfd_vma) STW_RP, loc + 24); size = 28; } else { - bfd_put_32 (stub_bfd, (unsigned int) BV_R0_R21, loc + 8); - insn = hppa_rebuild_insn ((int) LDW_R1_DLT, - hppa_field_adjust (sym_value, 4, e_rsel), - 14); + bfd_put_32 (stub_bfd, (bfd_vma) BV_R0_R21, loc + 8); + val = hppa_field_adjust (sym_value, (bfd_signed_vma) 4, e_rsel); + insn = hppa_rebuild_insn ((int) LDW_R1_DLT, val, 14); bfd_put_32 (stub_bfd, insn, loc + 12); size = 16; @@ -980,7 +977,7 @@ hppa_build_one_stub (gen_entry, in_arg) struct elf32_hppa_link_hash_entry *eh; bfd_vma value; - dynobj = elf_hash_table (info)->dynobj; + dynobj = hplink->root.dynobj; eh = (struct elf32_hppa_link_hash_entry *) stub_entry->h; BFD_ASSERT (eh->elf.root.type == bfd_link_hash_defined @@ -993,7 +990,8 @@ hppa_build_one_stub (gen_entry, in_arg) /* Fill in the entry in the procedure linkage table. The format of a plt entry is - <funcaddr> <__gp>. */ + <funcaddr> + <__gp>. */ bfd_put_32 (hplink->splt->owner, value, hplink->splt->contents + eh->elf.plt.offset); @@ -1026,20 +1024,19 @@ hppa_build_one_stub (gen_entry, in_arg) return false; } - insn = hppa_rebuild_insn ((int) BL_RP, - hppa_field_adjust (sym_value, -8, e_fsel) >> 2, - 17); + val = hppa_field_adjust (sym_value, (bfd_signed_vma) -8, e_fsel) >> 2; + insn = hppa_rebuild_insn ((int) BL_RP, val, 17); bfd_put_32 (stub_bfd, insn, loc); - bfd_put_32 (stub_bfd, (unsigned int) NOP, loc + 4); - bfd_put_32 (stub_bfd, (unsigned int) LDW_RP, loc + 8); - bfd_put_32 (stub_bfd, (unsigned int) LDSID_RP_R1, loc + 12); - bfd_put_32 (stub_bfd, (unsigned int) MTSP_R1, loc + 16); - bfd_put_32 (stub_bfd, (unsigned int) BE_SR0_RP, loc + 20); + bfd_put_32 (stub_bfd, (bfd_vma) NOP, loc + 4); + bfd_put_32 (stub_bfd, (bfd_vma) LDW_RP, loc + 8); + bfd_put_32 (stub_bfd, (bfd_vma) LDSID_RP_R1, loc + 12); + bfd_put_32 (stub_bfd, (bfd_vma) MTSP_R1, loc + 16); + bfd_put_32 (stub_bfd, (bfd_vma) BE_SR0_RP, loc + 20); /* Point the function symbol at the stub. */ stub_entry->h->elf.root.u.def.section = stub_sec; - stub_entry->h->elf.root.u.def.value = hplink->offset[stub_sec->index]; + stub_entry->h->elf.root.u.def.value = stub_sec->_raw_size; size = 24; break; @@ -1049,7 +1046,7 @@ hppa_build_one_stub (gen_entry, in_arg) return false; } - hplink->offset[stub_sec->index] += size; + stub_sec->_raw_size += size; return true; } @@ -1093,12 +1090,18 @@ hppa_size_one_stub (gen_entry, in_arg) hplink = (struct elf32_hppa_link_hash_table *) in_arg; if (stub_entry->stub_type == hppa_stub_long_branch) - size = 8; + { +#if ! LONG_BRANCH_PIC_IN_SHLIB + if (stub_entry->reloc_sec != NULL) + stub_entry->reloc_sec->_raw_size += sizeof (Elf32_External_Rela); +#endif + size = 8; + } else if (stub_entry->stub_type == hppa_stub_long_branch_shared) size = 12; else if (stub_entry->stub_type == hppa_stub_export) size = 24; - else /* hppa_stub_import or hppa_stub_import_shared */ + else /* hppa_stub_import or hppa_stub_import_shared. */ { if (hplink->multi_subspace) size = 28; @@ -1106,7 +1109,7 @@ hppa_size_one_stub (gen_entry, in_arg) size = 16; } - hplink->offset[stub_entry->stub_sec->index] += size; + stub_entry->stub_sec->_raw_size += size; return true; } @@ -1230,7 +1233,7 @@ elf32_hppa_check_relocs (abfd, info, sec, relocs) return true; hplink = hppa_link_hash_table (info); - dynobj = elf_hash_table (info)->dynobj; + dynobj = hplink->root.dynobj; symtab_hdr = &elf_tdata (abfd)->symtab_hdr; sym_hashes = elf_sym_hashes (abfd); local_got_refcounts = elf_local_got_refcounts (abfd); @@ -1245,10 +1248,11 @@ elf32_hppa_check_relocs (abfd, info, sec, relocs) NEED_PLT = 2, NEED_DYNREL = 4, #if LONG_BRANCH_PIC_IN_SHLIB - NEED_STUBREL = 0 /* We won't be needing them in this case. */ + NEED_STUBREL = 0, /* We won't be needing them in this case. */ #else - NEED_STUBREL = 8 + NEED_STUBREL = 8, #endif + PLT_PLABEL = 16 }; unsigned int r_symndx, r_type; @@ -1280,21 +1284,15 @@ elf32_hppa_check_relocs (abfd, info, sec, relocs) case R_PARISC_PLABEL14R: /* "Official" procedure labels. */ case R_PARISC_PLABEL21L: case R_PARISC_PLABEL32: - if (h == NULL) - { - /* If this is a local symbol we do not need to create a - PLT entry, but if we are creating a shared object we - have to output a relocation for the PLABEL itself. */ - need_entry = NEED_DYNREL; - } - else - { - /* If it is a global symbol, then we do need to create a - PLT entry, and additionally, if we are creating a - shared object, we need to output a dynamic relocation - pointing to that PLT entry. */ - need_entry = NEED_PLT | NEED_DYNREL; - } + /* If the addend is non-zero, we break badly. */ + BFD_ASSERT (rel->r_addend == 0); + + /* If we are creating a shared library, then we need to + create a PLT entry for all PLABELs, because PLABELs with + local symbols may be passed via a pointer to another + object. Additionally, output a dynamic relocation + pointing to the PLT entry. */ + need_entry = PLT_PLABEL | NEED_PLT | NEED_DYNREL; break; case R_PARISC_PCREL12F: @@ -1396,7 +1394,7 @@ elf32_hppa_check_relocs (abfd, info, sec, relocs) /* Allocate space for a GOT entry, as well as a dynamic relocation for this entry. */ if (dynobj == NULL) - elf_hash_table (info)->dynobj = dynobj = abfd; + hplink->root.dynobj = dynobj = abfd; if (hplink->sgot == NULL) { @@ -1431,7 +1429,11 @@ elf32_hppa_check_relocs (abfd, info, sec, relocs) { size_t size; - size = symtab_hdr->sh_info * sizeof (bfd_signed_vma); + /* Allocate space for local got offsets and local + plt offsets. Done this way to save polluting + elf_obj_tdata with another target specific + pointer. */ + size = symtab_hdr->sh_info * 2 * sizeof (bfd_signed_vma); local_got_refcounts = ((bfd_signed_vma *) bfd_alloc (abfd, size)); if (local_got_refcounts == NULL) @@ -1471,13 +1473,47 @@ elf32_hppa_check_relocs (abfd, info, sec, relocs) clean up later in adjust_dynamic_symbol. */ if ((sec->flags & SEC_ALLOC) != 0) { - if (h->elf.plt.refcount == -1) + if (h != NULL) { - h->elf.plt.refcount = 1; - h->elf.elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT; + if (h->elf.plt.refcount == -1) + { + h->elf.plt.refcount = 1; + h->elf.elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT; + } + else + h->elf.plt.refcount += 1; + + /* If this .plt entry is for a plabel, we need an + extra word for ld.so. adjust_dynamic_symbol will + also keep the entry even if it appears to be + local. */ + if (need_entry & PLT_PLABEL) + h->plabel = 1; + } + else if (need_entry & PLT_PLABEL) + { + int indx; + + if (local_got_refcounts == NULL) + { + size_t size; + + /* Allocate space for local got offsets and local + plt offsets. */ + size = symtab_hdr->sh_info * 2 * sizeof (bfd_signed_vma); + local_got_refcounts = ((bfd_signed_vma *) + bfd_alloc (abfd, size)); + if (local_got_refcounts == NULL) + return false; + elf_local_got_refcounts (abfd) = local_got_refcounts; + memset (local_got_refcounts, -1, size); + } + indx = r_symndx + symtab_hdr->sh_info; + if (local_got_refcounts[indx] == -1) + local_got_refcounts[indx] = 1; + else + local_got_refcounts[indx] += 1; } - else - h->elf.plt.refcount += 1; } } @@ -1538,7 +1574,7 @@ elf32_hppa_check_relocs (abfd, info, sec, relocs) char *name; if (dynobj == NULL) - elf_hash_table (info)->dynobj = dynobj = abfd; + hplink->root.dynobj = dynobj = abfd; name = bfd_elf_string_from_elf_section (abfd, @@ -1555,7 +1591,7 @@ elf32_hppa_check_relocs (abfd, info, sec, relocs) if ((need_entry & NEED_STUBREL)) { - int len = strlen (name) + sizeof (STUB_SUFFIX); + size_t len = strlen (name) + sizeof (STUB_SUFFIX); char *newname = bfd_malloc (len); if (newname == NULL) @@ -1719,9 +1755,11 @@ elf32_hppa_gc_sweep_hook (abfd, info, sec, relocs) Elf_Internal_Shdr *symtab_hdr; struct elf_link_hash_entry **sym_hashes; bfd_signed_vma *local_got_refcounts; + bfd_signed_vma *local_plt_refcounts; const Elf_Internal_Rela *rel, *relend; unsigned long r_symndx; struct elf_link_hash_entry *h; + struct elf32_hppa_link_hash_table *hplink; bfd *dynobj; asection *sgot; asection *srelgot; @@ -1729,13 +1767,16 @@ elf32_hppa_gc_sweep_hook (abfd, info, sec, relocs) symtab_hdr = &elf_tdata (abfd)->symtab_hdr; sym_hashes = elf_sym_hashes (abfd); local_got_refcounts = elf_local_got_refcounts (abfd); - - dynobj = elf_hash_table (info)->dynobj; + local_plt_refcounts = local_got_refcounts; + if (local_plt_refcounts != NULL) + local_plt_refcounts += symtab_hdr->sh_info; + hplink = hppa_link_hash_table (info); + dynobj = hplink->root.dynobj; if (dynobj == NULL) return true; - sgot = hppa_link_hash_table (info)->sgot; - srelgot = hppa_link_hash_table (info)->srelgot; + sgot = hplink->sgot; + srelgot = hplink->srelgot; relend = relocs + sec->reloc_count; for (rel = relocs; rel < relend; rel++) @@ -1753,7 +1794,7 @@ elf32_hppa_gc_sweep_hook (abfd, info, sec, relocs) h->got.refcount -= 1; if (h->got.refcount == 0) { - sgot->_raw_size -= 4; + sgot->_raw_size -= GOT_ENTRY_SIZE; srelgot->_raw_size -= sizeof (Elf32_External_Rela); } } @@ -1765,7 +1806,7 @@ elf32_hppa_gc_sweep_hook (abfd, info, sec, relocs) local_got_refcounts[r_symndx] -= 1; if (local_got_refcounts[r_symndx] == 0) { - sgot->_raw_size -= 4; + sgot->_raw_size -= GOT_ENTRY_SIZE; if (info->shared) srelgot->_raw_size -= sizeof (Elf32_External_Rela); } @@ -1773,9 +1814,6 @@ elf32_hppa_gc_sweep_hook (abfd, info, sec, relocs) } break; - case R_PARISC_PLABEL14R: - case R_PARISC_PLABEL21L: - case R_PARISC_PLABEL32: case R_PARISC_PCREL12F: case R_PARISC_PCREL17C: case R_PARISC_PCREL17F: @@ -1789,6 +1827,23 @@ elf32_hppa_gc_sweep_hook (abfd, info, sec, relocs) } break; + case R_PARISC_PLABEL14R: + case R_PARISC_PLABEL21L: + case R_PARISC_PLABEL32: + r_symndx = ELF32_R_SYM (rel->r_info); + if (r_symndx >= symtab_hdr->sh_info) + { + h = sym_hashes[r_symndx - symtab_hdr->sh_info]; + if (h->plt.refcount > 0) + h->plt.refcount -= 1; + } + else if (local_plt_refcounts != NULL) + { + if (local_plt_refcounts[r_symndx] > 0) + local_plt_refcounts[r_symndx] -= 1; + } + break; + default: break; } @@ -1797,6 +1852,23 @@ elf32_hppa_gc_sweep_hook (abfd, info, sec, relocs) } +/* Our own version of hide_symbol, so that we can keep plt entries for + plabels. */ + +static void +elf32_hppa_hide_symbol (info, h) + struct bfd_link_info *info ATTRIBUTE_UNUSED; + struct elf_link_hash_entry *h; +{ + h->dynindx = -1; + if (! ((struct elf32_hppa_link_hash_entry *) h)->plabel) + { + h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT; + h->plt.offset = (bfd_vma) -1; + } +} + + /* Adjust a symbol defined by a dynamic object and referenced by a regular object. The current definition is in some section of the dynamic object, but we're not including those sections. We have to @@ -1812,8 +1884,8 @@ elf32_hppa_adjust_dynamic_symbol (info, h) struct elf32_hppa_link_hash_table *hplink; asection *s; - dynobj = elf_hash_table (info)->dynobj; hplink = hppa_link_hash_table (info); + dynobj = hplink->root.dynobj; /* If this is a function, put it in the procedure linkage table. We will fill in the contents of the procedure linkage table later, @@ -1824,17 +1896,19 @@ elf32_hppa_adjust_dynamic_symbol (info, h) 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. 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. */ + 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 (!info->shared && h->plt.refcount > 0 && (h->root.type == bfd_link_hash_defined @@ -1854,12 +1928,21 @@ elf32_hppa_adjust_dynamic_symbol (info, h) /* Make an entry in the .plt section. */ s = hplink->splt; h->plt.offset = s->_raw_size; - s->_raw_size += PLT_ENTRY_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) + 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; @@ -1977,11 +2060,12 @@ hppa_handle_PIC_calls (h, inf) return true; } + h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT; ((struct elf32_hppa_link_hash_entry *) h)->pic_call = 1; info = (struct bfd_link_info *) inf; - dynobj = elf_hash_table (info)->dynobj; hplink = hppa_link_hash_table (info); + dynobj = hplink->root.dynobj; /* Make an entry in the .plt section. */ s = hplink->splt; @@ -1992,7 +2076,8 @@ hppa_handle_PIC_calls (h, inf) } -#if ! LONG_BRANCH_PIC_IN_SHLIB || RELATIVE_DYNAMIC_RELOCS +#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. */ @@ -2008,7 +2093,7 @@ hppa_discard_copies (h, inf) eh = (struct elf32_hppa_link_hash_entry *) h; info = (struct bfd_link_info *) inf; -#if ! LONG_BRANCH_PIC_IN_SHLIB +#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 @@ -2023,10 +2108,10 @@ hppa_discard_copies (h, inf) } #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 RELATIVE_DYNAMIC_RELOCS if (eh->elf.dynindx == -1 || ((eh->elf.elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0 && eh->elf.root.type != bfd_link_hash_defweak @@ -2056,11 +2141,14 @@ elf32_hppa_size_dynamic_sections (output_bfd, info) boolean reltext; hplink = hppa_link_hash_table (info); - dynobj = elf_hash_table (info)->dynobj; + dynobj = hplink->root.dynobj; BFD_ASSERT (dynobj != NULL); - if (elf_hash_table (info)->dynamic_sections_created) + if (hplink->root.dynamic_sections_created) { + const char *funcname; + bfd *i; + /* Set the contents of the .interp section to the interpreter. */ if (! info->shared) { @@ -2069,6 +2157,86 @@ elf32_hppa_size_dynamic_sections (output_bfd, info) s->_raw_size = sizeof ELF_DYNAMIC_INTERPRETER; s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; } + + /* DT_INIT and DT_FINI need a .plt entry. Make sure they have + one. */ + funcname = info->init_function; + while (1) + { + if (funcname != NULL) + { + struct elf_link_hash_entry *h; + + h = elf_link_hash_lookup (&hplink->root, + funcname, + false, false, false); + if (h != NULL + && (h->elf_link_hash_flags & (ELF_LINK_HASH_REF_REGULAR + | ELF_LINK_HASH_DEF_REGULAR))) + { + if (h->plt.refcount <= 0) + { + h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT; + + /* Make an entry in the .plt section. We know + the function doesn't have a plabel by the + refcount */ + s = hplink->splt; + h->plt.offset = s->_raw_size; + s->_raw_size += PLT_ENTRY_SIZE; + + /* Make sure this symbol is output as a dynamic + symbol. */ + if (h->dynindx == -1) + { + if (! bfd_elf32_link_record_dynamic_symbol (info, h)) + return false; + } + + /* Make an entry for the reloc too. */ + s = hplink->srelplt; + s->_raw_size += sizeof (Elf32_External_Rela); + } + + ((struct elf32_hppa_link_hash_entry *) h)->plt_abs = 1; + } + } + if (funcname == info->fini_function) + break; + funcname = info->fini_function; + } + + /* 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 { @@ -2088,7 +2256,8 @@ elf32_hppa_size_dynamic_sections (output_bfd, info) hplink->srelgot->_raw_size = 0; } -#if ! LONG_BRANCH_PIC_IN_SHLIB || RELATIVE_DYNAMIC_RELOCS +#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 @@ -2180,7 +2349,7 @@ elf32_hppa_size_dynamic_sections (output_bfd, info) return false; } - if (elf_hash_table (info)->dynamic_sections_created) + 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 @@ -2408,8 +2577,31 @@ elf32_hppa_size_stubs (stub_bfd, multi_subspace, info, } } } - sec_count += input_bfd->section_count; } +#if LONG_BRANCH_PIC_IN_SHLIB + sec_count += input_bfd->section_count; +#else + if (! info->shared) + sec_count += input_bfd->section_count; + else + for (section = input_bfd->sections; + section != NULL; + section = section->next, sec_count++) + { + 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->reloc_section_created[sec_count] = reloc_sec; + free (name); + } +#endif } while (1) @@ -2635,26 +2827,29 @@ elf32_hppa_size_stubs (stub_bfd, multi_subspace, info, /* OK, we've added some stubs. Find out the new size of the stub sections. */ - hplink->offset = (bfd_vma *) - bfd_realloc (hplink->offset, - hplink->stub_bfd->section_count * sizeof (bfd_vma)); - if (hplink->offset == NULL) - goto error_ret_free_local; - - memset (hplink->offset, 0, - hplink->stub_bfd->section_count * sizeof (bfd_vma)); - - bfd_hash_traverse (&hplink->stub_hash_table, - hppa_size_one_stub, - hplink); - for (stub_sec = hplink->stub_bfd->sections; stub_sec != NULL; stub_sec = stub_sec->next) { - bfd_set_section_size (hplink->stub_bfd, stub_sec, - hplink->offset[stub_sec->index]); + stub_sec->_raw_size = 0; + stub_sec->_cooked_size = 0; + } +#if ! LONG_BRANCH_PIC_IN_SHLIB + for (i = 0; i < sec_count; i++) + { + stub_sec = hplink->reloc_section_created[i]; + 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; @@ -2695,11 +2890,13 @@ 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; - h = elf_link_hash_lookup (elf_hash_table (info), "$global$", + 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) @@ -2709,28 +2906,48 @@ elf32_hppa_set_gp (abfd, info) } else { - /* If $global$ isn't defined, we make one up ourselves - from the start of .data, .plt, or .got. */ - struct elf32_hppa_link_hash_table *hplink; - - hplink = hppa_link_hash_table (info); - gp_val = 0; - sec = bfd_get_section_by_name (abfd, ".data"); - if (sec == NULL) - sec = hplink->splt; - if (sec == NULL) - sec = hplink->sgot; - if (sec == NULL) + /* 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) { - (*info->callbacks->undefined_symbol) - (info, "$global$", abfd, NULL, 0, true); - return false; + 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"); + } } } - elf_gp (abfd) = (gp_val - + sec->output_section->vma - + sec->output_offset); + if (sec != NULL) + gp_val += sec->output_section->vma + sec->output_offset; + + elf_gp (abfd) = gp_val; return true; } @@ -2755,20 +2972,18 @@ elf32_hppa_build_stubs (info) stub_sec != NULL; stub_sec = stub_sec->next) { - unsigned int size; + size_t size; /* Allocate memory to hold the linker stubs. */ - size = bfd_section_size (hplink->stub_bfd, stub_sec); + 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. */ - memset (hplink->offset, 0, - hplink->stub_bfd->section_count * sizeof (bfd_vma)); - table = &hplink->stub_hash_table; bfd_hash_traverse (table, hppa_build_one_stub, info); @@ -2819,10 +3034,16 @@ final_link_relocate (input_section, contents, rel, value, info, sym_sec, h) 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, then find the import stub in the stub hash. */ + 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->pic_call)) + || (h != NULL && + (h->pic_call + || (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, info); @@ -2874,7 +3095,7 @@ final_link_relocate (input_section, contents, rel, value, info, sym_sec, h) == (((int) OP_ADDIL << 26) | (27 << 21))) { insn &= ~ (0x1f << 21); -#if 1 /* debug them */ +#if 1 /* debug them. */ (*_bfd_error_handler) (_("%s(%s+0x%lx): fixing %s"), bfd_get_filename (input_bfd), @@ -2887,7 +3108,7 @@ final_link_relocate (input_section, contents, rel, value, info, sym_sec, h) break; } - /* Fall thru */ + /* Fall thru. */ case R_PARISC_DLTIND21L: case R_PARISC_DLTIND14R: @@ -3017,7 +3238,7 @@ final_link_relocate (input_section, contents, rel, value, info, sym_sec, h) insn = hppa_rebuild_insn (insn, val, r_format); /* Update the instruction word. */ - bfd_put_32 (input_bfd, (unsigned int) insn, hit_data); + bfd_put_32 (input_bfd, (bfd_vma) insn, hit_data); return bfd_reloc_ok; } @@ -3046,9 +3267,9 @@ elf32_hppa_relocate_section (output_bfd, info, input_bfd, input_section, symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - dynobj = elf_hash_table (info)->dynobj; - local_got_offsets = elf_local_got_offsets (input_bfd); hplink = hppa_link_hash_table (info); + dynobj = hplink->root.dynobj; + local_got_offsets = elf_local_got_offsets (input_bfd); sreloc = NULL; rel = relocs; @@ -3064,7 +3285,7 @@ elf32_hppa_relocate_section (output_bfd, info, input_bfd, input_section, bfd_vma relocation; bfd_reloc_status_type r; const char *sym_name; - boolean pltrel; + boolean plabel; r_type = ELF32_R_TYPE (rel->r_info); if (r_type >= (unsigned int) R_PARISC_UNIMPLEMENTED) @@ -3157,7 +3378,7 @@ elf32_hppa_relocate_section (output_bfd, info, input_bfd, input_section, /* Do any required modifications to the relocation value, and determine what types of dynamic info we need to output, if any. */ - pltrel = 0; + plabel = 0; switch (r_type) { case R_PARISC_DLTIND14F: @@ -3172,7 +3393,7 @@ elf32_hppa_relocate_section (output_bfd, info, input_bfd, input_section, off = h->elf.got.offset; BFD_ASSERT (off != (bfd_vma) -1); - if (! elf_hash_table (info)->dynamic_sections_created + if (! hplink->root.dynamic_sections_created || (info->shared && (info->symbolic || h->elf.dynindx == -1) && (h->elf.elf_link_hash_flags @@ -3224,7 +3445,7 @@ elf32_hppa_relocate_section (output_bfd, info, input_bfd, input_section, if (info->shared) { - /* Output a dynamic SEGREL32 relocation for this + /* 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. */ @@ -3234,7 +3455,7 @@ elf32_hppa_relocate_section (output_bfd, info, input_bfd, input_section, outrel.r_offset = (off + hplink->sgot->output_offset + hplink->sgot->output_section->vma); - outrel.r_info = ELF32_R_INFO (0, R_PARISC_SEGREL32); + 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 *) @@ -3257,22 +3478,78 @@ elf32_hppa_relocate_section (output_bfd, info, input_bfd, input_section, case R_PARISC_PLABEL14R: case R_PARISC_PLABEL21L: case R_PARISC_PLABEL32: - /* If we have a global symbol with a PLT slot, then redirect - this relocation to it. */ - if (h != NULL - && h->elf.dynindx != -1 - && h->elf.plt.offset != (bfd_vma) -1) + if (hplink->root.dynamic_sections_created) { - /* PLABELs contain function pointers. Relocation is - to the entry for the function in the .plt. The - magic +2 offset signals to $$dyncall that the - function pointer is in the .plt and thus has a gp - pointer too. */ - relocation = (h->elf.plt.offset - + hplink->splt->output_offset - + hplink->splt->output_section->vma - + 2); - pltrel = 1; + bfd_vma off; + + /* If we have a global symbol with a PLT slot, then + redirect this relocation to it. */ + if (h != NULL) + { + off = h->elf.plt.offset; + } + else + { + int indx; + + indx = r_symndx + symtab_hdr->sh_info; + off = local_got_offsets[indx]; + + /* As for the local .got entry case, we use the last + bit to record whether we've already initialised + this local .plt entry. */ + if ((off & 1) != 0) + off &= ~1; + else + { + bfd_put_32 (output_bfd, + relocation, + hplink->splt->contents + off); + bfd_put_32 (output_bfd, + elf_gp (hplink->splt->output_section->owner), + hplink->splt->contents + off + 4); + + if (info->shared) + { + /* Output a dynamic IPLT relocation for this + PLT entry. */ + Elf_Internal_Rela outrel; + asection *srelplt = hplink->srelplt; + + outrel.r_offset = (off + + hplink->splt->output_offset + + hplink->splt->output_section->vma); + outrel.r_info = ELF32_R_INFO (0, R_PARISC_IPLT); + outrel.r_addend = relocation; + bfd_elf32_swap_reloca_out (output_bfd, &outrel, + ((Elf32_External_Rela *) + srelplt->contents + + srelplt->reloc_count)); + ++srelplt->reloc_count; + } + + local_got_offsets[indx] |= 1; + } + } + + BFD_ASSERT (off < (bfd_vma) -2); + + /* PLABELs contain function pointers. Relocation is to + the entry for the function in the .plt. The magic +2 + offset signals to $$dyncall that the function pointer + is in the .plt and thus has a gp pointer too. + Exception: Undefined PLABELs should have a value of + zero. */ + if (h == NULL + || (h->elf.root.type != bfd_link_hash_undefweak + && h->elf.root.type != bfd_link_hash_undefined)) + { + relocation = (off + + hplink->splt->output_offset + + hplink->splt->output_section->vma + + 2); + } + plabel = 1; } /* Fall through and possibly emit a dynamic relocation. */ @@ -3332,7 +3609,7 @@ elf32_hppa_relocate_section (output_bfd, info, input_bfd, input_section, bfd_vma off; off = (_bfd_stab_section_offset - (output_bfd, &elf_hash_table (info)->stab_info, + (output_bfd, &hplink->root.stab_info, input_section, &elf_section_data (input_section)->stab_info, rel->r_offset)); @@ -3348,9 +3625,10 @@ elf32_hppa_relocate_section (output_bfd, info, input_bfd, input_section, { memset (&outrel, 0, sizeof (outrel)); } - else if (!pltrel - && h != NULL - && ((!info->symbolic && h->elf.dynindx != -1) + else if (h != NULL + && h->elf.dynindx != -1 + && (plabel + || !info->symbolic || (h->elf.elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)) { @@ -3363,7 +3641,14 @@ elf32_hppa_relocate_section (output_bfd, info, input_bfd, input_section, /* Add the absolute offset of the symbol. */ outrel.r_addend += relocation; - if (sym_sec != NULL + /* Global plabels need to be processed by the + dynamic linker so that functions have at most one + fptr. For this reason, we need to differentiate + between global and local plabels, which we do by + providing the function symbol for a global plabel + reloc, and no symbol for local plabels. */ + if (! plabel + && sym_sec != NULL && sym_sec->output_section != NULL && ! bfd_is_abs_section (sym_sec)) { @@ -3448,7 +3733,7 @@ elf32_hppa_finish_dynamic_symbol (output_bfd, info, h, sym) bfd *dynobj; hplink = hppa_link_hash_table (info); - dynobj = elf_hash_table (info)->dynobj; + dynobj = hplink->root.dynobj; /* Millicode symbols should not be put in the dynamic symbol table under any circumstances. */ @@ -3464,7 +3749,12 @@ elf32_hppa_finish_dynamic_symbol (output_bfd, info, h, sym) it up. The format of a plt entry is - <funcaddr> <__gp>. */ + <funcaddr> + <__gp> + <used by ld.so> + + The last field is present only for plt entries that are used + by global plabels. */ /* We do not actually care about the value in the PLT entry if we are creating a shared library and the symbol is still @@ -3480,21 +3770,39 @@ elf32_hppa_finish_dynamic_symbol (output_bfd, info, h, sym) + h->root.u.def.section->output_section->vma); } - bfd_put_32 (hplink->splt->owner, value, + bfd_put_32 (hplink->splt->owner, + value, hplink->splt->contents + h->plt.offset); - value = elf_gp (hplink->splt->output_section->owner); - bfd_put_32 (hplink->splt->owner, value, + bfd_put_32 (hplink->splt->owner, + elf_gp (hplink->splt->output_section->owner), hplink->splt->contents + h->plt.offset + 4); - - if (! ((struct elf32_hppa_link_hash_entry *) h)->pic_call + if (PLABEL_PLT_ENTRY_SIZE != PLT_ENTRY_SIZE + && ((struct elf32_hppa_link_hash_entry *) h)->plabel && h->dynindx != -1) { + memset (hplink->splt->contents + h->plt.offset + 8, + 0, PLABEL_PLT_ENTRY_SIZE - PLT_ENTRY_SIZE); + } + + if (! ((struct elf32_hppa_link_hash_entry *) h)->pic_call) + { /* Create a dynamic IPLT relocation for this entry. */ rel.r_offset = (h->plt.offset + hplink->splt->output_offset + hplink->splt->output_section->vma); - rel.r_info = ELF32_R_INFO (h->dynindx, R_PARISC_IPLT); - rel.r_addend = 0; + if (! ((struct elf32_hppa_link_hash_entry *) h)->plt_abs + && h->dynindx != -1) + { + rel.r_info = ELF32_R_INFO (h->dynindx, R_PARISC_IPLT); + rel.r_addend = 0; + } + else + { + /* This symbol has been marked to become local, and is + used by a plabel so must be kept in the .plt. */ + rel.r_info = ELF32_R_INFO (0, R_PARISC_IPLT); + rel.r_addend = value; + } bfd_elf32_swap_reloca_out (hplink->splt->output_section->owner, &rel, @@ -3528,12 +3836,12 @@ elf32_hppa_finish_dynamic_symbol (output_bfd, info, h, sym) of a version file, we just want to emit a RELATIVE reloc. The entry in the global offset table will already have been initialized in the relocate_section function. */ - if (! elf_hash_table (info)->dynamic_sections_created + if (! hplink->root.dynamic_sections_created || (info->shared && (info->symbolic || h->dynindx == -1) && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR))) { - rel.r_info = ELF32_R_INFO (0, R_PARISC_SEGREL32); + rel.r_info = ELF32_R_INFO (0, R_PARISC_DIR32); rel.r_addend = (h->root.u.def.value + h->root.u.def.section->output_offset + h->root.u.def.section->output_section->vma); @@ -3601,12 +3909,12 @@ elf32_hppa_finish_dynamic_sections (output_bfd, info) struct elf32_hppa_link_hash_table *hplink; asection *sdyn; - dynobj = elf_hash_table (info)->dynobj; hplink = hppa_link_hash_table (info); + dynobj = hplink->root.dynobj; sdyn = bfd_get_section_by_name (dynobj, ".dynamic"); - if (elf_hash_table (info)->dynamic_sections_created) + if (hplink->root.dynamic_sections_created) { Elf32_External_Dyn *dyncon, *dynconend; @@ -3646,27 +3954,57 @@ elf32_hppa_finish_dynamic_sections (output_bfd, info) dyn.d_un.d_val = s->_raw_size; bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); break; + + case DT_INIT: + case DT_FINI: + { + struct elf_link_hash_entry *h; + const char *funcname; + + if (dyn.d_tag == DT_INIT) + funcname = info->init_function; + else + funcname = info->fini_function; + + h = elf_link_hash_lookup (&hplink->root, funcname, + false, false, false); + + /* This is a function pointer. The magic +2 offset + signals to $$dyncall that the function pointer + is in the .plt and thus has a gp pointer too. */ + dyn.d_un.d_ptr = (h->plt.offset + + hplink->splt->output_offset + + hplink->splt->output_section->vma + + 2); + bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); + break; + } } } } - /* Fill in the first entry in the global offset table. - We use it to point to our dynamic section, if we have one. */ if (hplink->sgot->_raw_size != 0) { + /* Fill in the first entry in the global offset table. + We use it to point to our dynamic section, if we have one. */ bfd_put_32 (output_bfd, (sdyn != NULL ? sdyn->output_section->vma + sdyn->output_offset : (bfd_vma) 0), hplink->sgot->contents); + /* The second entry is reserved for use by the dynamic linker. */ + bfd_put_32 (output_bfd, (bfd_vma) 0, hplink->sgot->contents + 4); + /* Set .got entry size. */ - elf_section_data (hplink->sgot->output_section)->this_hdr.sh_entsize = 4; + elf_section_data (hplink->sgot->output_section) + ->this_hdr.sh_entsize = GOT_ENTRY_SIZE; } /* Set plt entry size. */ if (hplink->splt->_raw_size != 0) - elf_section_data (hplink->splt->output_section)->this_hdr.sh_entsize = 8; + elf_section_data (hplink->splt->output_section) + ->this_hdr.sh_entsize = PLT_ENTRY_SIZE; return true; } @@ -3701,6 +4039,7 @@ elf32_hppa_elf_get_symbol_type (elf_sym, type) #define elf_backend_create_dynamic_sections elf32_hppa_create_dynamic_sections #define elf_backend_fake_sections elf_hppa_fake_sections #define elf_backend_relocate_section elf32_hppa_relocate_section +#define elf_backend_hide_symbol elf32_hppa_hide_symbol #define elf_backend_finish_dynamic_symbol elf32_hppa_finish_dynamic_symbol #define elf_backend_finish_dynamic_sections elf32_hppa_finish_dynamic_sections #define elf_backend_size_dynamic_sections elf32_hppa_size_dynamic_sections @@ -3715,7 +4054,7 @@ elf32_hppa_elf_get_symbol_type (elf_sym, type) #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 4 +#define elf_backend_got_header_size 8 #define TARGET_BIG_SYM bfd_elf32_hppa_vec #define TARGET_BIG_NAME "elf32-hppa" |