/* BFD back-end for HP PA-RISC ELF files.
- Copyright (C) 1990-2017 Free Software Foundation, Inc.
+ Copyright (C) 1990-2019 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
/* Variable names follow a coding style.
Please follow this (Apps Hungarian) style:
- Structure/Variable Prefix
+ Structure/Variable Prefix
elf_link_hash_table "etab"
elf_link_hash_entry "eh"
#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 */
more than one stub used to reach say, printf, and we need to
distinguish between them. */
id_sec = htab->stub_group[input_section->id].link_sec;
+ if (id_sec == NULL)
+ return NULL;
if (hh != NULL && hh->hsh_cache != NULL
&& hh->hsh_cache->hh == hh
if (hsh == NULL)
{
/* xgettext:c-format */
- _bfd_error_handler (_("%B: cannot create stub entry %s"),
+ _bfd_error_handler (_("%pB: cannot create stub entry %s"),
section->owner, stub_name);
return NULL;
}
return hppa_stub_import;
}
+ if (destination == (bfd_vma) -1)
+ return hppa_stub_none;
+
/* Determine where the call point is. */
location = (input_sec->output_offset
+ input_sec->output_section->vma
#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) */
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:
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;
{
_bfd_error_handler
/* xgettext:c-format */
- (_("%B(%A+%#Lx): cannot reach %s, recompile with -ffunction-sections"),
+ (_("%pB(%pA+%#" PRIx64 "): "
+ "cannot reach %s, recompile with -ffunction-sections"),
hsh->target_section->owner,
stub_sec,
- hsh->stub_offset,
+ (uint64_t) hsh->stub_offset,
hsh->bh_root.string);
bfd_set_error (bfd_error_bad_value);
return FALSE;
insn = hppa_rebuild_insn ((int) BL22_RP, val, 22);
bfd_put_32 (stub_bfd, insn, loc);
- bfd_put_32 (stub_bfd, (bfd_vma) NOP, loc + 4);
+ 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);
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;
{
_bfd_error_handler
/* xgettext:c-format */
- (_("%B: relocation %s can not be used when making a shared object; recompile with -fPIC"),
+ (_("%pB: relocation %s can not be used when making a shared object; recompile with -fPIC"),
abfd,
elf_hppa_howto_table[r_type].name);
bfd_set_error (bfd_error_bad_value);
/* This relocation describes which C++ vtable entries are actually
used. Record for later use during GC. */
case R_PARISC_GNU_VTENTRY:
- BFD_ASSERT (hh != NULL);
- if (hh != NULL
- && !bfd_elf_gc_record_vtentry (abfd, sec, &hh->eh, rela->r_addend))
+ if (!bfd_elf_gc_record_vtentry (abfd, sec, &hh->eh, rela->r_addend))
return FALSE;
continue;
case R_PARISC_TLS_IE21L:
case R_PARISC_TLS_IE14R:
if (bfd_link_dll (info))
- info->flags |= DF_STATIC_TLS;
+ info->flags |= DF_STATIC_TLS;
need_entry = NEED_GOT;
break;
}
/* Calculate size of relocs needed for symbol given its TLS_TYPE and
- NEEDed GOT entries. KNOWN says a TPREL offset can be calculated
- at link time. */
+ NEEDed GOT entries. TPREL_KNOWN says a TPREL offset can be
+ calculated at link time. DTPREL_KNOWN says the same for a DTPREL
+ offset. */
static inline unsigned int
-got_relocs_needed (int tls_type, unsigned int need, bfd_boolean known)
+got_relocs_needed (int tls_type, unsigned int need,
+ bfd_boolean dtprel_known, bfd_boolean tprel_known)
{
/* All the entries we allocated need relocs.
- Except IE in executable with a local symbol. We could also omit
- the DTPOFF reloc on the second word of a GD entry under the same
- condition as that for IE, but ld.so might want to differentiate
- LD and GD entries at some stage. */
- if ((tls_type & GOT_TLS_IE) != 0 && known)
+ Except for GD and IE with local symbols. */
+ if ((tls_type & GOT_TLS_GD) != 0 && dtprel_known)
+ need -= GOT_ENTRY_SIZE;
+ if ((tls_type & GOT_TLS_IE) != 0 && tprel_known)
need -= GOT_ENTRY_SIZE;
return need * sizeof (Elf32_External_Rela) / GOT_ENTRY_SIZE;
}
need = got_entries_needed (hh->tls_type);
sec->size += need;
if (htab->etab.dynamic_sections_created
- && (bfd_link_pic (info)
+ && (bfd_link_dll (info)
+ || (bfd_link_pic (info) && (hh->tls_type & GOT_NORMAL) != 0)
|| (eh->dynindx != -1
&& !SYMBOL_REFERENCES_LOCAL (info, eh)))
&& !UNDEFWEAK_NO_DYNAMIC_RELOC (info, eh))
{
- bfd_boolean tprel_known = (bfd_link_executable (info)
- && SYMBOL_REFERENCES_LOCAL (info, eh));
+ bfd_boolean local = SYMBOL_REFERENCES_LOCAL (info, eh);
htab->etab.srelgot->size
- += got_relocs_needed (hh->tls_type, need, tprel_known);
+ += got_relocs_needed (hh->tls_type, need, local,
+ local && bfd_link_executable (info));
}
}
else
info->flags |= DF_TEXTREL;
info->callbacks->minfo
- (_("%B: dynamic relocation against `%T' in read-only section `%A'\n"),
+ (_("%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. */
*local_got = sec->size;
need = got_entries_needed (*local_tls_type);
sec->size += need;
- if (bfd_link_pic (info))
- {
- bfd_boolean tprel_known = bfd_link_executable (info);
- htab->etab.srelgot->size
- += got_relocs_needed (*local_tls_type, need, tprel_known);
- }
+ if (bfd_link_dll (info)
+ || (bfd_link_pic (info)
+ && (*local_tls_type & GOT_NORMAL) != 0))
+ htab->etab.srelgot->size
+ += got_relocs_needed (*local_tls_type, need, TRUE,
+ bfd_link_executable (info));
}
else
*local_got = (bfd_vma) -1;
if (htab->tls_ldm_got.refcount > 0)
{
/* Allocate 2 got entries and 1 dynamic reloc for
- R_PARISC_TLS_DTPMOD32 relocs. */
+ R_PARISC_TLS_DTPMOD32 relocs. */
htab->tls_ldm_got.offset = htab->etab.sgot->size;
htab->etab.sgot->size += (GOT_ENTRY_SIZE * 2);
htab->etab.srelgot->size += sizeof (Elf32_External_Rela);
/* 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, htab->etab.sgot);
- int pltalign = bfd_section_alignment (dynobj, sec);
+ 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)
- (void) bfd_set_section_alignment (dynobj, 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;
}
|| sec == htab->etab.sdynbss
|| sec == htab->etab.sdynrelro)
;
- else if (CONST_STRNEQ (bfd_get_section_name (dynobj, sec), ".rela"))
+ else if (CONST_STRNEQ (bfd_section_name (sec), ".rela"))
{
if (sec->size != 0)
{
else
{
/* xgettext:c-format */
- _bfd_error_handler (_("%B: duplicate export stub %s"),
+ _bfd_error_handler (_("%pB: duplicate export stub %s"),
input_bfd, stub_name);
}
}
/* If there aren't any relocs, then there's nothing more
to do. */
if ((section->flags & SEC_RELOC) == 0
+ || (section->flags & SEC_ALLOC) == 0
+ || (section->flags & SEC_LOAD) == 0
+ || (section->flags & SEC_CODE) == 0
|| section->reloc_count == 0)
continue;
section. */
sym_sec = NULL;
sym_value = 0;
- destination = 0;
+ destination = -1;
hh = NULL;
if (r_indx < symtab_hdr->sh_info)
{
{
if (strcmp (bfd_get_target (abfd), "elf32-hppa-netbsd") != 0)
{
- /* We know we don't have a .plt. If .got is large,
+ /* We know we don't have a .plt. If .got is large,
offset our LTP. */
- if (sec->size > 0x2000)
+ if (sec->size > 0x2000)
gp_val = 0x2000;
}
}
|| hh->eh.root.type == bfd_link_hash_defweak)))
{
hsh = hppa_get_stub_entry (input_section, sym_sec,
- hh, rela, htab);
+ hh, rela, htab);
if (hsh != NULL)
{
value = (hsh->stub_offset
error. */
_bfd_error_handler
/* xgettext:c-format */
- (_("%B(%A+%#Lx): %s fixup for insn %#x is not supported in a non-shared link"),
+ (_("%pB(%pA+%#" PRIx64 "): %s fixup for insn %#x "
+ "is not supported in a non-shared link"),
input_bfd,
input_section,
- offset,
+ (uint64_t) offset,
howto->name,
insn);
}
if (value + addend + max_branch_offset >= 2*max_branch_offset)
{
hsh = hppa_get_stub_entry (input_section, sym_sec,
- hh, rela, htab);
+ hh, rela, htab);
if (hsh == NULL)
return bfd_reloc_undefined;
{
_bfd_error_handler
/* xgettext:c-format */
- (_("%B(%A+%#Lx): cannot reach %s, recompile with -ffunction-sections"),
+ (_("%pB(%pA+%#" PRIx64 "): cannot reach %s, "
+ "recompile with -ffunction-sections"),
input_bfd,
input_section,
- offset,
+ (uint64_t) offset,
hsh->bh_root.string);
bfd_set_error (bfd_error_bad_value);
return bfd_reloc_notsupported;
bfd_byte *loc = NULL;
int cur_off = off;
- /* The GOT entries have not been initialized yet. Do it
- now, and emit any relocations. If both an IE GOT and a
- GD GOT are necessary, we emit the GD first. */
+ /* The GOT entries have not been initialized yet. Do it
+ now, and emit any relocations. If both an IE GOT and a
+ GD GOT are necessary, we emit the GD first. */
if (indx != 0
- || (bfd_link_pic (info)
+ || (bfd_link_dll (info)
&& (hh == NULL
|| !UNDEFWEAK_NO_DYNAMIC_RELOC (info, &hh->eh))))
{
bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
htab->etab.srelgot->reloc_count++;
loc += sizeof (Elf32_External_Rela);
+ bfd_put_32 (output_bfd, 0,
+ htab->etab.sgot->contents + cur_off);
+ }
+ else
+ /* If we are not emitting relocations for a
+ general dynamic reference, then we must be in a
+ static link or an executable link with the
+ symbol binding locally. Mark it as belonging
+ to module 1, the executable. */
+ bfd_put_32 (output_bfd, 1,
+ htab->etab.sgot->contents + cur_off);
+
+ if (indx != 0)
+ {
outrel.r_info
= ELF32_R_INFO (indx, R_PARISC_TLS_DTPOFF32);
outrel.r_offset += 4;
bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
htab->etab.srelgot->reloc_count++;
loc += sizeof (Elf32_External_Rela);
- bfd_put_32 (output_bfd, 0,
- htab->etab.sgot->contents + cur_off);
bfd_put_32 (output_bfd, 0,
htab->etab.sgot->contents + cur_off + 4);
}
else
- {
- /* If we are not emitting relocations for a
- general dynamic reference, then we must be in a
- static link or an executable link with the
- symbol binding locally. Mark it as belonging
- to module 1, the executable. */
- bfd_put_32 (output_bfd, 1,
- htab->etab.sgot->contents + cur_off);
- bfd_put_32 (output_bfd, relocation - dtpoff_base (info),
- htab->etab.sgot->contents + cur_off + 4);
- }
+ bfd_put_32 (output_bfd, relocation - dtpoff_base (info),
+ htab->etab.sgot->contents + cur_off + 4);
cur_off += 8;
}
if (sym_name == NULL)
return FALSE;
if (*sym_name == '\0')
- sym_name = bfd_section_name (input_bfd, sym_sec);
+ sym_name = bfd_section_name (sym_sec);
_bfd_error_handler
- (_("%B:%s has both normal and TLS relocs"),
+ (_("%pB:%s has both normal and TLS relocs"),
input_bfd, sym_name);
}
bfd_set_error (bfd_error_bad_value);
}
if ((tls_type & GOT_TLS_GD)
- && r_type != R_PARISC_TLS_GD21L
- && r_type != R_PARISC_TLS_GD14R)
+ && r_type != R_PARISC_TLS_GD21L
+ && r_type != R_PARISC_TLS_GD14R)
off += 2 * GOT_ENTRY_SIZE;
/* Add the base of the GOT to the relocation value. */
if (sym_name == NULL)
return FALSE;
if (*sym_name == '\0')
- sym_name = bfd_section_name (input_bfd, sym_sec);
+ sym_name = bfd_section_name (sym_sec);
}
howto = elf_hppa_howto_table + r_type;
{
_bfd_error_handler
/* xgettext:c-format */
- (_("%B(%A+%#Lx): cannot handle %s for %s"),
+ (_("%pB(%pA+%#" PRIx64 "): cannot handle %s for %s"),
input_bfd,
input_section,
- rela->r_offset,
+ (uint64_t) rela->r_offset,
howto->name,
sym_name);
bfd_set_error (bfd_error_bad_value);
case R_PARISC_TLS_DTPMOD32:
case R_PARISC_TLS_DTPOFF32:
case R_PARISC_TLS_TPREL32:
- return reloc_class_normal;
+ return reloc_class_normal;
}
if (ELF32_R_SYM (rela->r_info) == STN_UNDEF)