PowerPC64 ld --no-power10-stubs

Alan Modra amodra@gmail.com
Fri Jul 10 01:55:55 GMT 2020


Needed for libraries that use ifuncs or other means to support
cpu-optimized versions of functions, some power10, some not, and those
functions make calls using linkage stubs.

bfd/
	* elf64-ppc.h (struct ppc64_elf_params): Add power10_stubs.
	* elf64-ppc.c (struct ppc_link_hash_table): Delete
	power10_stubs.
	(ppc64_elf_check_relocs): Adjust setting of power10_stubs.
	(plt_stub_size, ppc_build_one_stub, ppc_size_one_stub): Adjust
	uses of power10_stubs.
ld/
	* emultempl/ppc64elf.em (params): Init new field.
	(enum ppc64_opt): Add OPTION_POWER10_STUBS and OPTION_NO_POWER10_STUBS.
	(PARSE_AND_LIST_LONGOPTS): Support --power10-stubs and
	--no-power10-stubs.
	(PARSE_AND_LIST_OPTIONS, PARSE_AND_LIST_ARGS_CASES): Likewise.
	* testsuite/ld-powerpc/callstub-3.d: New test.
	* testsuite/ld-powerpc/powerpc.exp: Run it.

diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c
index 8d710848ba..e54f561019 100644
--- a/bfd/elf64-ppc.c
+++ b/bfd/elf64-ppc.c
@@ -3245,9 +3245,6 @@ struct ppc_link_hash_table
   /* Whether calls are made via the PLT from NOTOC functions.  */
   unsigned int notoc_plt:1;
 
-  /* Whether to use power10 instructions in linkage stubs.  */
-  unsigned int power10_stubs:1;
-
   /* Incremented every time we size stubs.  */
   unsigned int stub_iteration;
 
@@ -4602,7 +4599,8 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
 	case R_PPC64_PLT_PCREL34:
 	case R_PPC64_PLT_PCREL34_NOTOC:
 	case R_PPC64_PCREL28:
-	  htab->power10_stubs = 1;
+	  if (htab->params->power10_stubs < 0)
+	    htab->params->power10_stubs = 1;
 	  break;
 	default:
 	  break;
@@ -10763,7 +10761,7 @@ plt_stub_size (struct ppc_link_hash_table *htab,
 
   if (stub_entry->stub_type >= ppc_stub_plt_call_notoc)
     {
-      if (htab->power10_stubs)
+      if (htab->params->power10_stubs > 0)
 	{
 	  bfd_vma start = (stub_entry->stub_offset
 			   + stub_entry->group->stub_sec->output_offset
@@ -11604,7 +11602,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 
       relp = p;
       num_rel = 0;
-      if (htab->power10_stubs)
+      if (htab->params->power10_stubs > 0)
 	{
 	  bfd_boolean load = stub_entry->stub_type >= ppc_stub_plt_call_notoc;
 	  p = build_power10_offset (htab->params->stub_bfd, p, off, odd, load);
@@ -11643,7 +11641,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
       if (info->emitrelocations)
 	{
 	  bfd_vma roff = relp - stub_entry->group->stub_sec->contents;
-	  if (htab->power10_stubs)
+	  if (htab->params->power10_stubs > 0)
 	    num_rel += num_relocs_for_power10_offset (off, odd);
 	  else
 	    {
@@ -11653,7 +11651,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 	  r = get_relocs (stub_entry->group->stub_sec, num_rel);
 	  if (r == NULL)
 	    return FALSE;
-	  if (htab->power10_stubs)
+	  if (htab->params->power10_stubs > 0)
 	    r = emit_relocs_for_power10_offset (info, r, roff, targ, off, odd);
 	  else
 	    r = emit_relocs_for_offset (info, r, roff, targ, off);
@@ -11671,7 +11669,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 	    }
 	}
 
-      if (!htab->power10_stubs
+      if (htab->params->power10_stubs <= 0
 	  && htab->glink_eh_frame != NULL
 	  && htab->glink_eh_frame->size != 0)
 	{
@@ -12019,7 +12017,7 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
       if (info->emitrelocations)
 	{
 	  unsigned int num_rel;
-	  if (htab->power10_stubs)
+	  if (htab->params->power10_stubs > 0)
 	    num_rel = num_relocs_for_power10_offset (off, odd);
 	  else
 	    num_rel = num_relocs_for_offset (off - 8);
@@ -12027,7 +12025,7 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 	  stub_entry->group->stub_sec->flags |= SEC_RELOC;
 	}
 
-      if (htab->power10_stubs)
+      if (htab->params->power10_stubs > 0)
 	extra = size_power10_offset (off, odd);
       else
 	extra = size_offset (off - 8);
@@ -12038,7 +12036,7 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 	 calculated.  */
       off -= extra;
 
-      if (!htab->power10_stubs)
+      if (htab->params->power10_stubs <= 0)
 	{
 	  /* After the bcl, lr has been modified so we need to emit
 	     .eh_frame info saying the return address is in r12.  */
@@ -12101,7 +12099,7 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
       if (info->emitrelocations)
 	{
 	  unsigned int num_rel;
-	  if (htab->power10_stubs)
+	  if (htab->params->power10_stubs > 0)
 	    num_rel = num_relocs_for_power10_offset (off, odd);
 	  else
 	    num_rel = num_relocs_for_offset (off - 8);
@@ -12111,7 +12109,7 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 
       size = plt_stub_size (htab, stub_entry, off);
 
-      if (!htab->power10_stubs)
+      if (htab->params->power10_stubs <= 0)
 	{
 	  /* After the bcl, lr has been modified so we need to emit
 	     .eh_frame info saying the return address is in r12.  */
diff --git a/bfd/elf64-ppc.h b/bfd/elf64-ppc.h
index a2ffd4eb72..547971f8be 100644
--- a/bfd/elf64-ppc.h
+++ b/bfd/elf64-ppc.h
@@ -54,6 +54,9 @@ struct ppc64_elf_params
   /* Set if PLT call stubs for localentry:0 functions should omit r2 save.  */
   int plt_localentry0;
 
+  /* Whether to use power10 instructions in linkage stubs.  */
+  int power10_stubs;
+
   /* Whether to canonicalize .opd so that there are no overlapping
      .opd entries.  */
   int non_overlapping_opd;
diff --git a/ld/ChangeLog b/ld/ChangeLog
index 14f31a805f..b9c844ced3 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -1,3 +1,13 @@
+2020-07-10  Alan Modra  <amodra@gmail.com>
+
+	* emultempl/ppc64elf.em (params): Init new field.
+	(enum ppc64_opt): Add OPTION_POWER10_STUBS and OPTION_NO_POWER10_STUBS.
+	(PARSE_AND_LIST_LONGOPTS): Support --power10-stubs and
+	--no-power10-stubs.
+	(PARSE_AND_LIST_OPTIONS, PARSE_AND_LIST_ARGS_CASES): Likewise.
+	* testsuite/ld-powerpc/callstub-3.d: New test.
+	* testsuite/ld-powerpc/powerpc.exp: Run it.
+
 2020-07-09  Alan Modra  <amodra@gmail.com>
 
 	* emulparams/ppcpe.sh: Delete.
diff --git a/ld/emultempl/ppc64elf.em b/ld/emultempl/ppc64elf.em
index a2834c8525..4987243fa1 100644
--- a/ld/emultempl/ppc64elf.em
+++ b/ld/emultempl/ppc64elf.em
@@ -38,7 +38,7 @@ static struct ppc64_elf_params params = { NULL,
 					  &ppc_layout_sections_again,
 					  1, -1, -1, 0,
 					  ${DEFAULT_PLT_STATIC_CHAIN-0}, -1, 5,
-					  -1, 0, -1, -1, 0};
+					  -1, -1, 0, -1, -1, 0};
 
 /* Fake input file for stubs.  */
 static lang_input_statement_type *stub_file;
@@ -684,6 +684,8 @@ enum ppc64_opt
   OPTION_NO_PLT_ALIGN,
   OPTION_PLT_LOCALENTRY,
   OPTION_NO_PLT_LOCALENTRY,
+  OPTION_POWER10_STUBS,
+  OPTION_NO_POWER10_STUBS,
   OPTION_STUBSYMS,
   OPTION_NO_STUBSYMS,
   OPTION_SAVRES,
@@ -714,6 +716,8 @@ PARSE_AND_LIST_LONGOPTS=${PARSE_AND_LIST_LONGOPTS}'
   { "no-plt-align", no_argument, NULL, OPTION_NO_PLT_ALIGN },
   { "plt-localentry", optional_argument, NULL, OPTION_PLT_LOCALENTRY },
   { "no-plt-localentry", no_argument, NULL, OPTION_NO_PLT_LOCALENTRY },
+  { "power10-stubs", no_argument, NULL, OPTION_POWER10_STUBS },
+  { "no-power10-stubs", no_argument, NULL, OPTION_NO_POWER10_STUBS },
   { "emit-stub-syms", no_argument, NULL, OPTION_STUBSYMS },
   { "no-emit-stub-syms", no_argument, NULL, OPTION_NO_STUBSYMS },
   { "dotsyms", no_argument, NULL, OPTION_DOTSYMS },
@@ -769,6 +773,12 @@ PARSE_AND_LIST_OPTIONS=${PARSE_AND_LIST_OPTIONS}'
   --no-plt-localentry         Don'\''t optimize ELFv2 calls\n"
 		   ));
   fprintf (file, _("\
+  --power10-stubs             Use Power10 PLT call stubs (default auto)\n"
+		   ));
+  fprintf (file, _("\
+  --no-power10-stubs          Don'\''t use Power10 PLT call stubs\n"
+		   ));
+  fprintf (file, _("\
   --emit-stub-syms            Label linker stubs with a symbol\n"
 		   ));
   fprintf (file, _("\
@@ -878,6 +888,14 @@ PARSE_AND_LIST_ARGS_CASES=${PARSE_AND_LIST_ARGS_CASES}'
       params.plt_localentry0 = 0;
       break;
 
+    case OPTION_POWER10_STUBS:
+      params.power10_stubs = 1;
+      break;
+
+    case OPTION_NO_POWER10_STUBS:
+      params.power10_stubs = 0;
+      break;
+
     case OPTION_STUBSYMS:
       params.emit_stub_syms = 1;
       break;
diff --git a/ld/testsuite/ld-powerpc/callstub-3.d b/ld/testsuite/ld-powerpc/callstub-3.d
new file mode 100644
index 0000000000..06cbfbda4a
--- /dev/null
+++ b/ld/testsuite/ld-powerpc/callstub-3.d
@@ -0,0 +1,38 @@
+#source: callstub-1.s
+#as: -a64 -mpower10
+#ld: -melf64ppc -shared --plt-align=0 --hash-style=gnu --no-power10-stubs
+#objdump: -dr -Mpower10
+
+.*
+
+Disassembly of section \.text:
+
+.*\.plt_call\.f1>:
+.*:	(f8 41 00 18|18 00 41 f8) 	std     r2,24\(r1\)
+.*:	(7d 88 02 a6|a6 02 88 7d) 	mflr    r12
+.*:	(42 9f 00 05|05 00 9f 42) 	bcl     .*
+.*:	(7d 68 02 a6|a6 02 68 7d) 	mflr    r11
+.*:	(7d 88 03 a6|a6 03 88 7d) 	mtlr    r12
+.*:	(3d 8b 00 01|01 00 8b 3d) 	addis   r12,r11,1
+.*:	(e9 8c .. ..|.. .. 8c e9) 	ld      r12,.*\(r12\)
+.*:	(7d 89 03 a6|a6 03 89 7d) 	mtctr   r12
+.*:	(4e 80 04 20|20 04 80 4e) 	bctr
+
+.*\.plt_call\.f2>:
+.*:	(7d 88 02 a6|a6 02 88 7d) 	mflr    r12
+.*:	(42 9f 00 05|05 00 9f 42) 	bcl     .*
+.*:	(7d 68 02 a6|a6 02 68 7d) 	mflr    r11
+.*:	(7d 88 03 a6|a6 03 88 7d) 	mtlr    r12
+.*:	(3d 8b 00 01|01 00 8b 3d) 	addis   r12,r11,1
+.*:	(e9 8c .. ..|.. .. 8c e9) 	ld      r12,.*\(r12\)
+.*:	(7d 89 03 a6|a6 03 89 7d) 	mtctr   r12
+.*:	(4e 80 04 20|20 04 80 4e) 	bctr
+
+#...
+.*:	(4b ff ff 81|81 ff ff 4b) 	bl      .*\.plt_call\.f1>
+.*:	(e8 41 00 18|18 00 41 e8) 	ld      r2,24\(r1\)
+.*:	(4b ff ff 7d|7d ff ff 4b) 	bl      .*\.plt_call\.f1\+0x4>
+.*:	(4b ff ff 99|99 ff ff 4b) 	bl      .*\.plt_call\.f2>
+.*:	(04 10 00 01|01 00 10 04) 	pld     r3,.*
+.*:	(e4 60 .. ..|.. .. 60 e4) 
+#pass
diff --git a/ld/testsuite/ld-powerpc/powerpc.exp b/ld/testsuite/ld-powerpc/powerpc.exp
index de676b8176..50553baa90 100644
--- a/ld/testsuite/ld-powerpc/powerpc.exp
+++ b/ld/testsuite/ld-powerpc/powerpc.exp
@@ -402,6 +402,7 @@ if [ supports_ppc64 ] then {
     run_dump_test "pr23937"
     run_dump_test "callstub-1"
     run_dump_test "callstub-2"
+    run_dump_test "callstub-3"
     run_dump_test "tlsgd"
     run_dump_test "tlsld"
     run_dump_test "tlsie"

-- 
Alan Modra
Australia Development Lab, IBM


More information about the Binutils mailing list