[PATCH] ld: Add -z no-relax=SYMBOL

H.J. Lu hjl.tools@gmail.com
Mon Jan 27 01:33:30 GMT 2025


Add a "-z no-relax=SYMBOL" option to x86-64 linker to disable linker
optimization on GOTPCRELX relocations against SYMBOL.

bfd/

	PR ld/32591
	* elf-linker-x86.h (_bfd_elf_linker_x86_no_relax_symbol): New.
	* elf64-x86-64.c (elf_x86_64_convert_load_reloc): Avoid relocation
	overflow if a symbol is in no_relax_htab.
	(elf_x86_64_relocate_section): Don't warn GOTPCREL more than once
	for a symbol.  Replace --no-relax with -z no-relax=SYMBOL for
	GOTPCREL conversion overflow.
	* elfxx-x86.c: Include sysdep.h and libiberty.h.
	(_bfd_x86_elf_finish_dynamic_sections): Free no_relax_htab.
	(_bfd_elf_linker_x86_set_options): If --no-relax is used, free
	no_relax_htab.
	(_bfd_elf_linker_x86_no_relax_symbol): New.

include/

	PR ld/32591
	* bfdlink.h (bfd_link_info): Add no_relax_htab for the hash table
	for symbols without relaxation.

ld/

	PR ld/32591
	* NEWS: Mention "-z no-relax=SYMBOL".
	* ld.texi: Document "-z no-relax=SYMBOL".
	* emulparams/elf32_x86_64.sh: Source x86-64-no-relax.sh.
	* emulparams/elf_x86_64.sh: Likewise.
	* emulparams/x86-64-no-relax.sh: New file.
	* testsuite/ld-x86-64/pr19609-2a.d: Updated.
	* testsuite/ld-x86-64/pr19609-2b.d: Likewise.
	* testsuite/ld-x86-64/pr19609-4a.d: Likewise.
	* testsuite/ld-x86-64/pr19609-4c.d: Likewise.
	* testsuite/ld-x86-64/pr19609-5d.d: Likewise.
	* testsuite/ld-x86-64/pr19609-7a.d: Likewise.
	* testsuite/ld-x86-64/pr19609-7c.d: Likewise.
	* testsuite/ld-x86-64/pr32591-x32.d: New file.
	* testsuite/ld-x86-64/pr32591.d: Likewise.
	* testsuite/ld-x86-64/pr32591.s: Likewise.
	* testsuite/ld-x86-64/x86-64.exp: Run PR ld/32591 tests.

Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
---
 bfd/elf-linker-x86.h                 |  2 ++
 bfd/elf64-x86-64.c                   | 27 +++++++++++++++++++++++++--
 bfd/elfxx-x86.c                      | 26 ++++++++++++++++++++++++++
 include/bfdlink.h                    |  3 +++
 ld/NEWS                              |  3 +++
 ld/emulparams/elf32_x86_64.sh        |  1 +
 ld/emulparams/elf_x86_64.sh          |  1 +
 ld/emulparams/x86-64-no-relax.sh     | 12 ++++++++++++
 ld/ld.texi                           |  5 +++++
 ld/testsuite/ld-x86-64/pr19609-2a.d  |  2 +-
 ld/testsuite/ld-x86-64/pr19609-2b.d  |  2 +-
 ld/testsuite/ld-x86-64/pr19609-4a.d  |  2 +-
 ld/testsuite/ld-x86-64/pr19609-4c.d  |  2 +-
 ld/testsuite/ld-x86-64/pr19609-5d.d  |  2 +-
 ld/testsuite/ld-x86-64/pr19609-7a.d  |  2 +-
 ld/testsuite/ld-x86-64/pr19609-7c.d  |  2 +-
 ld/testsuite/ld-x86-64/pr32591-x32.d | 13 +++++++++++++
 ld/testsuite/ld-x86-64/pr32591.d     | 13 +++++++++++++
 ld/testsuite/ld-x86-64/pr32591.s     | 13 +++++++++++++
 ld/testsuite/ld-x86-64/x86-64.exp    |  2 ++
 20 files changed, 126 insertions(+), 9 deletions(-)
 create mode 100644 ld/emulparams/x86-64-no-relax.sh
 create mode 100644 ld/testsuite/ld-x86-64/pr32591-x32.d
 create mode 100644 ld/testsuite/ld-x86-64/pr32591.d
 create mode 100644 ld/testsuite/ld-x86-64/pr32591.s

diff --git a/bfd/elf-linker-x86.h b/bfd/elf-linker-x86.h
index 2c98257038f..eef5cbb4352 100644
--- a/bfd/elf-linker-x86.h
+++ b/bfd/elf-linker-x86.h
@@ -93,3 +93,5 @@ struct elf_linker_x86_params
 
 extern void _bfd_elf_linker_x86_set_options
   (struct bfd_link_info *, struct elf_linker_x86_params *);
+extern void _bfd_elf_linker_x86_no_relax_symbol
+  (struct bfd_link_info *, const char *);
diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c
index d1d02bd7b32..78dfd7d4385 100644
--- a/bfd/elf64-x86-64.c
+++ b/bfd/elf64-x86-64.c
@@ -1898,6 +1898,16 @@ elf_x86_64_convert_load_reloc (bfd *abfd,
       if (isym->st_shndx == SHN_UNDEF)
 	return true;
 
+      if (link_info->no_relax_htab != NULL)
+	{
+	  const char *name = bfd_elf_sym_name (abfd,
+					       &elf_symtab_hdr (abfd),
+					       isym, NULL);
+	  if (htab_find (link_info->no_relax_htab, name)
+	      != HTAB_EMPTY_ENTRY)
+	    no_overflow = true;
+	}
+
       local_ref = true;
       if (isym->st_shndx == SHN_ABS)
 	{
@@ -1922,6 +1932,11 @@ elf_x86_64_convert_load_reloc (bfd *abfd,
 	 R_X86_64_PC32.  */
       struct elf_x86_link_hash_entry *eh = elf_x86_hash_entry (h);
 
+      if (link_info->no_relax_htab != NULL
+	  && (htab_find (link_info->no_relax_htab, h->root.root.string)
+	      != HTAB_EMPTY_ENTRY))
+	no_overflow = true;
+
       abs_symbol = ABS_SYMBOL_P (h);
       abs_relocation = h->root.u.def.value;
 
@@ -4879,12 +4894,20 @@ elf_x86_64_relocate_section (bfd *output_bfd,
 	    {
 	      if (converted_reloc)
 		{
+		  if (info->no_relax_htab != NULL
+		      && (htab_find (info->no_relax_htab, name)
+			  != HTAB_EMPTY_ENTRY))
+		    continue;
+
+		  /* Don't warn GOTPCREL more than once for a symbol.  */
+		  _bfd_elf_linker_x86_no_relax_symbol (info, name);
+
 		  info->callbacks->einfo
 		    ("%X%H:", input_bfd, input_section, rel->r_offset);
 		  info->callbacks->einfo
 		    (_(" failed to convert GOTPCREL relocation against "
-		       "'%s'; relink with --no-relax\n"),
-		     name);
+		       "'%s'; relink with -z no-relax=%s\n"),
+		     name, name);
 		  status = false;
 		  continue;
 		}
diff --git a/bfd/elfxx-x86.c b/bfd/elfxx-x86.c
index 8e5a005fd36..a6d6894d887 100644
--- a/bfd/elfxx-x86.c
+++ b/bfd/elfxx-x86.c
@@ -18,6 +18,8 @@
    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
    MA 02110-1301, USA.  */
 
+#include "sysdep.h"
+#include "libiberty.h"
 #include "elfxx-x86.h"
 #include "elf-vxworks.h"
 #include "objalloc.h"
@@ -2756,6 +2758,12 @@ _bfd_x86_elf_finish_dynamic_sections (bfd *output_bfd,
   bfd_byte *dyncon, *dynconend;
   bfd_size_type sizeof_dyn;
 
+  if (info->no_relax_htab != NULL)
+    {
+      htab_delete (info->no_relax_htab);
+      info->no_relax_htab = NULL;
+    }
+
   bed = get_elf_backend_data (output_bfd);
   htab = elf_x86_hash_table (info, bed->target_id);
   if (htab == NULL)
@@ -4950,4 +4958,22 @@ _bfd_elf_linker_x86_set_options (struct bfd_link_info * info,
     = elf_x86_hash_table (info, bed->target_id);
   if (htab != NULL)
     htab->params = params;
+  /* If --no-relax is used, free no_relax_htab.  */
+  if (info->disable_target_specific_optimizations > 1
+      && info->no_relax_htab != NULL)
+    {
+      htab_delete (info->no_relax_htab);
+      info->no_relax_htab = NULL;
+    }
+}
+
+void
+_bfd_elf_linker_x86_no_relax_symbol (struct bfd_link_info *info,
+				     const char *name)
+{
+  if (info->no_relax_htab == NULL)
+    info->no_relax_htab = htab_create_alloc (16, htab_hash_string,
+					     htab_eq_string, NULL,
+					     xcalloc, free);
+  *htab_find_slot (info->no_relax_htab, name, INSERT) = (char *) name;
 }
diff --git a/include/bfdlink.h b/include/bfdlink.h
index ae451075996..da60a271f69 100644
--- a/include/bfdlink.h
+++ b/include/bfdlink.h
@@ -759,6 +759,9 @@ struct bfd_link_info
   /* The version information.  */
   struct bfd_elf_version_tree *version_info;
 
+  /* The hash table for symbols without relaxation.  */
+  void *no_relax_htab;
+
   /* Size of cache.  Backend can use it to keep strace cache size.   */
   bfd_size_type cache_size;
 
diff --git a/ld/NEWS b/ld/NEWS
index 17fb20a6b9f..ca242e9b62d 100644
--- a/ld/NEWS
+++ b/ld/NEWS
@@ -1,5 +1,8 @@
 -*- text -*-
 
+* Add a "-z no-relax=SYMBOL" option to x86-64 linker to disable linker
+  optimization on GOTPCRELX relocations against SYMBOL.
+
 Changes in 2.44:
 
 * Support for Nios II target has been removed, as this architecture has been
diff --git a/ld/emulparams/elf32_x86_64.sh b/ld/emulparams/elf32_x86_64.sh
index 6a92eec129d..3d9242d0d27 100644
--- a/ld/emulparams/elf32_x86_64.sh
+++ b/ld/emulparams/elf32_x86_64.sh
@@ -8,6 +8,7 @@ source_sh ${srcdir}/emulparams/x86-report-relative.sh
 source_sh ${srcdir}/emulparams/x86-64-level.sh
 source_sh ${srcdir}/emulparams/x86-64-level-report.sh
 source_sh ${srcdir}/emulparams/x86-64-plt.sh
+source_sh ${srcdir}/emulparams/x86-64-no-relax.sh
 source_sh ${srcdir}/emulparams/static.sh
 source_sh ${srcdir}/emulparams/dt-relr.sh
 SCRIPT_NAME=elf
diff --git a/ld/emulparams/elf_x86_64.sh b/ld/emulparams/elf_x86_64.sh
index 92449745c7a..dc0cbdd9da1 100644
--- a/ld/emulparams/elf_x86_64.sh
+++ b/ld/emulparams/elf_x86_64.sh
@@ -9,6 +9,7 @@ source_sh ${srcdir}/emulparams/x86-64-level.sh
 source_sh ${srcdir}/emulparams/x86-64-level-report.sh
 source_sh ${srcdir}/emulparams/x86-64-lam.sh
 source_sh ${srcdir}/emulparams/x86-64-plt.sh
+source_sh ${srcdir}/emulparams/x86-64-no-relax.sh
 source_sh ${srcdir}/emulparams/static.sh
 source_sh ${srcdir}/emulparams/dt-relr.sh
 SCRIPT_NAME=elf
diff --git a/ld/emulparams/x86-64-no-relax.sh b/ld/emulparams/x86-64-no-relax.sh
new file mode 100644
index 00000000000..411a3c21833
--- /dev/null
+++ b/ld/emulparams/x86-64-no-relax.sh
@@ -0,0 +1,12 @@
+PARSE_AND_LIST_OPTIONS_X86_64_NO_RELAX='
+  fprintf (file, _("\
+  -z no-relax=SYMBOL          Do not use relaxation on SYMBOL\n"));
+'
+PARSE_AND_LIST_ARGS_CASE_Z_X86_64_NO_RELAX='
+      else if (startswith (optarg, "no-relax="))
+	_bfd_elf_linker_x86_no_relax_symbol (&link_info,
+					     optarg + 9);
+'
+
+PARSE_AND_LIST_OPTIONS="$PARSE_AND_LIST_OPTIONS $PARSE_AND_LIST_OPTIONS_X86_64_NO_RELAX"
+PARSE_AND_LIST_ARGS_CASE_Z="$PARSE_AND_LIST_ARGS_CASE_Z $PARSE_AND_LIST_ARGS_CASE_Z_X86_64_NO_RELAX"
diff --git a/ld/ld.texi b/ld/ld.texi
index f6384ad82dd..7e6648f93a2 100644
--- a/ld/ld.texi
+++ b/ld/ld.texi
@@ -1569,6 +1569,11 @@ Supported for x86_64.
 @item muldefs
 Allow multiple definitions.
 
+@item no-relax=@var{symbol}
+Disable linker optimization on GOTPCRELX relocations against @var{symbol}.
+This option may be used multiple times on the command line to disable
+linker optimization against multiple symbols.  Supported for x86_64.
+
 @item nocopyreloc
 Disable linker generated .dynbss variables used in place of variables
 defined in shared libraries.  May result in dynamic text relocations.
diff --git a/ld/testsuite/ld-x86-64/pr19609-2a.d b/ld/testsuite/ld-x86-64/pr19609-2a.d
index 6d3db92afb7..de559775f15 100644
--- a/ld/testsuite/ld-x86-64/pr19609-2a.d
+++ b/ld/testsuite/ld-x86-64/pr19609-2a.d
@@ -1,4 +1,4 @@
 #source: pr19609-2.s
 #as: --64 -mrelax-relocations=yes
 #ld: -melf_x86_64 -Ttext=0x70000000 -Tdata=0xa0000000
-#error: .*failed to convert GOTPCREL relocation against 'foo'; relink with --no-relax.*
+#error: .*failed to convert GOTPCREL relocation against 'foo'; relink with -z no-relax=foo
diff --git a/ld/testsuite/ld-x86-64/pr19609-2b.d b/ld/testsuite/ld-x86-64/pr19609-2b.d
index 4fee93d7034..42870295d04 100644
--- a/ld/testsuite/ld-x86-64/pr19609-2b.d
+++ b/ld/testsuite/ld-x86-64/pr19609-2b.d
@@ -1,4 +1,4 @@
 #source: pr19609-2.s
 #as: --x32 -mrelax-relocations=yes
 #ld: -melf32_x86_64 -Ttext=0x70000000 -Tdata=0xa0000000
-#error: .*failed to convert GOTPCREL relocation against 'foo'; relink with --no-relax.*
+#error: .*failed to convert GOTPCREL relocation against 'foo'; relink with -z no-relax=foo
diff --git a/ld/testsuite/ld-x86-64/pr19609-4a.d b/ld/testsuite/ld-x86-64/pr19609-4a.d
index eb37d0c8729..931b2b7d109 100644
--- a/ld/testsuite/ld-x86-64/pr19609-4a.d
+++ b/ld/testsuite/ld-x86-64/pr19609-4a.d
@@ -1,4 +1,4 @@
 #source: pr19609-4.s
 #as: --64 -mrelax-relocations=yes
 #ld: -melf_x86_64 -Ttext=0x70000000 -Tdata=0xa0000000
-#error: .*failed to convert GOTPCREL relocation against 'foo'; relink with --no-relax.*failed to convert GOTPCREL relocation against 'foo'; relink with --no-relax.*
+#error: .*failed to convert GOTPCREL relocation against 'foo'; relink with -z no-relax=foo
diff --git a/ld/testsuite/ld-x86-64/pr19609-4c.d b/ld/testsuite/ld-x86-64/pr19609-4c.d
index eb37d0c8729..931b2b7d109 100644
--- a/ld/testsuite/ld-x86-64/pr19609-4c.d
+++ b/ld/testsuite/ld-x86-64/pr19609-4c.d
@@ -1,4 +1,4 @@
 #source: pr19609-4.s
 #as: --64 -mrelax-relocations=yes
 #ld: -melf_x86_64 -Ttext=0x70000000 -Tdata=0xa0000000
-#error: .*failed to convert GOTPCREL relocation against 'foo'; relink with --no-relax.*failed to convert GOTPCREL relocation against 'foo'; relink with --no-relax.*
+#error: .*failed to convert GOTPCREL relocation against 'foo'; relink with -z no-relax=foo
diff --git a/ld/testsuite/ld-x86-64/pr19609-5d.d b/ld/testsuite/ld-x86-64/pr19609-5d.d
index 0ab28efff1e..9fe54b130a3 100644
--- a/ld/testsuite/ld-x86-64/pr19609-5d.d
+++ b/ld/testsuite/ld-x86-64/pr19609-5d.d
@@ -1,4 +1,4 @@
 #source: pr19609-5.s
 #as: --64 -mrelax-relocations=yes
 #ld: -melf_x86_64 -Ttext=0x80000000
-#error: .*failed to convert GOTPCREL relocation against 'bar'; relink with --no-relax
+#error: .*failed to convert GOTPCREL relocation against 'bar'; relink with -z no-relax=bar
diff --git a/ld/testsuite/ld-x86-64/pr19609-7a.d b/ld/testsuite/ld-x86-64/pr19609-7a.d
index 34704a94c16..c1fe8b6f804 100644
--- a/ld/testsuite/ld-x86-64/pr19609-7a.d
+++ b/ld/testsuite/ld-x86-64/pr19609-7a.d
@@ -1,4 +1,4 @@
 #source: pr19609-7.s
 #as: --64 -mrelax-relocations=yes
 #ld: -melf_x86_64 -Ttext=0x80000000
-#error: .*failed to convert GOTPCREL relocation against 'foobar'; relink with --no-relax
+#error: .*failed to convert GOTPCREL relocation against 'foobar'; relink with -z no-relax=foobar
diff --git a/ld/testsuite/ld-x86-64/pr19609-7c.d b/ld/testsuite/ld-x86-64/pr19609-7c.d
index 09488e22a8e..add0d5cbabe 100644
--- a/ld/testsuite/ld-x86-64/pr19609-7c.d
+++ b/ld/testsuite/ld-x86-64/pr19609-7c.d
@@ -1,4 +1,4 @@
 #source: pr19609-7.s
 #as: --x32 -mrelax-relocations=yes
 #ld: -melf32_x86_64 -Ttext=0x80000000
-#error: .*failed to convert GOTPCREL relocation against 'foobar'; relink with --no-relax
+#error: .*failed to convert GOTPCREL relocation against 'foobar'; relink with -z no-relax=foobar
diff --git a/ld/testsuite/ld-x86-64/pr32591-x32.d b/ld/testsuite/ld-x86-64/pr32591-x32.d
new file mode 100644
index 00000000000..ae438855935
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr32591-x32.d
@@ -0,0 +1,13 @@
+#source: pr32591.s
+#as: --x32 -mrelax-relocations=yes
+#ld: -melf32_x86_64 -Ttext=0x70000000 -Tdata=0xa0000000 -z no-relax=foo -z no-relax=bar
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+70000000 <_start>:
+[ 	]*[a-f0-9]+:	48 3b 05 ([0-9a-f]{2} ){4}	cmp    -?0x[a-f0-9]+\(%rip\),%rax        # .*
+[ 	]*[a-f0-9]+:	48 3b 05 ([0-9a-f]{2} ){4}	cmp    -?0x[a-f0-9]+\(%rip\),%rax        # .*
diff --git a/ld/testsuite/ld-x86-64/pr32591.d b/ld/testsuite/ld-x86-64/pr32591.d
new file mode 100644
index 00000000000..eed53ab6565
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr32591.d
@@ -0,0 +1,13 @@
+#as: --64 -mrelax-relocations=yes
+#ld: -melf_x86_64 -Ttext=0x70000000 -Tdata=0xa0000000 -z no-relax=foo -z no-relax=bar
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+0+70000000 <_start>:
+[ 	]*[a-f0-9]+:	48 3b 05 ([0-9a-f]{2} ){4}	cmp    -?0x[a-f0-9]+\(%rip\),%rax        # .*
+[ 	]*[a-f0-9]+:	48 3b 05 ([0-9a-f]{2} ){4}	cmp    -?0x[a-f0-9]+\(%rip\),%rax        # .*
+#pass
diff --git a/ld/testsuite/ld-x86-64/pr32591.s b/ld/testsuite/ld-x86-64/pr32591.s
new file mode 100644
index 00000000000..35ff57bcbf3
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr32591.s
@@ -0,0 +1,13 @@
+	.data
+foo:
+	.quad	0
+	.globl bar
+bar:
+	.quad	0
+	.text
+	.globl  _start
+	.type	_start, @function
+_start:
+	cmpq	foo@GOTPCREL(%rip), %rax
+	cmpq	bar@GOTPCREL(%rip), %rax
+	.size	_start, .-_start
diff --git a/ld/testsuite/ld-x86-64/x86-64.exp b/ld/testsuite/ld-x86-64/x86-64.exp
index 48a468814c1..46f542f329f 100644
--- a/ld/testsuite/ld-x86-64/x86-64.exp
+++ b/ld/testsuite/ld-x86-64/x86-64.exp
@@ -544,6 +544,8 @@ run_dump_test "tlsdesc4"
 run_dump_test "tlsdesc5"
 run_dump_test "pr32191"
 run_dump_test "pr32191-x32"
+run_dump_test "pr32591"
+run_dump_test "pr32591-x32"
 
 if { ![skip_sframe_tests] } {
     run_dump_test "sframe-simple-1"
-- 
2.48.1



More information about the Binutils mailing list