/* BFD back-end for HP PA-RISC ELF files.
- Copyright (C) 1990-2019 Free Software Foundation, Inc.
+ Copyright (C) 1990-2020 Free Software Foundation, Inc.
Original code by
Center for Software Science
Import stub to call shared library routine from normal object file
(single sub-space version)
- : addil LR'lt_ptr+ltoff,%dp ; get procedure entry point
- : ldw RR'lt_ptr+ltoff(%r1),%r21
+ : addil LR'lt_ptr+ltoff,%dp ; get PLT address
+ : ldo RR'lt_ptr+ltoff(%r1),%r22 ;
+ : ldw 0(%r22),%r21 ; get procedure entry point
: bv %r0(%r21)
- : ldw RR'lt_ptr+ltoff+4(%r1),%r19 ; get new dlt value.
+ : ldw 4(%r22),%r19 ; get new dlt value.
Import stub to call shared library routine from shared library
(single sub-space version)
- : addil LR'ltoff,%r19 ; get procedure entry point
- : ldw RR'ltoff(%r1),%r21
+ : addil LR'ltoff,%r19 ; get PLT address
+ : ldo RR'ltoff(%r1),%r22
+ : ldw 0(%r22),%r21 ; get procedure entry point
: bv %r0(%r21)
- : ldw RR'ltoff+4(%r1),%r19 ; get new dlt value.
+ : ldw 4(%r22),%r19 ; get new dlt value.
Import stub to call shared library routine from normal object file
(multiple sub-space support)
- : addil LR'lt_ptr+ltoff,%dp ; get procedure entry point
- : ldw RR'lt_ptr+ltoff(%r1),%r21
- : ldw RR'lt_ptr+ltoff+4(%r1),%r19 ; get new dlt value.
- : ldsid (%r21),%r1
+ : addil LR'lt_ptr+ltoff,%dp ; get PLT address
+ : ldo RR'lt_ptr+ltoff(%r1),%r22 ;
+ : ldw 0(%r22),%r21 ; get procedure entry point
+ : ldsid (%r21),%r1 ; get target sid
+ : ldw 4(%r22),%r19 ; get new dlt value.
: mtsp %r1,%sr0
: be 0(%sr0,%r21) ; branch to target
: stw %rp,-24(%sp) ; save rp
Import stub to call shared library routine from shared library
(multiple sub-space support)
- : addil LR'ltoff,%r19 ; get procedure entry point
- : ldw RR'ltoff(%r1),%r21
- : ldw RR'ltoff+4(%r1),%r19 ; get new dlt value.
- : ldsid (%r21),%r1
+ : addil LR'ltoff,%r19 ; get PLT address
+ : ldo RR'ltoff(%r1),%r22
+ : ldw 0(%r22),%r21 ; get procedure entry point
+ : ldsid (%r21),%r1 ; get target sid
+ : ldw 4(%r22),%r19 ; get new dlt value.
: mtsp %r1,%sr0
: be 0(%sr0,%r21) ; branch to target
: stw %rp,-24(%sp) ; save rp
#define PLT_ENTRY_SIZE 8
#define GOT_ENTRY_SIZE 4
+#define LONG_BRANCH_STUB_SIZE 8
+#define LONG_BRANCH_SHARED_STUB_SIZE 12
+#define IMPORT_STUB_SIZE 20
+#define IMPORT_SHARED_STUB_SIZE 32
+#define EXPORT_STUB_SIZE 24
#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, 0x80, 0x10, 0x95, /* 1: ldw 0(%r20),%r21 */
+ 0xea, 0xa0, 0xc0, 0x00, /* bv %r0(%r21) */
0x0e, 0x88, 0x10, 0x95, /* ldw 4(%r20),%r21 */
#define PLT_STUB_ENTRY (3*4)
0xea, 0x9f, 0x1f, 0xdd, /* b,l 1b,%r20 */
symbol. */
struct elf32_hppa_stub_hash_entry *hsh_cache;
- /* Used to count relocations for delayed sizing of relocation
- sections. */
- struct elf_dyn_relocs *dyn_relocs;
-
ENUM_BITFIELD (_tls_type) tls_type : 8;
/* Set if this symbol is used by a plabel reloc. */
/* Initialize the local fields. */
hh = hppa_elf_hash_entry (entry);
hh->hsh_cache = NULL;
- hh->dyn_relocs = NULL;
hh->plabel = 0;
hh->tls_type = GOT_UNKNOWN;
}
elf32_hppa_link_hash_table_create (bfd *abfd)
{
struct elf32_hppa_link_hash_table *htab;
- bfd_size_type amt = sizeof (*htab);
+ size_t amt = sizeof (*htab);
htab = bfd_zmalloc (amt);
if (htab == NULL)
#define ADDIL_R19 0x2a600000 /* addil LR'XXX,%r19,%r1 */
#define LDW_R1_DP 0x483b0000 /* ldw RR'XXX(%sr0,%r1),%dp */
+#define LDO_R1_R22 0x34360000 /* ldo RR'XXX(%r1),%r22 */
+#define LDW_R22_R21 0x0ec01095 /* ldw 0(%r22),%r21 */
+#define LDW_R22_R19 0x0ec81093 /* ldw 4(%r22),%r19 */
+
#define LDSID_R21_R1 0x02a010a1 /* ldsid (%sr0,%r21),%r1 */
#define MTSP_R1 0x00011820 /* mtsp %r1,%sr0 */
#define BE_SR0_R21 0xe2a00000 /* be 0(%sr0,%r21) */
switch (hsh->stub_type)
{
case hppa_stub_long_branch:
+ /* Fail if the target section could not be assigned to an output
+ section. The user should fix his linker script. */
+ if (hsh->target_section->output_section == NULL
+ && info->non_contiguous_regions)
+ info->callbacks->einfo (_("%F%P: Could not assign '%pA' to an output "
+ "section. Retry without "
+ "--enable-non-contiguous-regions.\n"),
+ hsh->target_section);
+
/* Create the long branch. A long branch is formed with "ldil"
loading the upper bits of the target address into a register,
then branching with "be" which adds in the lower bits.
insn = hppa_rebuild_insn ((int) BE_SR4_R1, val, 17);
bfd_put_32 (stub_bfd, insn, loc + 4);
- size = 8;
+ size = LONG_BRANCH_STUB_SIZE;
break;
case hppa_stub_long_branch_shared:
+ /* Fail if the target section could not be assigned to an output
+ section. The user should fix his linker script. */
+ if (hsh->target_section->output_section == NULL
+ && info->non_contiguous_regions)
+ info->callbacks->einfo (_("%F%P: Could not assign %pA to an output "
+ "section. Retry without "
+ "--enable-non-contiguous-regions.\n"),
+ hsh->target_section);
+
/* Branches are relative. This is where we are going to. */
sym_value = (hsh->target_value
+ hsh->target_section->output_offset
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;
+ size = LONG_BRANCH_SHARED_STUB_SIZE;
break;
case hppa_stub_import:
if (hsh->stub_type == hppa_stub_import_shared)
insn = ADDIL_R19;
#endif
+
+ /* Load function descriptor address into register %r22. It is
+ sometimes needed for lazy binding. */
val = hppa_field_adjust (sym_value, 0, e_lrsel),
insn = hppa_rebuild_insn ((int) insn, val, 21);
bfd_put_32 (stub_bfd, insn, loc);
- /* 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, 0, e_rrsel);
- insn = hppa_rebuild_insn ((int) LDW_R1_R21, val, 14);
+ insn = hppa_rebuild_insn ((int) LDO_R1_R22, val, 14);
bfd_put_32 (stub_bfd, insn, loc + 4);
+ bfd_put_32 (stub_bfd, (bfd_vma) LDW_R22_R21, loc + 8);
+
if (htab->multi_subspace)
{
- 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);
-
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);
+ bfd_put_32 (stub_bfd, (bfd_vma) LDW_R22_R19, loc + 16);
+ bfd_put_32 (stub_bfd, (bfd_vma) MTSP_R1, loc + 20);
+ bfd_put_32 (stub_bfd, (bfd_vma) BE_SR0_R21, loc + 24);
+ bfd_put_32 (stub_bfd, (bfd_vma) STW_RP, loc + 28);
- size = 28;
+ size = IMPORT_SHARED_STUB_SIZE;
}
else
{
- bfd_put_32 (stub_bfd, (bfd_vma) BV_R0_R21, loc + 8);
- 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);
+ bfd_put_32 (stub_bfd, (bfd_vma) BV_R0_R21, loc + 12);
+ bfd_put_32 (stub_bfd, (bfd_vma) LDW_R22_R19, loc + 16);
- size = 16;
+ size = IMPORT_STUB_SIZE;
}
break;
case hppa_stub_export:
+ /* Fail if the target section could not be assigned to an output
+ section. The user should fix his linker script. */
+ if (hsh->target_section->output_section == NULL
+ && info->non_contiguous_regions)
+ info->callbacks->einfo (_("%F%P: Could not assign %pA to an output "
+ "section. Retry without "
+ "--enable-non-contiguous-regions.\n"),
+ hsh->target_section);
+
/* Branches are relative. This is where we are going to. */
sym_value = (hsh->target_value
+ hsh->target_section->output_offset
hsh->hh->eh.root.u.def.section = stub_sec;
hsh->hh->eh.root.u.def.value = stub_sec->size;
- size = 24;
+ size = EXPORT_STUB_SIZE;
break;
default:
htab = in_arg;
if (hsh->stub_type == hppa_stub_long_branch)
- size = 8;
+ size = LONG_BRANCH_STUB_SIZE;
else if (hsh->stub_type == hppa_stub_long_branch_shared)
- size = 12;
+ size = LONG_BRANCH_SHARED_STUB_SIZE;
else if (hsh->stub_type == hppa_stub_export)
- size = 24;
+ size = EXPORT_STUB_SIZE;
else /* hppa_stub_import or hppa_stub_import_shared. */
{
if (htab->multi_subspace)
- size = 28;
+ size = IMPORT_SHARED_STUB_SIZE;
else
- size = 16;
+ size = IMPORT_STUB_SIZE;
}
hsh->stub_sec->size += size;
hh_dir = hppa_elf_hash_entry (eh_dir);
hh_ind = hppa_elf_hash_entry (eh_ind);
- if (hh_ind->dyn_relocs != NULL
- && eh_ind->root.type == bfd_link_hash_indirect)
- {
- if (hh_dir->dyn_relocs != NULL)
- {
- struct elf_dyn_relocs **hdh_pp;
- struct elf_dyn_relocs *hdh_p;
-
- /* Add reloc counts against the indirect sym to the direct sym
- list. Merge any entries against the same section. */
- for (hdh_pp = &hh_ind->dyn_relocs; (hdh_p = *hdh_pp) != NULL; )
- {
- struct elf_dyn_relocs *hdh_q;
-
- for (hdh_q = hh_dir->dyn_relocs;
- hdh_q != NULL;
- hdh_q = hdh_q->next)
- if (hdh_q->sec == hdh_p->sec)
- {
-#if RELATIVE_DYNRELOCS
- hdh_q->pc_count += hdh_p->pc_count;
-#endif
- hdh_q->count += hdh_p->count;
- *hdh_pp = hdh_p->next;
- break;
- }
- if (hdh_q == NULL)
- hdh_pp = &hdh_p->next;
- }
- *hdh_pp = hh_dir->dyn_relocs;
- }
-
- hh_dir->dyn_relocs = hh_ind->dyn_relocs;
- hh_ind->dyn_relocs = NULL;
- }
-
if (eh_ind->root.type == bfd_link_hash_indirect)
{
hh_dir->plabel |= hh_ind->plabel;
relocations we need for this symbol. */
if (hh != NULL)
{
- hdh_head = &hh->dyn_relocs;
+ hdh_head = &hh->eh.dyn_relocs;
}
else
{
}
}
-/* Find any dynamic relocs that apply to read-only sections. */
-
-static asection *
-readonly_dynrelocs (struct elf_link_hash_entry *eh)
-{
- struct elf32_hppa_link_hash_entry *hh;
- struct elf_dyn_relocs *hdh_p;
-
- hh = hppa_elf_hash_entry (eh);
- for (hdh_p = hh->dyn_relocs; hdh_p != NULL; hdh_p = hdh_p->next)
- {
- asection *sec = hdh_p->sec->output_section;
-
- if (sec != NULL && (sec->flags & SEC_READONLY) != 0)
- return hdh_p->sec;
- }
- return NULL;
-}
-
/* Return true if we have dynamic relocs against H or any of its weak
aliases, that apply to read-only sections. Cannot be used after
size_dynamic_sections. */
struct elf32_hppa_link_hash_entry *hh = hppa_elf_hash_entry (eh);
do
{
- if (readonly_dynrelocs (&hh->eh))
+ if (_bfd_elf_readonly_dynrelocs (&hh->eh))
return TRUE;
hh = hppa_elf_hash_entry (hh->eh.u.alias);
} while (hh != NULL && &hh->eh != eh);
/* Discard dyn_relocs when non-pic if we've decided that a
function symbol is local. */
if (!bfd_link_pic (info) && local)
- hppa_elf_hash_entry (eh)->dyn_relocs = NULL;
+ eh->dyn_relocs = NULL;
/* If the symbol is used by a plabel, we must allocate a PLT slot.
The refcounts are not reliable when it has been hidden since
eh->root.u.def.value = def->root.u.def.value;
if (def->root.u.def.section == htab->etab.sdynbss
|| def->root.u.def.section == htab->etab.sdynrelro)
- hppa_elf_hash_entry (eh)->dyn_relocs = NULL;
+ eh->dyn_relocs = NULL;
return TRUE;
}
}
/* We no longer want dyn_relocs. */
- hppa_elf_hash_entry (eh)->dyn_relocs = NULL;
+ eh->dyn_relocs = NULL;
return _bfd_elf_adjust_dynamic_copy (info, eh, sec);
}
/* If no dynamic sections we can't have dynamic relocs. */
if (!htab->etab.dynamic_sections_created)
- hh->dyn_relocs = NULL;
+ eh->dyn_relocs = NULL;
/* Discard relocs on undefined syms with non-default visibility. */
else if ((eh->root.type == bfd_link_hash_undefined
&& ELF_ST_VISIBILITY (eh->other) != STV_DEFAULT)
|| UNDEFWEAK_NO_DYNAMIC_RELOC (info, eh))
- hh->dyn_relocs = NULL;
+ eh->dyn_relocs = NULL;
- if (hh->dyn_relocs == NULL)
+ if (eh->dyn_relocs == NULL)
return TRUE;
/* If this is a -Bsymbolic shared link, then we need to discard all
{
struct elf_dyn_relocs **hdh_pp;
- for (hdh_pp = &hh->dyn_relocs; (hdh_p = *hdh_pp) != NULL; )
+ for (hdh_pp = &eh->dyn_relocs; (hdh_p = *hdh_pp) != NULL; )
{
hdh_p->count -= hdh_p->pc_count;
hdh_p->pc_count = 0;
}
#endif
- if (hh->dyn_relocs != NULL)
+ if (eh->dyn_relocs != NULL)
{
if (!ensure_undef_dynamic (info, eh))
return FALSE;
return FALSE;
if (eh->dynindx == -1)
- hh->dyn_relocs = NULL;
+ eh->dyn_relocs = NULL;
}
else
- hh->dyn_relocs = NULL;
+ eh->dyn_relocs = NULL;
}
/* Finally, allocate space. */
- for (hdh_p = hh->dyn_relocs; hdh_p != NULL; hdh_p = hdh_p->next)
+ for (hdh_p = eh->dyn_relocs; hdh_p != NULL; hdh_p = hdh_p->next)
{
asection *sreloc = elf_section_data (hdh_p->sec)->sreloc;
sreloc->size += hdh_p->count * sizeof (Elf32_External_Rela);
return TRUE;
}
-/* Set DF_TEXTREL if we find any dynamic relocs that apply to
- read-only sections. */
-
-static bfd_boolean
-maybe_set_textrel (struct elf_link_hash_entry *eh, void *inf)
-{
- asection *sec;
-
- if (eh->root.type == bfd_link_hash_indirect)
- return TRUE;
-
- sec = readonly_dynrelocs (eh);
- if (sec != NULL)
- {
- struct bfd_link_info *info = (struct bfd_link_info *) inf;
-
- info->flags |= DF_TEXTREL;
- info->callbacks->minfo
- (_("%pB: dynamic relocation against `%pT' in read-only section `%pA'\n"),
- sec->owner, eh->root.root.string, sec);
-
- /* Not an error, just cut short the traversal. */
- return FALSE;
- }
- return TRUE;
-}
-
/* Set the sizes of the dynamic sections. */
static bfd_boolean
against the .got section. */
int gotalign = bfd_section_alignment (htab->etab.sgot);
int pltalign = bfd_section_alignment (sec);
+ int align = gotalign > 3 ? gotalign : 3;
bfd_size_type mask;
- if (gotalign > pltalign)
- bfd_set_section_alignment (sec, gotalign);
+ if (align > pltalign)
+ bfd_set_section_alignment (sec, align);
mask = ((bfd_size_type) 1 << gotalign) - 1;
sec->size = (sec->size + sizeof (plt_stub) + mask) & ~mask;
}
/* If any dynamic relocs apply to a read-only section,
then we need a DT_TEXTREL entry. */
if ((info->flags & DF_TEXTREL) == 0)
- elf_link_hash_traverse (&htab->etab, maybe_set_textrel, info);
+ elf_link_hash_traverse (&htab->etab,
+ _bfd_elf_maybe_set_textrel, info);
if ((info->flags & DF_TEXTREL) != 0)
{
unsigned int top_id, top_index;
asection *section;
asection **input_list, **list;
- bfd_size_type amt;
+ size_t amt;
struct elf32_hppa_link_hash_table *htab = hppa_link_hash_table (info);
if (htab == NULL)
/* We want to read in symbol extension records only once. To do this
we need to read in the local symbols in parallel and save them for
later use; so hold pointers to the local symbols in an array. */
- bfd_size_type amt = sizeof (Elf_Internal_Sym *) * htab->bfd_count;
+ size_t amt = sizeof (Elf_Internal_Sym *) * htab->bfd_count;
all_local_syms = bfd_zmalloc (amt);
htab->all_local_syms = all_local_syms;
if (all_local_syms == NULL)
/* Do not attempt to sort non-regular files. This is here
especially for configure scripts and kernel builds which run
tests with "ld [...] -o /dev/null". */
- if (stat (abfd->filename, &buf) != 0
+ if (stat (bfd_get_filename (abfd), &buf) != 0
|| !S_ISREG(buf.st_mode))
return TRUE;
struct elf32_hppa_link_hash_entry *hh,
struct bfd_link_info *info)
{
- int insn;
+ unsigned int insn;
unsigned int r_type = ELF32_R_TYPE (rela->r_info);
unsigned int orig_r_type = r_type;
reloc_howto_type *howto = elf_hppa_howto_table + r_type;
/* GCC sometimes uses a register other than r19 for the
operation, so we must convert any addil instruction
that uses this relocation. */
- if ((insn & 0xfc000000) == ((int) OP_ADDIL << 26))
+ if ((insn & 0xfc000000) == OP_ADDIL << 26)
insn = ADDIL_DP;
else
/* We must have a ldil instruction. It's too hard to find
instance: "extern int foo" with foo defined as "const int foo". */
if (sym_sec == NULL || (sym_sec->flags & SEC_CODE) != 0)
{
- if ((insn & ((0x3f << 26) | (0x1f << 21)))
- == (((int) OP_ADDIL << 26) | (27 << 21)))
+ if ((insn & ((0x3fu << 26) | (0x1f << 21)))
+ == ((OP_ADDIL << 26) | (27 << 21)))
{
insn &= ~ (0x1f << 21);
}
if (bfd_link_pic (info)
? ((hh == NULL
- || hh->dyn_relocs != NULL)
+ || hh->eh.dyn_relocs != NULL)
&& ((hh != NULL && pc_dynrelocs (hh))
|| IS_ABSOLUTE_RELOC (r_type)))
: (hh != NULL
- && hh->dyn_relocs != NULL))
+ && hh->eh.dyn_relocs != NULL))
{
Elf_Internal_Rela outrel;
bfd_boolean skip;