hppa64: Implement segment based relocations for local symbols

There is progress in implementing 64-bit shared library support.

Fixes link error compiling vdso64.so.  HP-UX dynamic linker no longer
complains that libgcc_s.4 linked with GNU ld is an invalid shared library.

Relocations are now generated for all slots in .rela.data, .rela.dlt
and .rela.opd.  Relocation counts for libgcc_s.4 linked using GNU and
HP ld are the same except .rela.plt.  That may be okay as GNU ld directs
pc-relative calls to stubs.

Glibc's ld.so.new appears to link okay.  However, libgcc_s.4 linked with
GNU ld is still broken on HP-UX.

There are six unexpected fails in the testsuite and three unexpected
passes.  There's at least one fail due to name munging in the .dynsym
table.

2025-11-02  John David Anglin  <danglin@gcc.gnu.org>

bfd/ChangeLog:

	* elf64-hppa.c (struct elf64_hppa_link_hash_entry): Remove
	sym_ind and owner fields.  Rename hash entries for __text_seg
	and __data_seg.  Adjust all users.
	(global_sym_index): Remove.
	(hppa64_elf_local_refcounts): Assert size is not 0.
	(elf64_hppa_check_relocs): Drop NEED_PLT from R_PARISC_FPTR64
	relocation.  Don't stash abfd and r_symndx in hh->owner and
	hh->sym_indx.  Add global symbols with hh->eh.dynindx equal
	-1 to dynamic table.  Don't record section symbols to the
	local dynamic symbol table.
	(allocate_global_data_dlt): Don't add symbol to local dynamic
	symbol table.
	(allocate_global_data_opd): Likewise.
	(elf64_hppa_late_size_sections): Rework code to add __text_seg
	and __data_seg symbols to the dynamic table.
	(elf64_hppa_finalize_dlt): Revise to use __text_seg and
	__data_seg symbols.
	(elf64_hppa_finalize_dynreloc): Likewise.
	(elf_hppa_final_link_relocate): When generating a shared
	library, ignore relocs in debugging sections.  Revise
	relocations needing DLT and OPD dynamic relocations to output
	dynamic relocatios for local symbols.  Move code to initialize
	segment base values back to SEGREL case.
This commit is contained in:
John David Anglin
2025-11-02 16:04:55 -05:00
parent 1ddfd4f3ea
commit e23cba69ec

View File

@@ -62,12 +62,6 @@ struct elf64_hppa_link_hash_entry
bfd_vma opd_offset; bfd_vma opd_offset;
bfd_vma stub_offset; bfd_vma stub_offset;
/* The index of the (possibly local) symbol in the input bfd and its
associated BFD. Needed so that we can have relocs against local
symbols in shared libraries. */
long sym_indx;
bfd *owner;
/* Dynamic symbols may need to have two different values. One for /* Dynamic symbols may need to have two different values. One for
the dynamic symbol table, one for the normal symbol table. the dynamic symbol table, one for the normal symbol table.
@@ -137,9 +131,9 @@ struct elf64_hppa_link_hash_table
bfd_vma text_segment_base; bfd_vma text_segment_base;
bfd_vma data_segment_base; bfd_vma data_segment_base;
/* Hash entries for __text_seg and __data_seg. */ /* Hash entries for __text_seg and __data_seg symbols. */
struct elf_link_hash_entry *text_segment; struct elf_link_hash_entry *text_hash_entry;
struct elf_link_hash_entry *data_segment; struct elf_link_hash_entry *data_hash_entry;
/* We build tables to map from an input section back to its /* We build tables to map from an input section back to its
symbol index. This is the BFD for which we currently have symbol index. This is the BFD for which we currently have
@@ -251,24 +245,6 @@ static bool get_stub
static int elf64_hppa_elf_get_symbol_type static int elf64_hppa_elf_get_symbol_type
(Elf_Internal_Sym *, int); (Elf_Internal_Sym *, int);
/* Search for the index of a global symbol in it's defining object file. */
static long
global_sym_index (struct elf_link_hash_entry *h)
{
struct elf_link_hash_entry **p;
bfd *obj;
BFD_ASSERT (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak);
obj = h->root.u.def.section->owner;
for (p = elf_sym_hashes (obj); *p != h; ++p)
continue;
return p - elf_sym_hashes (obj) + elf_tdata (obj)->symtab_hdr.sh_info;
}
/* Initialize an entry in the link hash table. */ /* Initialize an entry in the link hash table. */
static struct bfd_hash_entry * static struct bfd_hash_entry *
@@ -501,6 +477,7 @@ hppa64_elf_local_refcounts (bfd *abfd)
counts. Done this way to save polluting elf_obj_tdata counts. Done this way to save polluting elf_obj_tdata
with another target specific pointer. */ with another target specific pointer. */
size = symtab_hdr->sh_info; size = symtab_hdr->sh_info;
BFD_ASSERT (size);
size *= 3 * sizeof (bfd_signed_vma); size *= 3 * sizeof (bfd_signed_vma);
local_refcounts = bfd_zalloc (abfd, size); local_refcounts = bfd_zalloc (abfd, size);
elf_local_got_refcounts (abfd) = local_refcounts; elf_local_got_refcounts (abfd) = local_refcounts;
@@ -776,24 +753,15 @@ elf64_hppa_check_relocs (bfd *abfd,
/* This is a simple OPD entry. */ /* This is a simple OPD entry. */
case R_PARISC_FPTR64: case R_PARISC_FPTR64:
if (bfd_link_pic (info) || maybe_dynamic) if (bfd_link_pic (info) || maybe_dynamic)
need_entry = (NEED_OPD | NEED_PLT | NEED_DYNREL); need_entry = (NEED_OPD | NEED_DYNREL);
else else
need_entry = (NEED_OPD | NEED_PLT); need_entry = (NEED_OPD);
dynrel_type = R_PARISC_FPTR64; dynrel_type = R_PARISC_FPTR64;
break; break;
/* Add more cases as needed. */ /* Add more cases as needed. */
} }
/* We may need this information later for OPD. */
if (hh)
{
/* Stash away enough information to be able to find this symbol
regardless of whether or not it is local or global. */
hh->owner = abfd;
hh->sym_indx = r_symndx;
}
if (!need_entry) if (!need_entry)
continue; continue;
@@ -900,18 +868,9 @@ elf64_hppa_check_relocs (bfd *abfd,
/* Add symbol to dynamic symbol table. */ /* Add symbol to dynamic symbol table. */
if (hh != NULL if (hh != NULL
&& hh->eh.dynindx == -1
&& bfd_link_pic (info) && bfd_link_pic (info)
&& ! (bfd_elf_link_record_local_dynamic_symbol && ! (bfd_elf_link_record_dynamic_symbol (info, &hh->eh)))
(info, abfd, r_symndx)))
goto err_out;
/* If we are building a shared library and we just recorded
a dynamic R_PARISC_FPTR64 relocation, then make sure the
section symbol for this section ends up in the dynamic
symbol table. */
if (bfd_link_pic (info) && dynrel_type == R_PARISC_FPTR64
&& ! (bfd_elf_link_record_local_dynamic_symbol
(info, abfd, sec_symndx)))
goto err_out; goto err_out;
} }
} }
@@ -993,25 +952,6 @@ allocate_global_data_dlt (struct elf_link_hash_entry *eh, void *data)
if (hh->want_dlt) if (hh->want_dlt)
{ {
if (bfd_link_pic (x->info))
{
/* Possibly add the symbol to the local dynamic symbol
table since we might need to create a dynamic relocation
against it. */
if (eh->dynindx == -1 && eh->type != STT_PARISC_MILLI)
{
if (!hh->owner)
{
hh->owner = eh->root.u.def.section->owner;
hh->sym_indx = global_sym_index (eh);
}
if (! (bfd_elf_link_record_local_dynamic_symbol
(x->info, hh->owner, hh->sym_indx)))
return false;
}
}
hh->dlt_offset = x->ofs; hh->dlt_offset = x->ofs;
x->ofs += DLT_ENTRY_SIZE; x->ofs += DLT_ENTRY_SIZE;
} }
@@ -1106,24 +1046,6 @@ allocate_global_data_opd (struct elf_link_hash_entry *eh, void *data)
|| hh->eh.root.type == bfd_link_hash_defined || hh->eh.root.type == bfd_link_hash_defined
|| hh->eh.root.type == bfd_link_hash_defweak) || hh->eh.root.type == bfd_link_hash_defweak)
{ {
/* If we are creating a shared library, then we will have to
create a runtime relocation for the symbol to properly
initialize the .opd entry. Make sure the symbol gets
added to the dynamic symbol table. */
if (bfd_link_pic (x->info) && hh->eh.dynindx == -1)
{
/* PR 6511: Default to using the dynamic symbol table. */
if (!hh->owner)
{
hh->owner = eh->root.u.def.section->owner;
hh->sym_indx = global_sym_index (eh);
}
if (!bfd_elf_link_record_local_dynamic_symbol
(x->info, hh->owner, hh->sym_indx))
return false;
}
hh->opd_offset = x->ofs; hh->opd_offset = x->ofs;
x->ofs += OPD_ENTRY_SIZE; x->ofs += OPD_ENTRY_SIZE;
} }
@@ -1710,7 +1632,12 @@ elf64_hppa_late_size_sections (bfd *output_bfd, struct bfd_link_info *info)
} }
/* Add __text_seg section symbol to dynamic table. */ /* Add __text_seg section symbol to dynamic table. */
if (bfd_link_pic (info) && !hppa_info->text_segment) if (bfd_link_pic (info) && !hppa_info->text_hash_entry)
{
asection *s;
s = bfd_get_section_by_name (info->output_bfd, ".dynamic");
if (s != NULL)
{ {
struct elf_link_hash_entry *nh; struct elf_link_hash_entry *nh;
@@ -1718,10 +1645,6 @@ elf64_hppa_late_size_sections (bfd *output_bfd, struct bfd_link_info *info)
"__text_seg", true, false, false); "__text_seg", true, false, false);
if (nh != NULL) if (nh != NULL)
{ {
asection *s;
s = bfd_get_section_by_name (info->output_bfd, ".dynamic");
nh->type = STT_SECTION; nh->type = STT_SECTION;
nh->root.type = bfd_link_hash_defined; nh->root.type = bfd_link_hash_defined;
nh->root.u.def.value = 0; nh->root.u.def.value = 0;
@@ -1729,12 +1652,22 @@ elf64_hppa_late_size_sections (bfd *output_bfd, struct bfd_link_info *info)
nh->forced_local = 1; nh->forced_local = 1;
nh->other = STV_DEFAULT; nh->other = STV_DEFAULT;
bfd_elf_link_record_dynamic_symbol (info, nh); bfd_elf_link_record_dynamic_symbol (info, nh);
hppa_info->text_segment = nh; hppa_info->text_hash_entry = nh;
}
} }
} }
/* Add __data_seg section symbol to dynamic table. */ /* Add __data_seg section symbol to dynamic table. */
if (bfd_link_pic (info) && !hppa_info->data_segment) if (bfd_link_pic (info) && !hppa_info->data_hash_entry)
{
asection *s;
/* The .data section isn't always present nor is it always the
first section in the data segment. It's too early to call
bfd_map_over_sections, so we assume we don't need any data
segment relocations when .data is missing. */
s = bfd_get_section_by_name (info->output_bfd, ".data");
if (s != NULL)
{ {
struct elf_link_hash_entry *nh; struct elf_link_hash_entry *nh;
@@ -1742,10 +1675,6 @@ elf64_hppa_late_size_sections (bfd *output_bfd, struct bfd_link_info *info)
"__data_seg", true, false, false); "__data_seg", true, false, false);
if (nh != NULL) if (nh != NULL)
{ {
asection *s;
s = bfd_get_section_by_name (info->output_bfd, ".data");
nh->type = STT_SECTION; nh->type = STT_SECTION;
nh->root.type = bfd_link_hash_defined; nh->root.type = bfd_link_hash_defined;
nh->root.u.def.value = 0; nh->root.u.def.value = 0;
@@ -1753,7 +1682,8 @@ elf64_hppa_late_size_sections (bfd *output_bfd, struct bfd_link_info *info)
nh->forced_local = 1; nh->forced_local = 1;
nh->other = STV_DEFAULT; nh->other = STV_DEFAULT;
bfd_elf_link_record_dynamic_symbol (info, nh); bfd_elf_link_record_dynamic_symbol (info, nh);
hppa_info->data_segment = nh; hppa_info->data_hash_entry = nh;
}
} }
} }
@@ -2201,7 +2131,7 @@ elf64_hppa_finalize_opd (struct elf_link_hash_entry *eh, void *data)
+ eh->root.u.def.section->output_offset); + eh->root.u.def.section->output_offset);
/* Compute the base address of the segment with this symbol. */ /* Compute the base address of the segment with this symbol. */
sec = hppa_info->text_segment->root.u.def.section; sec = hppa_info->text_hash_entry->root.u.def.section;
value2 = sec->output_section->vma; value2 = sec->output_section->vma;
/* Compute the difference between the symbol and the text segment /* Compute the difference between the symbol and the text segment
@@ -2211,7 +2141,7 @@ elf64_hppa_finalize_opd (struct elf_link_hash_entry *eh, void *data)
/* The result becomes the addend of the relocation. */ /* The result becomes the addend of the relocation. */
rel.r_addend += value; rel.r_addend += value;
dynindx = hppa_info->text_segment->dynindx; dynindx = hppa_info->text_hash_entry->dynindx;
BFD_ASSERT (dynindx != -1); BFD_ASSERT (dynindx != -1);
rel.r_info = ELF64_R_INFO (dynindx, R_PARISC_EPLT); rel.r_info = ELF64_R_INFO (dynindx, R_PARISC_EPLT);
@@ -2284,16 +2214,34 @@ elf64_hppa_finalize_dlt (struct elf_link_hash_entry *eh, void *data)
Elf_Internal_Rela rel; Elf_Internal_Rela rel;
bfd_byte *loc; bfd_byte *loc;
int dynindx; int dynindx;
asection *sec;
bfd_vma value, value2;
/* We may need to do a relocation against a local symbol, in if (eh->dynindx == -1)
which case we have to look up it's dynamic symbol index off {
the local symbol hash table. */ value = (eh->root.u.def.value
if (eh && eh->dynindx != -1) + eh->root.u.def.section->output_section->vma
dynindx = eh->dynindx; + eh->root.u.def.section->output_offset);
if (eh->root.u.def.section->flags & SEC_READONLY)
{
sec = hppa_info->text_hash_entry->root.u.def.section;
value2 = sec->output_section->vma;
dynindx = hppa_info->text_hash_entry->dynindx;
}
else else
dynindx {
= _bfd_elf_link_lookup_local_dynindx (info, hh->owner, sec = hppa_info->data_hash_entry->root.u.def.section;
hh->sym_indx); value2 = sec->output_section->vma;
dynindx = hppa_info->data_hash_entry->dynindx;
}
rel.r_addend = value - value2;
}
else
{
dynindx = eh->dynindx;
rel.r_addend = 0;
}
/* Create a dynamic relocation for this entry. Do include the output /* Create a dynamic relocation for this entry. Do include the output
offset of the DLT entry since we need an absolute address in the offset of the DLT entry since we need an absolute address in the
@@ -2304,7 +2252,6 @@ elf64_hppa_finalize_dlt (struct elf_link_hash_entry *eh, void *data)
rel.r_info = ELF64_R_INFO (dynindx, R_PARISC_FPTR64); rel.r_info = ELF64_R_INFO (dynindx, R_PARISC_FPTR64);
else else
rel.r_info = ELF64_R_INFO (dynindx, R_PARISC_DIR64); rel.r_info = ELF64_R_INFO (dynindx, R_PARISC_DIR64);
rel.r_addend = 0;
loc = sdltrel->contents; loc = sdltrel->contents;
loc += sdltrel->reloc_count++ * sizeof (Elf64_External_Rela); loc += sdltrel->reloc_count++ * sizeof (Elf64_External_Rela);
@@ -2342,16 +2289,6 @@ elf64_hppa_finalize_dynreloc (struct elf_link_hash_entry *eh,
struct elf64_hppa_dyn_reloc_entry *rent; struct elf64_hppa_dyn_reloc_entry *rent;
int dynindx; int dynindx;
/* We may need to do a relocation against a local symbol, in
which case we have to look up it's dynamic symbol index off
the local symbol hash table. */
if (eh->dynindx != -1)
dynindx = eh->dynindx;
else
dynindx
= _bfd_elf_link_lookup_local_dynindx (info, hh->owner,
hh->sym_indx);
for (rent = hh->reloc_entries; rent; rent = rent->next) for (rent = hh->reloc_entries; rent; rent = rent->next)
{ {
Elf_Internal_Rela rel; Elf_Internal_Rela rel;
@@ -2393,6 +2330,7 @@ elf64_hppa_finalize_dynreloc (struct elf_link_hash_entry *eh,
if (bfd_link_pic (info) if (bfd_link_pic (info)
&& rent->type == R_PARISC_FPTR64 && hh->want_opd) && rent->type == R_PARISC_FPTR64 && hh->want_opd)
{ {
asection *sec;
bfd_vma value, value2; bfd_vma value, value2;
/* First compute the address of the opd entry for this symbol. */ /* First compute the address of the opd entry for this symbol. */
@@ -2400,27 +2338,59 @@ elf64_hppa_finalize_dynreloc (struct elf_link_hash_entry *eh,
+ hppa_info->opd_sec->output_section->vma + hppa_info->opd_sec->output_section->vma
+ hppa_info->opd_sec->output_offset); + hppa_info->opd_sec->output_offset);
/* Compute the value of the start of the section with if (hh->eh.dynindx != -1)
the relocation. */ {
value2 = (rent->sec->output_section->vma value2 = value;
+ rent->sec->output_offset); dynindx = hh->eh.dynindx;
}
else if (rent->sec->flags & SEC_READONLY)
{
sec = hppa_info->text_hash_entry->root.u.def.section;
value2 = sec->output_section->vma;
dynindx = hppa_info->text_hash_entry->dynindx;
}
else
{
sec = hppa_info->data_hash_entry->root.u.def.section;
value2 = sec->output_section->vma;
dynindx = hppa_info->data_hash_entry->dynindx;
}
/* Compute the difference between the start of the section /* Compute the difference between the start of the section
with the relocation and the opd entry. */ with the relocation and the opd entry. */
value -= value2; value -= value2;
/* The result becomes the addend of the relocation. */ /* The result becomes the addend of the relocation. */
rel.r_addend = value; rel.r_addend = value + rent->addend;
}
else if (eh->dynindx == -1)
{
asection *sec;
bfd_vma value, value2;
/* The section symbol becomes the symbol for the dynamic value = (eh->root.u.def.value
relocation. */ + eh->root.u.def.section->output_section->vma
dynindx + eh->root.u.def.section->output_offset);
= _bfd_elf_link_lookup_local_dynindx (info,
rent->sec->owner, if (eh->root.u.def.section->flags & SEC_READONLY)
rent->sec_symndx); {
sec = hppa_info->text_hash_entry->root.u.def.section;
value2 = sec->output_section->vma;
dynindx = hppa_info->text_hash_entry->dynindx;
} }
else else
{
sec = hppa_info->data_hash_entry->root.u.def.section;
value2 = sec->output_section->vma;
dynindx = hppa_info->data_hash_entry->dynindx;
}
rel.r_addend = value - value2 + rent->addend;
}
else
{
dynindx = eh->dynindx;
rel.r_addend = rent->addend; rel.r_addend = rent->addend;
}
BFD_ASSERT (dynindx != -1); BFD_ASSERT (dynindx != -1);
rel.r_info = ELF64_R_INFO (dynindx, rent->type); rel.r_info = ELF64_R_INFO (dynindx, rent->type);
@@ -3193,15 +3163,16 @@ elf_hppa_final_link_relocate (Elf_Internal_Rela *rel,
unsigned int r_type = howto->type; unsigned int r_type = howto->type;
bfd_byte *hit_data = contents + offset; bfd_byte *hit_data = contents + offset;
/* Dynamic relocs are not propagated for SEC_DEBUGGING
sections because such sections are not SEC_ALLOC and
thus ld.so will not process them. */
if (bfd_link_pic (info)
&& (input_section->flags & SEC_DEBUGGING) != 0)
return bfd_reloc_ok;
if (hppa_info == NULL) if (hppa_info == NULL)
return bfd_reloc_notsupported; return bfd_reloc_notsupported;
/* Initialize the segment base values. Needed for EPLT and SEGREL
relocations. */
if (hppa_info->text_segment_base == (bfd_vma) -1)
bfd_map_over_sections (output_bfd, elf_hppa_record_segment_addrs,
hppa_info);
symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
local_offsets = elf_local_got_offsets (input_bfd); local_offsets = elf_local_got_offsets (input_bfd);
insn = bfd_get_32 (input_bfd, hit_data); insn = bfd_get_32 (input_bfd, hit_data);
@@ -3334,6 +3305,13 @@ elf_hppa_final_link_relocate (Elf_Internal_Rela *rel,
case R_PARISC_LTOFF16DF: case R_PARISC_LTOFF16DF:
{ {
bfd_vma off; bfd_vma off;
bfd_vma relocation = value;
asection *sopd, *sopdrel;
bool need_dlt_reloc = false;
bool need_opd_reloc = false;
sopd = hppa_info->opd_sec;
sopdrel = hppa_info->opd_rel_sec;
/* If this relocation was against a local symbol, then we still /* If this relocation was against a local symbol, then we still
have not set up the DLT entry (it's not convenient to do so have not set up the DLT entry (it's not convenient to do so
@@ -3375,26 +3353,74 @@ elf_hppa_final_link_relocate (Elf_Internal_Rela *rel,
{ {
local_opd_offsets[r_symndx] |= 1; local_opd_offsets[r_symndx] |= 1;
/* If we are generating a shared library, we need
a relocation for the local symbol. */
if (bfd_link_pic (info))
need_opd_reloc = true;
/* The first two words of an .opd entry are zero. */ /* The first two words of an .opd entry are zero. */
memset (hppa_info->opd_sec->contents + off, 0, 16); memset (sopd->contents + off, 0, 16);
/* The next word is the address of the function. */ /* The next word is the address of the function. */
bfd_put_64 (hppa_info->opd_sec->owner, value + addend, bfd_put_64 (sopd->owner, value + addend,
(hppa_info->opd_sec->contents + off + 16)); sopd->contents + off + 16);
/* The last word is our local __gp value. */ /* The last word is our local __gp value. */
value = _bfd_get_gp_value (info->output_bfd); value = _bfd_get_gp_value (info->output_bfd);
bfd_put_64 (hppa_info->opd_sec->owner, value, bfd_put_64 (sopd->owner, value,
(hppa_info->opd_sec->contents + off + 24)); sopd->contents + off + 24);
} }
/* The DLT value is the address of the .opd entry. */ /* The OPD value is the address of the .opd entry. */
value = (off value = (off
+ hppa_info->opd_sec->output_offset + sopd->output_offset
+ hppa_info->opd_sec->output_section->vma); + sopd->output_section->vma);
addend = 0; addend = 0;
} }
if (need_opd_reloc)
{
Elf_Internal_Rela rela;
bfd_byte *loc;
int dynindx;
asection *sec;
/* The offset of this relocation is the absolute address
of the .opd entry for this symbol. */
rela.r_offset = (off
+ sopd->output_offset
+ sopd->output_section->vma);
/* Select base segment. */
if (sym_sec->flags & SEC_READONLY)
{
sec = hppa_info->text_hash_entry->root.u.def.section;
dynindx = hppa_info->text_hash_entry->dynindx;
}
else
{
sec = hppa_info->data_hash_entry->root.u.def.section;
dynindx = hppa_info->data_hash_entry->dynindx;
}
/* Adjust the value with the difference between the
symbol's address and the base segment's address. */
value += (relocation + addend
- sec->output_offset
- sec->output_section->vma);
/* The result becomes the addend of the relocation. */
rela.r_addend = value;
dynindx = hppa_info->text_hash_entry->dynindx;
BFD_ASSERT (dynindx != -1);
rela.r_info = ELF64_R_INFO (dynindx, R_PARISC_EPLT);
loc = sopdrel->contents;
loc += sopdrel->reloc_count++ * sizeof (Elf64_External_Rela);
bfd_elf64_swap_reloca_out (info->output_bfd, &rela, loc);
}
local_dlt_offsets = local_offsets; local_dlt_offsets = local_offsets;
off = local_dlt_offsets[r_symndx]; off = local_dlt_offsets[r_symndx];
@@ -3406,6 +3432,12 @@ elf_hppa_final_link_relocate (Elf_Internal_Rela *rel,
else else
{ {
local_dlt_offsets[r_symndx] |= 1; local_dlt_offsets[r_symndx] |= 1;
/* If we are generating a shared library, we need
a relocation for the local symbol. */
if (bfd_link_pic (info))
need_dlt_reloc = true;
bfd_put_64 (hppa_info->dlt_sec->owner, bfd_put_64 (hppa_info->dlt_sec->owner,
value + addend, value + addend,
hppa_info->dlt_sec->contents + off); hppa_info->dlt_sec->contents + off);
@@ -3445,6 +3477,50 @@ elf_hppa_final_link_relocate (Elf_Internal_Rela *rel,
value = hppa_field_adjust (value, 0, e_rsel); value = hppa_field_adjust (value, 0, e_rsel);
insn = elf_hppa_relocate_insn (insn, (int) value, r_type); insn = elf_hppa_relocate_insn (insn, (int) value, r_type);
if (need_dlt_reloc)
{
Elf_Internal_Rela rela;
bfd_byte *loc;
int dynindx;
asection *sec;
asection *sdlt, *sdltrel;
sdlt = hppa_info->dlt_sec;
sdltrel = hppa_info->dlt_rel_sec;
/* The offset of this relocation is the absolute address
of the .dlt entry. */
rela.r_offset = (off + sdlt->output_offset
+ sdlt->output_section->vma);
if (sym_sec->flags & SEC_READONLY)
{
sec = hppa_info->text_hash_entry->root.u.def.section;
dynindx = hppa_info->text_hash_entry->dynindx;
}
else
{
sec = hppa_info->data_hash_entry->root.u.def.section;
dynindx = hppa_info->data_hash_entry->dynindx;
}
/* Adjust value using the difference of the symbol's
location and the section symbol's address. */
value += (relocation + addend
- sec->output_offset
- sec->output_section->vma);
/* The result becomes the addend of the relocation. */
rela.r_addend = value;
BFD_ASSERT (dynindx != -1);
rela.r_info = ELF64_R_INFO (dynindx, R_PARISC_DIR64);
loc = sdltrel->contents;
loc += sdltrel->reloc_count++ * sizeof (Elf64_External_Rela);
bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
}
break; break;
} }
@@ -3691,6 +3767,7 @@ elf_hppa_final_link_relocate (Elf_Internal_Rela *rel,
bfd_vma relocation = value; bfd_vma relocation = value;
asection *sopd; asection *sopd;
asection *sopdrel; asection *sopdrel;
bool need_opd_reloc = false;
sopd = hppa_info->opd_sec; sopd = hppa_info->opd_sec;
sopdrel = hppa_info->opd_rel_sec; sopdrel = hppa_info->opd_rel_sec;
@@ -3701,7 +3778,7 @@ elf_hppa_final_link_relocate (Elf_Internal_Rela *rel,
{ {
bfd_vma *local_opd_offsets; bfd_vma *local_opd_offsets;
if (local_offsets == NULL) if (local_offsets == NULL || symtab_hdr->sh_info == 0)
abort (); abort ();
local_opd_offsets = local_offsets + 2 * symtab_hdr->sh_info; local_opd_offsets = local_offsets + 2 * symtab_hdr->sh_info;
@@ -3716,6 +3793,13 @@ elf_hppa_final_link_relocate (Elf_Internal_Rela *rel,
} }
else else
{ {
local_opd_offsets[r_symndx] |= 1;
/* If we are generating a shared library, we need
a relocation for the local symbol. */
if (bfd_link_pic (info))
need_opd_reloc = true;
/* The first two words of an .opd entry are zero. */ /* The first two words of an .opd entry are zero. */
memset (hppa_info->opd_sec->contents + off, 0, 16); memset (hppa_info->opd_sec->contents + off, 0, 16);
@@ -3740,12 +3824,10 @@ elf_hppa_final_link_relocate (Elf_Internal_Rela *rel,
bfd_put_64 (output_bfd, value, hit_data); bfd_put_64 (output_bfd, value, hit_data);
/* If we are generating a shared library, we must generate an if (need_opd_reloc)
EPLT relocation for the symbol. */
if (hh == NULL && bfd_link_pic (info))
{ {
Elf_Internal_Rela rela; Elf_Internal_Rela rela;
bfd_byte *loc, *locend; bfd_byte *loc;
int dynindx; int dynindx;
asection *sec; asection *sec;
@@ -3754,28 +3836,27 @@ elf_hppa_final_link_relocate (Elf_Internal_Rela *rel,
rela.r_offset = (off + sopd->output_offset rela.r_offset = (off + sopd->output_offset
+ sopd->output_section->vma); + sopd->output_section->vma);
/* Compute the difference between the symbol address /* Select base segment. */
and the test segment base address. */ if (sym_sec->flags & SEC_READONLY)
sec = hppa_info->text_segment->root.u.def.section; {
value = (relocation + addend - sec->output_section->vma); sec = hppa_info->text_hash_entry->root.u.def.section;
dynindx = hppa_info->text_hash_entry->dynindx;
}
else
{
sec = hppa_info->data_hash_entry->root.u.def.section;
dynindx = hppa_info->data_hash_entry->dynindx;
}
/* Compute the difference between the symbol's address
and the base segment's address. */
value += (relocation + addend
- sec->output_offset
- sec->output_section->vma);
/* The result becomes the addend of the relocation. */ /* The result becomes the addend of the relocation. */
rela.r_addend = value; rela.r_addend = value;
/* Ugh, the EPLT relocations must be unique! */
locend = (sopdrel->contents
+ sopdrel->reloc_count * sizeof (Elf64_External_Rela));
for (loc = sopdrel->contents; loc < locend;
loc += sizeof (Elf64_External_Rela))
{
Elf_Internal_Rela rela1;
bfd_elf64_swap_reloca_in (info->output_bfd, loc, &rela1);
if (rela.r_addend == rela1.r_addend)
return bfd_reloc_ok;
}
dynindx = hppa_info->text_segment->dynindx;
BFD_ASSERT (dynindx != -1); BFD_ASSERT (dynindx != -1);
rela.r_info = ELF64_R_INFO (dynindx, R_PARISC_EPLT); rela.r_info = ELF64_R_INFO (dynindx, R_PARISC_EPLT);
@@ -3796,6 +3877,11 @@ elf_hppa_final_link_relocate (Elf_Internal_Rela *rel,
case R_PARISC_SEGREL32: case R_PARISC_SEGREL32:
case R_PARISC_SEGREL64: case R_PARISC_SEGREL64:
{ {
/* Initialize the segment base values. */
if (hppa_info->text_segment_base == (bfd_vma) -1)
bfd_map_over_sections (output_bfd, elf_hppa_record_segment_addrs,
hppa_info);
/* VALUE holds the absolute address. We want to include the /* VALUE holds the absolute address. We want to include the
addend, then turn it into a segment relative address. addend, then turn it into a segment relative address.