aboutsummaryrefslogtreecommitdiff
path: root/bfd
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2022-01-26 10:31:36 +1030
committerAlan Modra <amodra@gmail.com>2022-02-03 13:40:41 +1030
commit3a3a4c1fe4ccb1914d29fbf8f5930d55aacec78f (patch)
treed70433071d319f0d23a4f09aa62380be09291430 /bfd
parent36a13a0e62bc672f59c6d27bc2b963edee32b488 (diff)
downloadbinutils-3a3a4c1fe4ccb1914d29fbf8f5930d55aacec78f.zip
binutils-3a3a4c1fe4ccb1914d29fbf8f5930d55aacec78f.tar.gz
binutils-3a3a4c1fe4ccb1914d29fbf8f5930d55aacec78f.tar.bz2
PowerPC64 treatment of absolute symbols
Supporting -static-pie on PowerPC64 requires the linker to properly treat SHN_ABS symbols for cases like glibc's _nl_current_LC_CTYPE_used absolute symbol. I've been slow to fix the linker on powerpc because there is some chance that this will break some shared libraries or PIEs. bfd/ * elf64-ppc.c (ppc64_elf_check_relocs): Consolidate local sym handling code. Don't count dyn relocs against non-dynamic absolute symbols. (dec_dynrel_count): Adjust to suit. (ppc64_elf_edit_toc): Don't remove entries for absolute symbols when pic. (allocate_got): Don't allocate space for got relocs against non-dynamic absolute syms. (ppc64_elf_layout_multitoc): Likewise. (got_and_plt_relr): Likewise. (ppc64_elf_size_dynamic_sections): Likewise for local got. (got_and_plt_relr_for_local_syms): Likewise. (ppc64_elf_size_stubs): Don't allocate space for relr either. (ppc64_elf_relocate_section): Don't write relocs against non-dynamic absolute symbols. Don't optimise got and toc code sequences loading absolute symbol entries. ld/ * testsuite/ld-powerpc/abs-reloc.s, * testsuite/ld-powerpc/abs-static.d, * testsuite/ld-powerpc/abs-static.r, * testsuite/ld-powerpc/abs-pie.d, * testsuite/ld-powerpc/abs-pie.r, * testsuite/ld-powerpc/abs-shared.d, * testsuite/ld-powerpc/abs-shared.r, * testsuite/ld-powerpc/abs-pie-relr.d, * testsuite/ld-powerpc/abs-pie-relr.r, * testsuite/ld-powerpc/abs-shared-relr.d, * testsuite/ld-powerpc/abs-shared-relr.r: New tests. * testsuite/ld-powerpc/powerpc.exp: Run them.
Diffstat (limited to 'bfd')
-rw-r--r--bfd/elf64-ppc.c188
1 files changed, 126 insertions, 62 deletions
diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c
index b4fa4ae..7223c49 100644
--- a/bfd/elf64-ppc.c
+++ b/bfd/elf64-ppc.c
@@ -4779,6 +4779,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
{
unsigned long r_symndx;
struct elf_link_hash_entry *h;
+ Elf_Internal_Sym *isym;
enum elf_ppc64_reloc_type r_type;
int tls_type;
struct _ppc64_elf_section_data *ppc64_sec;
@@ -4786,9 +4787,15 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
r_symndx = ELF64_R_SYM (rel->r_info);
if (r_symndx < symtab_hdr->sh_info)
- h = NULL;
+ {
+ h = NULL;
+ isym = bfd_sym_from_r_symndx (&htab->elf.sym_cache, abfd, r_symndx);
+ if (isym == NULL)
+ return false;
+ }
else
{
+ isym = NULL;
h = sym_hashes[r_symndx - symtab_hdr->sh_info];
h = elf_follow_link (h);
@@ -4859,11 +4866,6 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
}
else
{
- Elf_Internal_Sym *isym = bfd_sym_from_r_symndx (&htab->elf.sym_cache,
- abfd, r_symndx);
- if (isym == NULL)
- return false;
-
if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
{
ifunc = update_local_sym_info (abfd, symtab_hdr, r_symndx,
@@ -5127,16 +5129,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
dest = h->root.u.def.section;
}
else
- {
- Elf_Internal_Sym *isym;
-
- isym = bfd_sym_from_r_symndx (&htab->elf.sym_cache,
- abfd, r_symndx);
- if (isym == NULL)
- return false;
-
- dest = bfd_section_from_elf_index (abfd, isym->st_shndx);
- }
+ dest = bfd_section_from_elf_index (abfd, isym->st_shndx);
if (dest != sec)
ppc64_elf_section_data (sec)->has_14bit_branch = 1;
@@ -5352,11 +5345,13 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
dodyn:
if ((h != NULL
&& (h->root.type == bfd_link_hash_defweak
- || !h->def_regular))
+ || (!h->def_regular && !h->root.ldscript_def)))
|| (h != NULL
- && !bfd_link_executable (info)
- && !SYMBOLIC_BIND (info, h))
+ && !SYMBOL_REFERENCES_LOCAL (info, h))
|| (bfd_link_pic (info)
+ && (h != NULL
+ ? !bfd_is_abs_symbol (&h->root)
+ : isym->st_shndx != SHN_ABS)
&& must_be_dyn_reloc (info, r_type))
|| (!bfd_link_pic (info)
&& ifunc != NULL))
@@ -5404,20 +5399,12 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
}
else
{
- /* Track dynamic relocs needed for local syms too.
- We really need local syms available to do this
- easily. Oh well. */
+ /* Track dynamic relocs needed for local syms too. */
struct ppc_local_dyn_relocs *p;
struct ppc_local_dyn_relocs **head;
bool is_ifunc;
asection *s;
void *vpp;
- Elf_Internal_Sym *isym;
-
- isym = bfd_sym_from_r_symndx (&htab->elf.sym_cache,
- abfd, r_symndx);
- if (isym == NULL)
- return false;
s = bfd_section_from_elf_index (abfd, isym->st_shndx);
if (s == NULL)
@@ -7256,11 +7243,13 @@ dec_dynrel_count (const Elf_Internal_Rela *rel,
if ((h != NULL
&& (h->root.type == bfd_link_hash_defweak
- || !h->def_regular))
+ || (!h->def_regular && !h->root.ldscript_def)))
|| (h != NULL
- && !bfd_link_executable (info)
- && !SYMBOLIC_BIND (info, h))
+ && !SYMBOL_REFERENCES_LOCAL (info, h))
|| (bfd_link_pic (info)
+ && (h != NULL
+ ? !bfd_is_abs_symbol (&h->root)
+ : sym_sec != bfd_abs_section_ptr)
&& must_be_dyn_reloc (info, r_type))
|| (!bfd_link_pic (info)
&& (h != NULL
@@ -9065,7 +9054,9 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
|| discarded_section (sym_sec))
continue;
- if (!SYMBOL_REFERENCES_LOCAL (info, h))
+ if (!SYMBOL_REFERENCES_LOCAL (info, h)
+ || (bfd_link_pic (info)
+ && sym_sec == bfd_abs_section_ptr))
continue;
if (h != NULL)
@@ -9647,7 +9638,9 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
if ((h ? h->type : ELF_ST_TYPE (sym->st_info)) == STT_GNU_IFUNC)
continue;
- if (!SYMBOL_REFERENCES_LOCAL (info, h))
+ if (!SYMBOL_REFERENCES_LOCAL (info, h)
+ || (bfd_link_pic (info)
+ && sym_sec == bfd_abs_section_ptr))
continue;
if (h != NULL)
@@ -9781,7 +9774,8 @@ allocate_got (struct elf_link_hash_entry *h,
&& (gent->tls_type == 0
? !info->enable_dt_relr
: !(bfd_link_executable (info)
- && SYMBOL_REFERENCES_LOCAL (info, h))))
+ && SYMBOL_REFERENCES_LOCAL (info, h)))
+ && !bfd_is_abs_symbol (&h->root))
|| (htab->elf.dynamic_sections_created
&& h->dynindx != -1
&& !SYMBOL_REFERENCES_LOCAL (info, h)))
@@ -10246,6 +10240,8 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
unsigned char *lgot_masks;
bfd_size_type locsymcount;
Elf_Internal_Shdr *symtab_hdr;
+ Elf_Internal_Sym *local_syms;
+ Elf_Internal_Sym *isym;
if (!is_ppc64_elf (ibfd))
continue;
@@ -10296,8 +10292,22 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
local_plt = (struct plt_entry **) end_lgot_ents;
end_local_plt = local_plt + locsymcount;
lgot_masks = (unsigned char *) end_local_plt;
+ local_syms = NULL;
+ if (bfd_link_pic (info))
+ {
+ local_syms = (Elf_Internal_Sym *) symtab_hdr->contents;
+ if (local_syms == NULL && locsymcount != 0)
+ {
+ local_syms = bfd_elf_get_elf_syms (ibfd, symtab_hdr, locsymcount,
+ 0, NULL, NULL, NULL);
+ if (local_syms == NULL)
+ return false;
+ }
+ }
s = ppc64_elf_tdata (ibfd)->got;
- for (; lgot_ents < end_lgot_ents; ++lgot_ents, ++lgot_masks)
+ for (isym = local_syms;
+ lgot_ents < end_lgot_ents;
+ ++lgot_ents, ++lgot_masks, isym != NULL && isym++)
{
struct got_entry **pent, *ent;
@@ -10330,7 +10340,8 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
else if (bfd_link_pic (info)
&& (ent->tls_type == 0
? !info->enable_dt_relr
- : !bfd_link_executable (info)))
+ : !bfd_link_executable (info))
+ && isym->st_shndx != SHN_ABS)
{
asection *srel = ppc64_elf_tdata (ibfd)->relgot;
srel->size += rel_size;
@@ -10341,6 +10352,14 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
else
*pent = ent->next;
}
+ if (local_syms != NULL
+ && symtab_hdr->contents != (unsigned char *) local_syms)
+ {
+ if (!info->keep_memory)
+ free (local_syms);
+ else
+ symtab_hdr->contents = (unsigned char *) local_syms;
+ }
/* Allocate space for plt calls to local syms. */
lgot_masks = (unsigned char *) end_local_plt;
@@ -12793,6 +12812,8 @@ ppc64_elf_layout_multitoc (struct bfd_link_info *info)
bfd_size_type locsymcount;
Elf_Internal_Shdr *symtab_hdr;
asection *s;
+ Elf_Internal_Sym *local_syms;
+ Elf_Internal_Sym *isym;
if (!is_ppc64_elf (ibfd))
continue;
@@ -12807,8 +12828,22 @@ ppc64_elf_layout_multitoc (struct bfd_link_info *info)
local_plt = (struct plt_entry **) end_lgot_ents;
end_local_plt = local_plt + locsymcount;
lgot_masks = (unsigned char *) end_local_plt;
+ local_syms = NULL;
+ if (bfd_link_pic (info))
+ {
+ local_syms = (Elf_Internal_Sym *) symtab_hdr->contents;
+ if (local_syms == NULL && locsymcount != 0)
+ {
+ local_syms = bfd_elf_get_elf_syms (ibfd, symtab_hdr, locsymcount,
+ 0, NULL, NULL, NULL);
+ if (local_syms == NULL)
+ return false;
+ }
+ }
s = ppc64_elf_tdata (ibfd)->got;
- for (; lgot_ents < end_lgot_ents; ++lgot_ents, ++lgot_masks)
+ for (isym = local_syms;
+ lgot_ents < end_lgot_ents;
+ ++lgot_ents, ++lgot_masks, isym != NULL && isym++)
{
struct got_entry *ent;
@@ -12832,7 +12867,8 @@ ppc64_elf_layout_multitoc (struct bfd_link_info *info)
else if (bfd_link_pic (info)
&& (ent->tls_type == 0
? !info->enable_dt_relr
- : !bfd_link_executable (info)))
+ : !bfd_link_executable (info))
+ && isym->st_shndx != SHN_ABS)
{
asection *srel = ppc64_elf_tdata (ibfd)->relgot;
srel->size += rel_size;
@@ -13422,7 +13458,8 @@ got_and_plt_relr_for_local_syms (struct bfd_link_info *info)
struct plt_entry **local_plt, **lplt, **end_local_plt;
Elf_Internal_Shdr *symtab_hdr;
bfd_size_type locsymcount;
- Elf_Internal_Sym *local_syms = NULL;
+ Elf_Internal_Sym *local_syms;
+ Elf_Internal_Sym *isym;
struct plt_entry *pent;
struct got_entry *gent;
@@ -13435,14 +13472,25 @@ got_and_plt_relr_for_local_syms (struct bfd_link_info *info)
symtab_hdr = &elf_symtab_hdr (ibfd);
locsymcount = symtab_hdr->sh_info;
+ local_syms = (Elf_Internal_Sym *) symtab_hdr->contents;
+ if (local_syms == NULL && locsymcount != 0)
+ {
+ local_syms = bfd_elf_get_elf_syms (ibfd, symtab_hdr, locsymcount,
+ 0, NULL, NULL, NULL);
+ if (local_syms == NULL)
+ return false;
+ }
end_lgot_ents = lgot_ents + locsymcount;
local_plt = (struct plt_entry **) end_lgot_ents;
end_local_plt = local_plt + locsymcount;
- for (lgot = lgot_ents; lgot < end_lgot_ents; ++lgot)
+ for (lgot = lgot_ents, isym = local_syms;
+ lgot < end_lgot_ents;
+ ++lgot, ++isym)
for (gent = *lgot; gent != NULL; gent = gent->next)
if (!gent->is_indirect
&& gent->tls_type == 0
- && gent->got.offset != (bfd_vma) -1)
+ && gent->got.offset != (bfd_vma) -1
+ && isym->st_shndx != SHN_ABS)
{
asection *got = ppc64_elf_tdata (gent->owner)->got;
bfd_vma r_offset = (got->output_section->vma
@@ -13456,29 +13504,22 @@ got_and_plt_relr_for_local_syms (struct bfd_link_info *info)
}
if (!htab->opd_abi)
- for (lplt = local_plt; lplt < end_local_plt; ++lplt)
+ for (lplt = local_plt, isym = local_syms;
+ lplt < end_local_plt;
+ ++lplt, ++isym)
for (pent = *lplt; pent != NULL; pent = pent->next)
- if (pent->plt.offset != (bfd_vma) -1)
+ if (pent->plt.offset != (bfd_vma) -1
+ && ELF_ST_TYPE (isym->st_info) != STT_GNU_IFUNC)
{
- Elf_Internal_Sym *sym;
-
- if (!get_sym_h (NULL, &sym, NULL, NULL, &local_syms,
- lplt - local_plt, ibfd))
+ bfd_vma r_offset = (pent->plt.offset
+ + htab->pltlocal->output_offset
+ + htab->pltlocal->output_section->vma);
+ if (!append_relr_off (htab, r_offset))
{
- err_exit:
if (symtab_hdr->contents != (unsigned char *) local_syms)
free (local_syms);
return false;
}
-
- if (ELF_ST_TYPE (sym->st_info) != STT_GNU_IFUNC)
- {
- bfd_vma r_offset = (pent->plt.offset
- + htab->pltlocal->output_offset
- + htab->pltlocal->output_section->vma);
- if (!append_relr_off (htab, r_offset))
- goto err_exit;
- }
}
if (local_syms != NULL
@@ -13514,9 +13555,10 @@ got_and_plt_relr (struct elf_link_hash_entry *h, void *inf)
&& (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak))
{
- if (!htab->elf.dynamic_sections_created
- || h->dynindx == -1
- || SYMBOL_REFERENCES_LOCAL (info, h))
+ if ((!htab->elf.dynamic_sections_created
+ || h->dynindx == -1
+ || SYMBOL_REFERENCES_LOCAL (info, h))
+ && !bfd_is_abs_symbol (&h->root))
for (gent = h->got.glist; gent != NULL; gent = gent->next)
if (!gent->is_indirect
&& gent->tls_type == 0
@@ -13806,6 +13848,10 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
: ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
continue;
if (h != NULL
+ ? bfd_is_abs_symbol (&h->root)
+ : sym->st_shndx == SHN_ABS)
+ continue;
+ if (h != NULL
&& !SYMBOL_REFERENCES_LOCAL (info, h))
continue;
}
@@ -16553,6 +16599,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
case R_PPC64_GOT16_DS:
if ((h ? h->elf.type : ELF_ST_TYPE (sym->st_info)) == STT_GNU_IFUNC
+ || (bfd_link_pic (info)
+ && sec == bfd_abs_section_ptr)
|| !htab->do_toc_opt)
break;
from = TOCstart + htab->sec_info[input_section->id].toc_off;
@@ -16577,6 +16625,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
case R_PPC64_GOT16_LO_DS:
case R_PPC64_GOT16_HA:
if ((h ? h->elf.type : ELF_ST_TYPE (sym->st_info)) == STT_GNU_IFUNC
+ || (bfd_link_pic (info)
+ && sec == bfd_abs_section_ptr)
|| !htab->do_toc_opt)
break;
from = TOCstart + htab->sec_info[input_section->id].toc_off;
@@ -16607,6 +16657,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
case R_PPC64_GOT_PCREL34:
if ((h ? h->elf.type : ELF_ST_TYPE (sym->st_info)) == STT_GNU_IFUNC
+ || (bfd_link_pic (info)
+ && sec == bfd_abs_section_ptr)
|| !htab->do_toc_opt)
break;
from = (rel->r_offset
@@ -16846,7 +16898,11 @@ ppc64_elf_relocate_section (bfd *output_bfd,
&& bfd_link_executable (info)
&& (h == NULL
|| SYMBOL_REFERENCES_LOCAL (info,
- &h->elf)))))
+ &h->elf)))
+ && (h != NULL
+ ? !bfd_is_abs_symbol (&h->elf.root)
+ : sym->st_shndx != SHN_ABS)))
+
relgot = ppc64_elf_tdata (ent->owner)->relgot;
if (relgot != NULL)
{
@@ -17555,7 +17611,11 @@ ppc64_elf_relocate_section (bfd *output_bfd,
case R_PPC64_GOT16_HA:
case R_PPC64_TOC16_HA:
if (htab->do_toc_opt && relocation + addend + 0x8000 < 0x10000
- && !ppc64_elf_tdata (input_bfd)->unexpected_toc_insn)
+ && !ppc64_elf_tdata (input_bfd)->unexpected_toc_insn
+ && !(bfd_link_pic (info)
+ && (h != NULL
+ ? bfd_is_abs_symbol (&h->elf.root)
+ : sec == bfd_abs_section_ptr)))
{
bfd_byte *p;
nop_it:
@@ -17586,6 +17646,10 @@ ppc64_elf_relocate_section (bfd *output_bfd,
case R_PPC64_TOC16_LO_DS:
if (htab->do_toc_opt && relocation + addend + 0x8000 < 0x10000
&& !ppc64_elf_tdata (input_bfd)->unexpected_toc_insn
+ && !(bfd_link_pic (info)
+ && (h != NULL
+ ? bfd_is_abs_symbol (&h->elf.root)
+ : sec == bfd_abs_section_ptr))
&& offset_in_range (input_section, rel->r_offset & ~3, 4))
{
bfd_byte *p = contents + (rel->r_offset & ~3);