aboutsummaryrefslogtreecommitdiff
path: root/bfd/elf32-hppa.c
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2000-09-27 17:30:19 +0000
committerAlan Modra <amodra@gmail.com>2000-09-27 17:30:19 +0000
commit47d89dba5e87eb8f200e5f1a8a37d71716856a6d (patch)
tree35e27d3ec96747bf2587c7ca2f96f6a70b93c938 /bfd/elf32-hppa.c
parent5506e1a5d86d957f3e71068785509d96d81e46a9 (diff)
downloadgdb-47d89dba5e87eb8f200e5f1a8a37d71716856a6d.zip
gdb-47d89dba5e87eb8f200e5f1a8a37d71716856a6d.tar.gz
gdb-47d89dba5e87eb8f200e5f1a8a37d71716856a6d.tar.bz2
.plt stub for lazy linking, --stub-group-size=N ld switch,
import stub fix, extra DIR14F reloc to fix abort in tc_gen_reloc
Diffstat (limited to 'bfd/elf32-hppa.c')
-rw-r--r--bfd/elf32-hppa.c240
1 files changed, 160 insertions, 80 deletions
diff --git a/bfd/elf32-hppa.c b/bfd/elf32-hppa.c
index 01e2611..0deec5a 100644
--- a/bfd/elf32-hppa.c
+++ b/bfd/elf32-hppa.c
@@ -120,6 +120,18 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#define GOT_ENTRY_SIZE 4
#define ELF_DYNAMIC_INTERPRETER "/lib/ld.so.1"
+static const bfd_byte plt_stub[] =
+{
+ 0x0e, 0x80, 0x10, 0x96, /* 1: ldw 0(%r20),%r22 */
+ 0xea, 0xc0, 0xc0, 0x00, /* bv %r0(%r22) */
+ 0x0e, 0x88, 0x10, 0x95, /* ldw 4(%r20),%r21 */
+#define PLT_STUB_ENTRY (3*4)
+ 0xea, 0x9f, 0x1f, 0xdd, /* b,l 1b,%r20 */
+ 0xd6, 0x80, 0x1c, 0x1e, /* depi 0,31,2,%r20 */
+ 0x00, 0xc0, 0xff, 0xee, /* 9: .word fixup_func */
+ 0xde, 0xad, 0xbe, 0xef /* .word fixup_ltp */
+};
+
/* Section name for stubs is the associated section name plus this
string. */
#define STUB_SUFFIX ".stub"
@@ -240,9 +252,6 @@ struct elf32_hppa_link_hash_table {
/* Linker stub bfd. */
bfd *stub_bfd;
- /* Whether we support multiple sub-spaces for shared libs. */
- boolean multi_subspace;
-
/* Linker call-backs. */
asection * (*add_stub_section) PARAMS ((const char *, asection *));
void (*layout_sections_again) PARAMS ((void));
@@ -268,6 +277,17 @@ struct elf32_hppa_link_hash_table {
asection *srelplt;
asection *sdynbss;
asection *srelbss;
+
+ /* Whether we support multiple sub-spaces for shared libs. */
+ unsigned int multi_subspace:1;
+
+ /* Flags set when PCREL12F and PCREL17F branches detected. Used to
+ select suitable defaults for the stub group size. */
+ unsigned int has_12bit_branch:1;
+ unsigned int has_17bit_branch:1;
+
+ /* Set if we need a .plt stub to support lazy dynamic linking. */
+ unsigned int need_plt_stub:1;
};
@@ -498,7 +518,6 @@ elf32_hppa_link_hash_table_create (abfd)
return NULL;
ret->stub_bfd = NULL;
- ret->multi_subspace = 0;
ret->add_stub_section = NULL;
ret->layout_sections_again = NULL;
ret->stub_group = NULL;
@@ -508,6 +527,10 @@ elf32_hppa_link_hash_table_create (abfd)
ret->srelplt = NULL;
ret->sdynbss = NULL;
ret->srelbss = NULL;
+ ret->multi_subspace = 0;
+ ret->has_12bit_branch = 0;
+ ret->has_17bit_branch = 0;
+ ret->need_plt_stub = 0;
return &ret->root.root;
}
@@ -896,11 +919,11 @@ hppa_build_one_stub (gen_entry, in_arg)
+ stub_sec->output_section->vma);
bfd_put_32 (stub_bfd, (bfd_vma) BL_R1, loc);
- val = hppa_field_adjust (sym_value, (bfd_signed_vma) -8, e_lsel);
+ val = hppa_field_adjust (sym_value, (bfd_signed_vma) -8, e_lrsel);
insn = hppa_rebuild_insn ((int) ADDIL_R1, val, 21);
bfd_put_32 (stub_bfd, insn, loc + 4);
- val = hppa_field_adjust (sym_value, (bfd_signed_vma) -8, e_rsel) >> 2;
+ val = hppa_field_adjust (sym_value, (bfd_signed_vma) -8, e_rrsel) >> 2;
insn = hppa_rebuild_insn ((int) BE_SR4_R1, val, 17);
bfd_put_32 (stub_bfd, insn, loc + 8);
size = 12;
@@ -918,17 +941,22 @@ hppa_build_one_stub (gen_entry, in_arg)
if (stub_entry->stub_type == hppa_stub_import_shared)
insn = ADDIL_R19;
#endif
- val = hppa_field_adjust (sym_value, (bfd_signed_vma) 0, e_lsel),
+ val = hppa_field_adjust (sym_value, (bfd_signed_vma) 0, e_lrsel),
insn = hppa_rebuild_insn ((int) insn, val, 21);
bfd_put_32 (stub_bfd, insn, loc);
- val = hppa_field_adjust (sym_value, (bfd_signed_vma) 0, e_rsel);
+ /* It is critical to use lrsel/rrsel here because we are using
+ two different offsets (+0 and +4) from sym_value. If we use
+ lsel/rsel then with unfortunate sym_values we will round
+ sym_value+4 up to the next 2k block leading to a mis-match
+ between the lsel and rsel value. */
+ val = hppa_field_adjust (sym_value, (bfd_signed_vma) 0, e_rrsel);
insn = hppa_rebuild_insn ((int) LDW_R1_R21, val, 14);
bfd_put_32 (stub_bfd, insn, loc + 4);
if (hplink->multi_subspace)
{
- val = hppa_field_adjust (sym_value, (bfd_signed_vma) 4, e_rsel);
+ val = hppa_field_adjust (sym_value, (bfd_signed_vma) 4, e_rrsel);
insn = hppa_rebuild_insn ((int) LDW_R1_DLT, val, 14);
bfd_put_32 (stub_bfd, insn, loc + 8);
@@ -942,7 +970,7 @@ hppa_build_one_stub (gen_entry, in_arg)
else
{
bfd_put_32 (stub_bfd, (bfd_vma) BV_R0_R21, loc + 8);
- val = hppa_field_adjust (sym_value, (bfd_signed_vma) 4, e_rsel);
+ val = hppa_field_adjust (sym_value, (bfd_signed_vma) 4, e_rrsel);
insn = hppa_rebuild_insn ((int) LDW_R1_DLT, val, 14);
bfd_put_32 (stub_bfd, insn, loc + 12);
@@ -1146,8 +1174,6 @@ elf32_hppa_create_dynamic_sections (abfd, info)
bfd *abfd;
struct bfd_link_info *info;
{
- flagword flags;
- asection *s;
struct elf32_hppa_link_hash_table *hplink;
/* Don't try to create the .plt and .got twice. */
@@ -1159,14 +1185,7 @@ elf32_hppa_create_dynamic_sections (abfd, info)
if (! _bfd_elf_create_dynamic_sections (abfd, info))
return false;
- /* Our .plt just contains pointers. I suppose we should be using
- .plt.got but .plt.got doesn't make too much sense without a .plt
- section. Set the flags to say the .plt isn't executable. */
- s = bfd_get_section_by_name (abfd, ".plt");
- flags = bfd_get_section_flags (abfd, s);
- if (! bfd_set_section_flags (abfd, s, flags & ~SEC_CODE))
- return false;
- hplink->splt = s;
+ hplink->splt = bfd_get_section_by_name (abfd, ".plt");
hplink->srelplt = bfd_get_section_by_name (abfd, ".rela.plt");
hplink->sgot = bfd_get_section_by_name (abfd, ".got");
@@ -1278,11 +1297,15 @@ elf32_hppa_check_relocs (abfd, info, sec, relocs)
break;
case R_PARISC_PCREL12F:
+ hplink->has_12bit_branch = 1;
+ /* Fall thru. */
case R_PARISC_PCREL17C:
case R_PARISC_PCREL17F:
+ hplink->has_17bit_branch = 1;
+ /* Fall thru. */
case R_PARISC_PCREL22F:
- /* Handle calls, and function pointers as they might need to
- go through the .plt, and might require long branch stubs. */
+ /* Function calls might need to go through the .plt, and
+ might require long branch stubs. */
if (h == NULL)
{
/* We know local syms won't need a .plt entry, and if
@@ -1329,7 +1352,8 @@ elf32_hppa_check_relocs (abfd, info, sec, relocs)
case R_PARISC_DIR17F: /* Used for external branches. */
case R_PARISC_DIR17R:
- case R_PARISC_DIR14R: /* Used for load/store from absolute locn. */
+ case R_PARISC_DIR14F: /* Used for load/store from absolute locn. */
+ case R_PARISC_DIR14R:
case R_PARISC_DIR21L: /* As above, and for ext branches too. */
#if 1
/* Help debug shared library creation. Any of the above
@@ -1932,6 +1956,8 @@ elf32_hppa_adjust_dynamic_symbol (info, h)
/* We also need to make an entry in the .rela.plt section. */
s = hplink->srelplt;
s->_raw_size += sizeof (Elf32_External_Rela);
+
+ hplink->need_plt_stub = 1;
}
return true;
}
@@ -2295,28 +2321,22 @@ elf32_hppa_size_dynamic_sections (output_bfd, info)
if (s->_raw_size != 0)
{
asection *target;
+ const char *outname;
/* Remember whether there are any reloc sections other
than .rela.plt. */
if (strcmp (name+5, ".plt") != 0)
- {
- 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 + 5);
- if (target != NULL
- && (target->flags & SEC_READONLY) != 0
- && (target->flags & SEC_ALLOC) != 0)
- reltext = true;
- }
+ relocs = true;
+
+ /* If this relocation section applies to a read only
+ section, then we probably need a DT_TEXTREL entry. */
+ outname = bfd_get_section_name (output_bfd,
+ s->output_section);
+ target = bfd_get_section_by_name (output_bfd, outname + 5);
+ if (target != NULL
+ && (target->flags & SEC_READONLY) != 0
+ && (target->flags & SEC_ALLOC) != 0)
+ reltext = true;
/* We use the reloc_count field as a counter if we need
to copy relocs into the output file. */
@@ -2324,7 +2344,22 @@ elf32_hppa_size_dynamic_sections (output_bfd, info)
}
}
else if (strcmp (name, ".plt") == 0)
- ;
+ {
+ if (hplink->need_plt_stub)
+ {
+ /* Make space for the plt stub at the end of the .plt
+ section. We want this stub right at the end, up
+ against the .got section. */
+ int gotalign = bfd_section_alignment (dynobj, hplink->sgot);
+ int pltalign = bfd_section_alignment (dynobj, s);
+ bfd_size_type mask;
+
+ if (gotalign > pltalign)
+ bfd_set_section_alignment (dynobj, s, gotalign);
+ mask = ((bfd_size_type) 1 << gotalign) - 1;
+ s->_raw_size = (s->_raw_size + sizeof (plt_stub) + mask) & ~mask;
+ }
+ }
else if (strcmp (name, ".got") == 0)
;
else
@@ -2413,12 +2448,13 @@ elf32_hppa_size_dynamic_sections (output_bfd, info)
instruction. */
boolean
-elf32_hppa_size_stubs (output_bfd, stub_bfd, info, multi_subspace,
+elf32_hppa_size_stubs (output_bfd, stub_bfd, info, multi_subspace, group_size,
add_stub_section, layout_sections_again)
bfd *output_bfd;
bfd *stub_bfd;
struct bfd_link_info *info;
boolean multi_subspace;
+ bfd_signed_vma group_size;
asection * (*add_stub_section) PARAMS ((const char *, asection *));
void (*layout_sections_again) PARAMS ((void));
{
@@ -2429,6 +2465,8 @@ elf32_hppa_size_stubs (output_bfd, stub_bfd, info, multi_subspace,
unsigned int bfd_indx, bfd_count;
int top_id, top_index;
struct elf32_hppa_link_hash_table *hplink;
+ bfd_size_type stub_group_size;
+ boolean stubs_always_before_branch;
boolean stub_changed = 0;
boolean ret = 0;
@@ -2439,6 +2477,20 @@ elf32_hppa_size_stubs (output_bfd, stub_bfd, info, multi_subspace,
hplink->multi_subspace = multi_subspace;
hplink->add_stub_section = add_stub_section;
hplink->layout_sections_again = layout_sections_again;
+ stubs_always_before_branch = group_size < 0;
+ if (group_size < 0)
+ stub_group_size = -group_size;
+ else
+ stub_group_size = group_size;
+ if (stub_group_size == 1)
+ {
+ /* Default values. */
+ stub_group_size = 8000000;
+ if (hplink->has_17bit_branch || hplink->multi_subspace)
+ stub_group_size = 250000;
+ if (hplink->has_12bit_branch)
+ stub_group_size = 7812;
+ }
/* Count the number of input BFDs and find the top input section id. */
for (input_bfd = info->input_bfds, bfd_count = 0, top_id = 0;
@@ -2490,7 +2542,7 @@ elf32_hppa_size_stubs (output_bfd, stub_bfd, info, multi_subspace,
section != NULL;
section = section->next)
{
- if ((section->flags & SEC_CODE) != 0 && section->index <= top_index)
+ if ((section->flags & SEC_CODE) != 0)
input_list[section->index] = NULL;
}
@@ -2546,7 +2598,7 @@ elf32_hppa_size_stubs (output_bfd, stub_bfd, info, multi_subspace,
total = tail->_raw_size;
while ((prev = PREV_SEC (curr)) != NULL
&& ((total += curr->output_offset - prev->output_offset)
- < 250000))
+ < stub_group_size))
curr = prev;
/* OK, the size from the start of CURR to the end is less
@@ -2570,14 +2622,17 @@ elf32_hppa_size_stubs (output_bfd, stub_bfd, info, multi_subspace,
/* But wait, there's more! Input sections up to 250000
bytes before the stub section can be handled by it too. */
- total = 0;
- while (prev != NULL
- && ((total += tail->output_offset - prev->output_offset)
- < 250000))
+ if (!stubs_always_before_branch)
{
- tail = prev;
- prev = PREV_SEC (tail);
- hplink->stub_group[tail->id].link_sec = curr;
+ total = 0;
+ while (prev != NULL
+ && ((total += tail->output_offset - prev->output_offset)
+ < stub_group_size))
+ {
+ tail = prev;
+ prev = PREV_SEC (tail);
+ hplink->stub_group[tail->id].link_sec = curr;
+ }
}
tail = prev;
}
@@ -3256,6 +3311,7 @@ final_link_relocate (input_section, contents, rel, value, hplink, sym_sec, h)
switch (r_type)
{
case R_PARISC_DIR32:
+ case R_PARISC_DIR14F:
case R_PARISC_DIR17F:
case R_PARISC_PCREL17C:
case R_PARISC_PCREL14F:
@@ -3688,6 +3744,7 @@ elf32_hppa_relocate_section (output_bfd, info, input_bfd, input_section,
case R_PARISC_DIR17F:
case R_PARISC_DIR17R:
+ case R_PARISC_DIR14F:
case R_PARISC_DIR14R:
case R_PARISC_DIR21L:
case R_PARISC_DPREL14F:
@@ -3871,7 +3928,6 @@ elf32_hppa_finish_dynamic_symbol (output_bfd, info, h, sym)
if (h->plt.offset != (bfd_vma) -1)
{
bfd_vma value;
- Elf_Internal_Rela rel;
/* This symbol has an entry in the procedure linkage table. Set
it up.
@@ -3879,15 +3935,7 @@ elf32_hppa_finish_dynamic_symbol (output_bfd, info, h, sym)
The format of a plt entry is
<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
- undefined; We create a dynamic relocation to fill in the
- correct value. */
+ */
value = 0;
if (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak)
@@ -3898,22 +3946,10 @@ 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,
- hplink->splt->contents + h->plt.offset);
- bfd_put_32 (hplink->splt->owner,
- elf_gp (hplink->splt->output_section->owner),
- hplink->splt->contents + h->plt.offset + 4);
- 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)
{
+ Elf_Internal_Rela rel;
+
/* Create a dynamic IPLT relocation for this entry. */
rel.r_offset = (h->plt.offset
+ hplink->splt->output_offset
@@ -3921,6 +3957,15 @@ elf32_hppa_finish_dynamic_symbol (output_bfd, info, h, sym)
if (! ((struct elf32_hppa_link_hash_entry *) h)->plt_abs
&& h->dynindx != -1)
{
+ /* To support lazy linking, the function pointer is
+ initialised to point to a special stub stored at the
+ end of the .plt. This is only done for plt entries
+ with a non-*ABS* dynamic relocation. */
+ value = (hplink->splt->output_offset
+ + hplink->splt->output_section->vma
+ + hplink->splt->_raw_size
+ - sizeof (plt_stub)
+ + PLT_STUB_ENTRY);
rel.r_info = ELF32_R_INFO (h->dynindx, R_PARISC_IPLT);
rel.r_addend = 0;
}
@@ -3940,6 +3985,20 @@ elf32_hppa_finish_dynamic_symbol (output_bfd, info, h, sym)
hplink->srelplt->reloc_count++;
}
+ bfd_put_32 (hplink->splt->owner,
+ value,
+ hplink->splt->contents + h->plt.offset);
+ bfd_put_32 (hplink->splt->owner,
+ elf_gp (hplink->splt->output_section->owner),
+ hplink->splt->contents + h->plt.offset + 4);
+ 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 ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
{
/* Mark the symbol as undefined, rather than as defined in
@@ -4122,17 +4181,38 @@ elf32_hppa_finish_dynamic_sections (output_bfd, info)
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);
+ memset (hplink->sgot->contents + GOT_ENTRY_SIZE, 0, GOT_ENTRY_SIZE);
/* Set .got entry size. */
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 = PLT_ENTRY_SIZE;
+ {
+ /* Set plt entry size. */
+ elf_section_data (hplink->splt->output_section)
+ ->this_hdr.sh_entsize = PLT_ENTRY_SIZE;
+
+ if (hplink->need_plt_stub)
+ {
+ /* Set up the .plt stub. */
+ memcpy (hplink->splt->contents
+ + hplink->splt->_raw_size - sizeof (plt_stub),
+ plt_stub, sizeof (plt_stub));
+
+ if ((hplink->splt->output_offset
+ + hplink->splt->output_section->vma
+ + hplink->splt->_raw_size)
+ != (hplink->sgot->output_offset
+ + hplink->sgot->output_section->vma))
+ {
+ (*_bfd_error_handler)
+ (_(".got section not immediately after .plt section"));
+ return false;
+ }
+ }
+ }
return true;
}