PowerPC64 --no-pcrel-optimize

This new option effectively ignores R_PPC64_PCREL_OPT, disabling the
optimization of instructions marked by that relocation.  The patch
also disables GOT indirect to GOT/TOC pointer relative code editing
when --no-toc-optimize.

bfd/
	* elf64-ppc.h (struct ppc64_elf_params): Add no_pcrel_opt.
	* elf64-ppc.c (ppc64_elf_relocate_section): Disable GOT reloc
	optimizations when --no-toc-optimize.  Disable R_PPC64_PCREL_OPT
	optimization when --no-pcrel-optimize.
ld/
	* emultempl/ppc64elf.em (params): Init new field.
	(enum ppc64_opt): Add OPTION_NO_PCREL_OPT.
	(PARSE_AND_LIST_LONGOPTS, PARSE_AND_LIST_OPTIONS),
	(PARSE_AND_LIST_ARGS_CASES): Support --no-pcrel-optimize.
This commit is contained in:
Alan Modra
2020-08-12 23:31:28 +09:30
parent 75e100a30d
commit 6738c8a7c9
5 changed files with 86 additions and 59 deletions

View File

@@ -1,3 +1,10 @@
2020-08-13 Alan Modra <amodra@gmail.com>
* elf64-ppc.h (struct ppc64_elf_params): Add no_pcrel_opt.
* elf64-ppc.c (ppc64_elf_relocate_section): Disable GOT reloc
optimizations when --no-toc-optimize. Disable R_PPC64_PCREL_OPT
optimization when --no-pcrel-optimize.
2020-08-13 Alan Modra <amodra@gmail.com> 2020-08-13 Alan Modra <amodra@gmail.com>
PR 26348 PR 26348

View File

@@ -15903,7 +15903,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
break; break;
case R_PPC64_GOT16_DS: case R_PPC64_GOT16_DS:
if ((h ? h->elf.type : ELF_ST_TYPE (sym->st_info)) == STT_GNU_IFUNC) if ((h ? h->elf.type : ELF_ST_TYPE (sym->st_info)) == STT_GNU_IFUNC
|| !htab->do_toc_opt)
break; break;
from = TOCstart + htab->sec_info[input_section->id].toc_off; from = TOCstart + htab->sec_info[input_section->id].toc_off;
if (relocation + addend - from + 0x8000 < 0x10000 if (relocation + addend - from + 0x8000 < 0x10000
@@ -15922,7 +15923,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
case R_PPC64_GOT16_LO_DS: case R_PPC64_GOT16_LO_DS:
case R_PPC64_GOT16_HA: case R_PPC64_GOT16_HA:
if ((h ? h->elf.type : ELF_ST_TYPE (sym->st_info)) == STT_GNU_IFUNC) if ((h ? h->elf.type : ELF_ST_TYPE (sym->st_info)) == STT_GNU_IFUNC
|| !htab->do_toc_opt)
break; break;
from = TOCstart + htab->sec_info[input_section->id].toc_off; from = TOCstart + htab->sec_info[input_section->id].toc_off;
if (relocation + addend - from + 0x80008000ULL < 0x100000000ULL if (relocation + addend - from + 0x80008000ULL < 0x100000000ULL
@@ -15945,34 +15947,38 @@ ppc64_elf_relocate_section (bfd *output_bfd,
break; break;
case R_PPC64_GOT_PCREL34: case R_PPC64_GOT_PCREL34:
if ((h ? h->elf.type : ELF_ST_TYPE (sym->st_info)) == STT_GNU_IFUNC) if ((h ? h->elf.type : ELF_ST_TYPE (sym->st_info)) == STT_GNU_IFUNC
|| !htab->do_toc_opt)
break; break;
from = (rel->r_offset from = (rel->r_offset
+ input_section->output_section->vma + input_section->output_section->vma
+ input_section->output_offset); + input_section->output_offset);
if (relocation - from + (1ULL << 33) < 1ULL << 34 if (!(relocation - from + (1ULL << 33) < 1ULL << 34
&& SYMBOL_REFERENCES_LOCAL (info, &h->elf)) && SYMBOL_REFERENCES_LOCAL (info, &h->elf)))
{ break;
offset = rel->r_offset;
pinsn = bfd_get_32 (input_bfd, contents + offset); offset = rel->r_offset;
pinsn <<= 32; pinsn = bfd_get_32 (input_bfd, contents + offset);
pinsn |= bfd_get_32 (input_bfd, contents + offset + 4); pinsn <<= 32;
if ((pinsn & ((-1ULL << 50) | (63ULL << 26))) pinsn |= bfd_get_32 (input_bfd, contents + offset + 4);
== ((1ULL << 58) | (1ULL << 52) | (57ULL << 26) /* pld */)) if ((pinsn & ((-1ULL << 50) | (63ULL << 26)))
{ != ((1ULL << 58) | (1ULL << 52) | (57ULL << 26) /* pld */))
/* Replace with paddi. */ break;
pinsn += (2ULL << 56) + (14ULL << 26) - (57ULL << 26);
r_type = R_PPC64_PCREL34; /* Replace with paddi. */
rel->r_info = ELF64_R_INFO (r_symndx, r_type); pinsn += (2ULL << 56) + (14ULL << 26) - (57ULL << 26);
bfd_put_32 (input_bfd, pinsn >> 32, contents + offset); r_type = R_PPC64_PCREL34;
bfd_put_32 (input_bfd, pinsn, contents + offset + 4); rel->r_info = ELF64_R_INFO (r_symndx, r_type);
goto pcrelopt; bfd_put_32 (input_bfd, pinsn >> 32, contents + offset);
} bfd_put_32 (input_bfd, pinsn, contents + offset + 4);
} /* Fall through. */
break;
case R_PPC64_PCREL34: case R_PPC64_PCREL34:
if (SYMBOL_REFERENCES_LOCAL (info, &h->elf)) if (!htab->params->no_pcrel_opt
&& rel + 1 < relend
&& rel[1].r_offset == rel->r_offset
&& rel[1].r_info == ELF64_R_INFO (0, R_PPC64_PCREL_OPT)
&& SYMBOL_REFERENCES_LOCAL (info, &h->elf))
{ {
offset = rel->r_offset; offset = rel->r_offset;
pinsn = bfd_get_32 (input_bfd, contents + offset); pinsn = bfd_get_32 (input_bfd, contents + offset);
@@ -15982,43 +15988,37 @@ ppc64_elf_relocate_section (bfd *output_bfd,
== ((1ULL << 58) | (2ULL << 56) | (1ULL << 52) == ((1ULL << 58) | (2ULL << 56) | (1ULL << 52)
| (14ULL << 26) /* paddi */)) | (14ULL << 26) /* paddi */))
{ {
pcrelopt: bfd_vma off2 = rel[1].r_addend;
if (rel + 1 < relend if (off2 == 0)
&& rel[1].r_offset == offset /* zero means next insn. */
&& rel[1].r_info == ELF64_R_INFO (0, R_PPC64_PCREL_OPT)) off2 = 8;
off2 += offset;
if (off2 + 4 <= input_section->size)
{ {
bfd_vma off2 = rel[1].r_addend; uint64_t pinsn2;
if (off2 == 0) bfd_signed_vma addend_off;
/* zero means next insn. */ pinsn2 = bfd_get_32 (input_bfd, contents + off2);
off2 = 8; pinsn2 <<= 32;
off2 += offset; if ((pinsn2 & (63ULL << 58)) == 1ULL << 58)
if (off2 + 4 <= input_section->size)
{ {
uint64_t pinsn2; if (off2 + 8 > input_section->size)
bfd_signed_vma addend_off; break;
pinsn2 = bfd_get_32 (input_bfd, contents + off2); pinsn2 |= bfd_get_32 (input_bfd,
pinsn2 <<= 32; contents + off2 + 4);
}
if (xlate_pcrel_opt (&pinsn, &pinsn2, &addend_off))
{
addend += addend_off;
rel->r_addend = addend;
bfd_put_32 (input_bfd, pinsn >> 32,
contents + offset);
bfd_put_32 (input_bfd, pinsn,
contents + offset + 4);
bfd_put_32 (input_bfd, pinsn2 >> 32,
contents + off2);
if ((pinsn2 & (63ULL << 58)) == 1ULL << 58) if ((pinsn2 & (63ULL << 58)) == 1ULL << 58)
{ bfd_put_32 (input_bfd, pinsn2,
if (off2 + 8 > input_section->size) contents + off2 + 4);
break;
pinsn2 |= bfd_get_32 (input_bfd,
contents + off2 + 4);
}
if (xlate_pcrel_opt (&pinsn, &pinsn2, &addend_off))
{
addend += addend_off;
rel->r_addend = addend;
bfd_put_32 (input_bfd, pinsn >> 32,
contents + offset);
bfd_put_32 (input_bfd, pinsn,
contents + offset + 4);
bfd_put_32 (input_bfd, pinsn2 >> 32,
contents + off2);
if ((pinsn2 & (63ULL << 58)) == 1ULL << 58)
bfd_put_32 (input_bfd, pinsn2,
contents + off2 + 4);
}
} }
} }
} }

View File

@@ -57,6 +57,9 @@ struct ppc64_elf_params
/* Whether to use power10 instructions in linkage stubs. */ /* Whether to use power10 instructions in linkage stubs. */
int power10_stubs; int power10_stubs;
/* Whether R_PPC64_PCREL_OPT should be ignored. */
int no_pcrel_opt;
/* Whether to canonicalize .opd so that there are no overlapping /* Whether to canonicalize .opd so that there are no overlapping
.opd entries. */ .opd entries. */
int non_overlapping_opd; int non_overlapping_opd;

View File

@@ -1,3 +1,10 @@
2020-08-13 Alan Modra <amodra@gmail.com>
* emultempl/ppc64elf.em (params): Init new field.
(enum ppc64_opt): Add OPTION_NO_PCREL_OPT.
(PARSE_AND_LIST_LONGOPTS, PARSE_AND_LIST_OPTIONS),
(PARSE_AND_LIST_ARGS_CASES): Support --no-pcrel-optimize.
2020-08-10 Nick Clifton <nickc@redhat.com> 2020-08-10 Nick Clifton <nickc@redhat.com>
PR ld/21351 PR ld/21351

View File

@@ -38,7 +38,7 @@ static struct ppc64_elf_params params = { NULL,
&ppc_layout_sections_again, &ppc_layout_sections_again,
1, -1, -1, 0, 1, -1, -1, 0,
${DEFAULT_PLT_STATIC_CHAIN-0}, -1, 5, ${DEFAULT_PLT_STATIC_CHAIN-0}, -1, 5,
-1, -1, 0, -1, -1, 0}; -1, -1, 0, 0, -1, -1, 0};
/* Fake input file for stubs. */ /* Fake input file for stubs. */
static lang_input_statement_type *stub_file; static lang_input_statement_type *stub_file;
@@ -686,6 +686,7 @@ enum ppc64_opt
OPTION_NO_PLT_LOCALENTRY, OPTION_NO_PLT_LOCALENTRY,
OPTION_POWER10_STUBS, OPTION_POWER10_STUBS,
OPTION_NO_POWER10_STUBS, OPTION_NO_POWER10_STUBS,
OPTION_NO_PCREL_OPT,
OPTION_STUBSYMS, OPTION_STUBSYMS,
OPTION_NO_STUBSYMS, OPTION_NO_STUBSYMS,
OPTION_SAVRES, OPTION_SAVRES,
@@ -717,6 +718,7 @@ PARSE_AND_LIST_LONGOPTS=${PARSE_AND_LIST_LONGOPTS}'
{ "plt-localentry", optional_argument, NULL, OPTION_PLT_LOCALENTRY }, { "plt-localentry", optional_argument, NULL, OPTION_PLT_LOCALENTRY },
{ "no-plt-localentry", no_argument, NULL, OPTION_NO_PLT_LOCALENTRY }, { "no-plt-localentry", no_argument, NULL, OPTION_NO_PLT_LOCALENTRY },
{ "power10-stubs", optional_argument, NULL, OPTION_POWER10_STUBS }, { "power10-stubs", optional_argument, NULL, OPTION_POWER10_STUBS },
{ "no-pcrel-optimize", no_argument, NULL, OPTION_NO_PCREL_OPT },
{ "no-power10-stubs", no_argument, NULL, OPTION_NO_POWER10_STUBS }, { "no-power10-stubs", no_argument, NULL, OPTION_NO_POWER10_STUBS },
{ "emit-stub-syms", no_argument, NULL, OPTION_STUBSYMS }, { "emit-stub-syms", no_argument, NULL, OPTION_STUBSYMS },
{ "no-emit-stub-syms", no_argument, NULL, OPTION_NO_STUBSYMS }, { "no-emit-stub-syms", no_argument, NULL, OPTION_NO_STUBSYMS },
@@ -776,6 +778,9 @@ PARSE_AND_LIST_OPTIONS=${PARSE_AND_LIST_OPTIONS}'
--power10-stubs [=auto] Use Power10 PLT call stubs (default auto)\n" --power10-stubs [=auto] Use Power10 PLT call stubs (default auto)\n"
)); ));
fprintf (file, _("\ fprintf (file, _("\
--no-pcrel-optimize Don'\''t perform R_PPC64_PCREL_OPT optimization\n"
));
fprintf (file, _("\
--no-power10-stubs Don'\''t use Power10 PLT call stubs\n" --no-power10-stubs Don'\''t use Power10 PLT call stubs\n"
)); ));
fprintf (file, _("\ fprintf (file, _("\
@@ -909,6 +914,10 @@ PARSE_AND_LIST_ARGS_CASES=${PARSE_AND_LIST_ARGS_CASES}'
params.power10_stubs = 0; params.power10_stubs = 0;
break; break;
case OPTION_NO_PCREL_OPT:
params.no_pcrel_opt = 1;
break;
case OPTION_STUBSYMS: case OPTION_STUBSYMS:
params.emit_stub_syms = 1; params.emit_stub_syms = 1;
break; break;
@@ -985,6 +994,7 @@ PARSE_AND_LIST_ARGS_CASES=${PARSE_AND_LIST_ARGS_CASES}'
params.no_multi_toc = 1; params.no_multi_toc = 1;
no_toc_sort = 1; no_toc_sort = 1;
params.plt_static_chain = 1; params.plt_static_chain = 1;
params.no_pcrel_opt = 1;
return FALSE; return FALSE;
' '