[lld] [X86][LLD] Handle R_X86_64_CODE_6_GOTTPOFF relocation type (PR #117675)

Feng Zou via llvm-commits llvm-commits at lists.llvm.org
Tue Nov 26 02:08:57 PST 2024


https://github.com/fzou1 updated https://github.com/llvm/llvm-project/pull/117675

>From 1d4f291949d9d1040be6359eade5b16005fc2c18 Mon Sep 17 00:00:00 2001
From: Feng Zou <feng.zou at intel.com>
Date: Tue, 26 Nov 2024 14:21:11 +0800
Subject: [PATCH 1/2] [X86][LLD] Handle R_X86_64_CODE_6_GOTTPOFF relocation
 type

For

    add %reg1, name at GOTTPOFF(%rip), %reg2
    add name at GOTTPOFF(%rip), %reg1, %reg2
    {nf} add %reg1, name at GOTTPOFF(%rip), %reg2
    {nf} add name at GOTTPOFF(%rip), %reg1, %reg2
    {nf} add name at GOTTPOFF(%rip), %reg

add

    R_X86_64_CODE_6_GOTTPOFF = 50

in #117277.

Linker can treat R_X86_64_CODE_6_GOTTPOFF as R_X86_64_GOTTPOFF or convert the
instructions above to

    add $name at tpoff, %reg1, %reg2
    add $name at tpoff, %reg1, %reg2
    {nf} add $name at tpoff, %reg1, %reg2
    {nf} add $name at tpoff, %reg1, %reg2
    {nf} add $name at tpoff, %reg

if the first byte of the instruction at the relocation offset - 6 is 0x62
(namely, encoded w/EVEX prefix) when possible.

Binutils patch: bminor/binutils-gdb at 5bc71c2
Binutils mailthread: https://sourceware.org/pipermail/binutils/2024-February/132351.html
ABI discussion: https://groups.google.com/g/x86-64-abi/c/FhEZjCtDLFw/m/VHDjN4orAgAJ
Blog: https://kanrobert.github.io/rfc/All-about-APX-relocation
---
 lld/ELF/Arch/X86_64.cpp | 89 +++++++++++++++++++++++++++--------------
 lld/test/ELF/tls-opt.s  | 17 ++++++++
 2 files changed, 75 insertions(+), 31 deletions(-)

diff --git a/lld/ELF/Arch/X86_64.cpp b/lld/ELF/Arch/X86_64.cpp
index 2dcce5c224d5d6..749ab7ca7db7e7 100644
--- a/lld/ELF/Arch/X86_64.cpp
+++ b/lld/ELF/Arch/X86_64.cpp
@@ -396,6 +396,7 @@ RelExpr X86_64::getRelExpr(RelType type, const Symbol &s,
   case R_X86_64_REX_GOTPCRELX:
   case R_X86_64_CODE_4_GOTPCRELX:
   case R_X86_64_GOTTPOFF:
+  case R_X86_64_CODE_6_GOTTPOFF:
     return R_GOT_PC;
   case R_X86_64_GOTOFF64:
     return R_GOTPLTREL;
@@ -547,44 +548,68 @@ void X86_64::relaxTlsGdToIe(uint8_t *loc, const Relocation &rel,
   }
 }
 
-// In some conditions, R_X86_64_GOTTPOFF relocation can be optimized to
-// R_X86_64_TPOFF32 so that it does not use GOT.
+// In some conditions, R_X86_64_GOTTPOFF/R_X86_64_CODE_6_GOTTPOFF relocation can
+// be optimized to R_X86_64_TPOFF32 so that it does not use GOT.
 void X86_64::relaxTlsIeToLe(uint8_t *loc, const Relocation &rel,
                             uint64_t val) const {
   uint8_t *inst = loc - 3;
   uint8_t reg = loc[-1] >> 3;
   uint8_t *regSlot = loc - 1;
 
-  // Note that ADD with RSP or R12 is converted to ADD instead of LEA
-  // because LEA with these registers needs 4 bytes to encode and thus
-  // wouldn't fit the space.
-
-  if (memcmp(inst, "\x48\x03\x25", 3) == 0) {
-    // "addq foo at gottpoff(%rip),%rsp" -> "addq $foo,%rsp"
-    memcpy(inst, "\x48\x81\xc4", 3);
-  } else if (memcmp(inst, "\x4c\x03\x25", 3) == 0) {
-    // "addq foo at gottpoff(%rip),%r12" -> "addq $foo,%r12"
-    memcpy(inst, "\x49\x81\xc4", 3);
-  } else if (memcmp(inst, "\x4c\x03", 2) == 0) {
-    // "addq foo at gottpoff(%rip),%r[8-15]" -> "leaq foo(%r[8-15]),%r[8-15]"
-    memcpy(inst, "\x4d\x8d", 2);
-    *regSlot = 0x80 | (reg << 3) | reg;
-  } else if (memcmp(inst, "\x48\x03", 2) == 0) {
-    // "addq foo at gottpoff(%rip),%reg -> "leaq foo(%reg),%reg"
-    memcpy(inst, "\x48\x8d", 2);
-    *regSlot = 0x80 | (reg << 3) | reg;
-  } else if (memcmp(inst, "\x4c\x8b", 2) == 0) {
-    // "movq foo at gottpoff(%rip),%r[8-15]" -> "movq $foo,%r[8-15]"
-    memcpy(inst, "\x49\xc7", 2);
-    *regSlot = 0xc0 | reg;
-  } else if (memcmp(inst, "\x48\x8b", 2) == 0) {
-    // "movq foo at gottpoff(%rip),%reg" -> "movq $foo,%reg"
-    memcpy(inst, "\x48\xc7", 2);
-    *regSlot = 0xc0 | reg;
+  if (rel.type == R_X86_64_GOTTPOFF) {
+    // Note that ADD with RSP or R12 is converted to ADD instead of LEA
+    // because LEA with these registers needs 4 bytes to encode and thus
+    // wouldn't fit the space.
+
+    if (memcmp(inst, "\x48\x03\x25", 3) == 0) {
+      // "addq foo at gottpoff(%rip),%rsp" -> "addq $foo,%rsp"
+      memcpy(inst, "\x48\x81\xc4", 3);
+    } else if (memcmp(inst, "\x4c\x03\x25", 3) == 0) {
+      // "addq foo at gottpoff(%rip),%r12" -> "addq $foo,%r12"
+      memcpy(inst, "\x49\x81\xc4", 3);
+    } else if (memcmp(inst, "\x4c\x03", 2) == 0) {
+      // "addq foo at gottpoff(%rip),%r[8-15]" -> "leaq foo(%r[8-15]),%r[8-15]"
+      memcpy(inst, "\x4d\x8d", 2);
+      *regSlot = 0x80 | (reg << 3) | reg;
+    } else if (memcmp(inst, "\x48\x03", 2) == 0) {
+      // "addq foo at gottpoff(%rip),%reg -> "leaq foo(%reg),%reg"
+      memcpy(inst, "\x48\x8d", 2);
+      *regSlot = 0x80 | (reg << 3) | reg;
+    } else if (memcmp(inst, "\x4c\x8b", 2) == 0) {
+      // "movq foo at gottpoff(%rip),%r[8-15]" -> "movq $foo,%r[8-15]"
+      memcpy(inst, "\x49\xc7", 2);
+      *regSlot = 0xc0 | reg;
+    } else if (memcmp(inst, "\x48\x8b", 2) == 0) {
+      // "movq foo at gottpoff(%rip),%reg" -> "movq $foo,%reg"
+      memcpy(inst, "\x48\xc7", 2);
+      *regSlot = 0xc0 | reg;
+    } else {
+      ErrAlways(ctx)
+          << getErrorLoc(ctx, loc - 3)
+          << "R_X86_64_GOTTPOFF must be used in MOVQ or ADDQ instructions only";
+    }
+  } else if (rel.type == R_X86_64_CODE_6_GOTTPOFF) {
+    if (loc[-6] != 0x62) {
+      Err(ctx) << getErrorLoc(ctx, loc - 6)
+               << "Invalid prefix with R_X86_64_CODE_6_GOTTPOFF!";
+      return;
+    }
+    if (loc[-2] == 0x3 || loc[-2] == 0x1) {
+      // "addq foo at gottpoff(%rip), %reg1, %reg2" -> "addq $foo, %reg1, %reg2"
+      loc[-2] = 0x81;
+      // Move R bits to B bits in EVEX payloads and ModRM byte.
+      if ((loc[-5] & (1 << 7)) == 0)
+        loc[-5] = (loc[-5] | (1 << 7)) & ~(1 << 5);
+      if ((loc[-5] & (1 << 4)) == 0)
+        loc[-5] = loc[-5] | (1 << 4) | (1 << 3);
+      *regSlot = 0xc0 | reg;
+    } else {
+      Err(ctx)
+          << getErrorLoc(ctx, loc - 6)
+          << "R_X86_64_CODE_6_GOTTPOFF must be used in ADDQ instructions only";
+    }
   } else {
-    ErrAlways(ctx)
-        << getErrorLoc(ctx, loc - 3)
-        << "R_X86_64_GOTTPOFF must be used in MOVQ or ADDQ instructions only";
+    llvm_unreachable("Unsupported relocation type!");
   }
 
   // The original code used a PC relative relocation.
@@ -741,6 +766,7 @@ int64_t X86_64::getImplicitAddend(const uint8_t *buf, RelType type) const {
   case R_X86_64_CODE_4_GOTPCRELX:
   case R_X86_64_PC32:
   case R_X86_64_GOTTPOFF:
+  case R_X86_64_CODE_6_GOTTPOFF:
   case R_X86_64_PLT32:
   case R_X86_64_TLSGD:
   case R_X86_64_TLSLD:
@@ -850,6 +876,7 @@ void X86_64::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
     }
     break;
   case R_X86_64_GOTTPOFF:
+  case R_X86_64_CODE_6_GOTTPOFF:
     if (rel.expr == R_RELAX_TLS_IE_TO_LE) {
       relaxTlsIeToLe(loc, rel, val);
     } else {
diff --git a/lld/test/ELF/tls-opt.s b/lld/test/ELF/tls-opt.s
index ce90ba4f869ce4..784f575b69ede5 100644
--- a/lld/test/ELF/tls-opt.s
+++ b/lld/test/ELF/tls-opt.s
@@ -20,6 +20,14 @@
 // DISASM-NEXT:   leaq -4(%r15), %r15
 // DISASM-NEXT:   addq $-4, %rsp
 // DISASM-NEXT:   addq $-4, %r12
+// DISASM-NEXT:   addq $-10, %r16, %r16
+// DISASM-NEXT:   addq $-10, %r16, %r20
+// DISASM-NEXT:   addq $-10, %r16, %rax
+// DISASM-NEXT:   addq $-10, %rax, %r16
+// DISASM-NEXT:   addq $-10, %r8, %r16
+// DISASM-NEXT:   addq $-10, %rax, %r12
+// DISASM-NEXT:   {nf} addq $-10, %r8, %r16
+// DISASM-NEXT:   {nf} addq $-10, %rax, %r12
 
 // LD to LE:
 // DISASM-NEXT:   movq %fs:0, %rax
@@ -69,6 +77,15 @@ _start:
  addq tls1 at GOTTPOFF(%rip), %r15
  addq tls1 at GOTTPOFF(%rip), %rsp
  addq tls1 at GOTTPOFF(%rip), %r12
+# NDD
+ addq tls0 at GOTTPOFF(%rip), %r16, %r16
+ addq tls0 at GOTTPOFF(%rip), %r16, %r20
+ addq tls0 at GOTTPOFF(%rip), %r16, %rax
+ addq tls0 at GOTTPOFF(%rip), %rax, %r16
+ addq %r8, tls0 at GOTTPOFF(%rip), %r16
+ addq tls0 at GOTTPOFF(%rip), %rax, %r12
+ {nf} addq %r8, tls0 at GOTTPOFF(%rip), %r16
+ {nf} addq tls0 at GOTTPOFF(%rip), %rax, %r12
 
  // LD to LE
  leaq tls0 at tlsld(%rip), %rdi

>From a8f2fa241d3b3fc7a1d2c174488b27d65458d1e5 Mon Sep 17 00:00:00 2001
From: Feng Zou <feng.zou at intel.com>
Date: Tue, 26 Nov 2024 18:08:29 +0800
Subject: [PATCH 2/2] Updated tests

---
 lld/test/ELF/pack-dyn-relocs-tls-x86-64.s |  5 ++++
 lld/test/ELF/tls-opt.s                    |  4 +++
 lld/test/ELF/x86-64-tls-ie-local.s        | 33 ++++++++++++++++++-----
 3 files changed, 35 insertions(+), 7 deletions(-)

diff --git a/lld/test/ELF/pack-dyn-relocs-tls-x86-64.s b/lld/test/ELF/pack-dyn-relocs-tls-x86-64.s
index b3b1e8a0602772..900976094123bf 100644
--- a/lld/test/ELF/pack-dyn-relocs-tls-x86-64.s
+++ b/lld/test/ELF/pack-dyn-relocs-tls-x86-64.s
@@ -12,12 +12,17 @@
     .globl  foo
 foo:
     movq    tlsvar at GOTTPOFF(%rip), %rcx
+    addq    tlsvar3 at GOTTPOFF(%rip), %rcx, %r16
+
 
     .section    .tdata,"awT", at progbits
     .space 0x1234
 tlsvar:
     .word   42
+tlsvar3:
+    .word   42
 
 // CHECK:          Section ({{.+}}) .rela.dyn {
 // CHECK-NEXT:     R_X86_64_TPOFF64 - 0x1234
+// CHECK-NEXT:     R_X86_64_TPOFF64 - 0x1236
 // CHECK-NEXT:     }
diff --git a/lld/test/ELF/tls-opt.s b/lld/test/ELF/tls-opt.s
index 784f575b69ede5..c501e98b7a3119 100644
--- a/lld/test/ELF/tls-opt.s
+++ b/lld/test/ELF/tls-opt.s
@@ -28,6 +28,7 @@
 // DISASM-NEXT:   addq $-10, %rax, %r12
 // DISASM-NEXT:   {nf} addq $-10, %r8, %r16
 // DISASM-NEXT:   {nf} addq $-10, %rax, %r12
+// DISASM-NEXT:   {nf} addq $-10, %r12
 
 // LD to LE:
 // DISASM-NEXT:   movq %fs:0, %rax
@@ -84,8 +85,11 @@ _start:
  addq tls0 at GOTTPOFF(%rip), %rax, %r16
  addq %r8, tls0 at GOTTPOFF(%rip), %r16
  addq tls0 at GOTTPOFF(%rip), %rax, %r12
+ # NDD + NF
  {nf} addq %r8, tls0 at GOTTPOFF(%rip), %r16
  {nf} addq tls0 at GOTTPOFF(%rip), %rax, %r12
+ # NF
+ {nf} addq tls0 at GOTTPOFF(%rip), %r12
 
  // LD to LE
  leaq tls0 at tlsld(%rip), %rdi
diff --git a/lld/test/ELF/x86-64-tls-ie-local.s b/lld/test/ELF/x86-64-tls-ie-local.s
index c527c86e667713..601b4e59740d3c 100644
--- a/lld/test/ELF/x86-64-tls-ie-local.s
+++ b/lld/test/ELF/x86-64-tls-ie-local.s
@@ -5,21 +5,40 @@
 # RUN: llvm-readobj -r %t.so | FileCheck --check-prefix=REL %s
 # RUN: llvm-objdump --no-print-imm-hex -d --no-show-raw-insn %t.so | FileCheck %s
 
-# SEC: .got PROGBITS 0000000000002338 000338 000010 00 WA 0 0 8
+# SEC: .got PROGBITS 0000000000002368 000368 000010 00 WA 0 0 8
 
 ## Dynamic relocations for non-preemptable symbols in a shared object have section index 0.
 # REL:      .rela.dyn {
-# REL-NEXT:   0x2338 R_X86_64_TPOFF64 - 0x0
-# REL-NEXT:   0x2340 R_X86_64_TPOFF64 - 0x4
+# REL-NEXT:   0x2368 R_X86_64_TPOFF64 - 0x0
+# REL-NEXT:   0x2370 R_X86_64_TPOFF64 - 0x4
 # REL-NEXT: }
 
-## &.got[0] - 0x127f = 0x2338 - 0x127f = 4281
-## &.got[1] - 0x1286 = 0x2340 - 0x1286 = 4282
-# CHECK:      1278:       addq 4281(%rip), %rax
-# CHECK-NEXT: 127f:       addq 4282(%rip), %rax
+## &.got[0] - 0x127f = 0x2368 - 0x127f = 4329
+## &.got[1] - 0x1286 = 0x2370 - 0x1286 = 4330
+## &.got[0] - 0x1290 = 0x2366 - 0x1290 = 4310
+## &.got[1] - 0x129a = 0x236e - 0x129a = 4308
+## &.got[0] - 0x12a4 = 0x2366 - 0x12a4 = 4290
+## &.got[1] - 0x12ae = 0x236e - 0x12ae = 4288
+## &.got[0] - 0x12ae = 0x2366 - 0x12b8 = 4270
+
+# CHECK:      1278:       addq 4329(%rip), %rax
+# CHECK-NEXT: 127f:       addq 4330(%rip), %rax
+# CHECK-NEXT: 1286:       addq %r8, 4310(%rip), %r16
+# CHECK-NEXT: 1290:       addq 4308(%rip), %rax, %r12
+# CHECK-NEXT: 129a:       {nf} addq %r8, 4290(%rip), %r16
+# CHECK-NEXT: 12a4:       {nf} addq 4288(%rip), %rax, %r12
+# CHECK-NEXT: 12ae:       {nf} addq 4270(%rip), %r12
 
 addq foo at GOTTPOFF(%rip), %rax
 addq bar at GOTTPOFF(%rip), %rax
+# NDD
+addq %r8, foo at GOTTPOFF(%rip), %r16
+addq bar at GOTTPOFF(%rip), %rax, %r12
+# NDD + NF
+{nf} addq %r8, foo at GOTTPOFF(%rip), %r16
+{nf} addq bar at GOTTPOFF(%rip), %rax, %r12
+# NF
+{nf} addq foo at GOTTPOFF(%rip), %r12
 
 .section .tbss,"awT", at nobits
 foo:



More information about the llvm-commits mailing list