[2/2] x86-64: tighten convert-load-reloc checking

Message ID c2281137-f16f-41db-8ac6-c6f6e36343b4@suse.com
State New
Headers
Series x86-64: enhancements to GOTPCREL / GOTTPOFF handling |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_binutils_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_binutils_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_binutils_check--master-aarch64 success Test passed
linaro-tcwg-bot/tcwg_binutils_check--master-arm success Test passed

Commit Message

Jan Beulich Jan. 14, 2025, 1:19 p.m. UTC
  Even if the assembler avoids using relaxable relocations for
inapplicable insns, such relocations can still appear for other reasons.
Be more thorough in the opcode checking we do, to avoid bogusly altering
other insns.

Furthermore correct an opcode mask (even if with the added condition
that's now fully benign).
---
The use of "abs_relocation" as an if() condition (just outside of lower
patch context) is highly questionable: The value of a symbol doesn't
express whether a symbol is absolute. In fact this way non-absolute
symbols also undergo the respective range check. Whereas at the same
time absolute symbols coming from the linker script or the --defsym
command line option aren't checked (because of what ABS_SYMBOL_P()
expands to). However, changing this breaks the pr19609-6a linker
testcase, as the way ABS_SYMBOL_P() works the range checking would then
be skipped, while later on when the relocation is processed it would
overflow.
  

Patch

--- a/bfd/elf64-x86-64.c
+++ b/bfd/elf64-x86-64.c
@@ -2223,13 +2223,15 @@  elf_x86_64_convert_load_reloc (bfd *abfd
 	      modrm = 0xc0 | (modrm & 0x38) >> 3;
 	      opcode = 0xf7;
 	    }
-	  else
+	  else if ((opcode | 0x38) == 0x3b)
 	    {
 	      /* Convert "binop foo@GOTPCREL(%rip), %reg" to
 		 "binop $foo, %reg".  */
-	      modrm = 0xc0 | (modrm & 0x38) >> 3 | (opcode & 0x3c);
+	      modrm = 0xc0 | ((modrm & 0x38) >> 3) | (opcode & 0x38);
 	      opcode = 0x81;
 	    }
+	  else
+	    return true;
 
 	  /* Use R_X86_64_32 with 32-bit operand to avoid relocation
 	     overflow when sign-extending imm32 to imm64.  */
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/load4.d
@@ -0,0 +1,13 @@ 
+#as: --64 -mrelax-relocations=yes
+#ld: -melf_x86_64 -z max-page-size=0x200000 -z noseparate-code
+#objdump: -dw
+
+.*: +file format .*
+
+Disassembly of section .text:
+
+0+4000b0 <_start>:
+[ 	]*[a-f0-9]+:	12 05 ([0-9a-f]{2} ){4} *	adc    0x[a-f0-9]+\(%rip\),%al        # 6000c8 <.*>
+[ 	]*[a-f0-9]+:	44 84 3d ([0-9a-f]{2} ){4} *	test   %r15b,0x[a-f0-9]+\(%rip\)        # 6000c8 <.*>
+[ 	]*[a-f0-9]+:	48 87 05 ([0-9a-f]{2} ){4} *	xchg   %rax,0x[a-f0-9]+\(%rip\)        # 6000c8 <.*>
+#pass
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/load4.s
@@ -0,0 +1,23 @@ 
+	.data
+	.type	bar, @object
+bar:
+	.byte	1
+	.size	bar, .-bar
+	.globl	foo
+	.type	foo, @object
+foo:
+	.byte	1
+	.size	foo, .-foo
+	.text
+	.globl	_start
+	.type	_start, @function
+_start:
+	# Other insns must not be accidentally transformed.
+	adc	1f(%rip), %al
+1:	.reloc .-4, R_X86_64_GOTPCRELX, bar-4
+	test	%r15b, 1f(%rip)
+1:	.reloc .-4, R_X86_64_REX_GOTPCRELX, bar-4
+	xchg	1f(%rip), %rax
+1:	.reloc .-4, R_X86_64_REX_GOTPCRELX, bar-4
+
+	.size	_start, .-_start
--- a/ld/testsuite/ld-x86-64/x86-64.exp
+++ b/ld/testsuite/ld-x86-64/x86-64.exp
@@ -653,6 +653,7 @@  run_dump_test "apx-load1d"
 run_dump_test "load2"
 run_dump_test "load3a"
 run_dump_test "load3b"
+run_dump_test "load4"
 run_dump_test "call1a"
 run_dump_test "call1b"
 run_dump_test "call1c"