[lld] 636beb6 - [X86][LLD] Handle R_X86_64_CODE_6_GOTTPOFF relocation type (#117675)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Dec 5 00:26:30 PST 2024
Author: Feng Zou
Date: 2024-12-05T16:26:26+08:00
New Revision: 636beb6a2833ee0290935f679252c1b662721b31
URL: https://github.com/llvm/llvm-project/commit/636beb6a2833ee0290935f679252c1b662721b31
DIFF: https://github.com/llvm/llvm-project/commit/636beb6a2833ee0290935f679252c1b662721b31.diff
LOG: [X86][LLD] Handle R_X86_64_CODE_6_GOTTPOFF relocation type (#117675)
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
Added:
lld/test/ELF/x86-64-tls-ie-err.s
Modified:
lld/ELF/Arch/X86_64.cpp
lld/test/ELF/invalid/broken-relaxation-x64.test
lld/test/ELF/pack-dyn-relocs-tls-x86-64.s
lld/test/ELF/tls-opt.s
lld/test/ELF/x86-64-tls-ie-local.s
Removed:
################################################################################
diff --git a/lld/ELF/Arch/X86_64.cpp b/lld/ELF/Arch/X86_64.cpp
index dd0dc83189d265..076176ebc9a4c4 100644
--- a/lld/ELF/Arch/X86_64.cpp
+++ b/lld/ELF/Arch/X86_64.cpp
@@ -401,6 +401,7 @@ RelExpr X86_64::getRelExpr(RelType type, const Symbol &s,
case R_X86_64_CODE_4_GOTPCRELX:
case R_X86_64_GOTTPOFF:
case R_X86_64_CODE_4_GOTTPOFF:
+ case R_X86_64_CODE_6_GOTTPOFF:
return R_GOT_PC;
case R_X86_64_GOTOFF64:
return R_GOTPLTREL;
@@ -562,8 +563,9 @@ void X86_64::relaxTlsGdToIe(uint8_t *loc, const Relocation &rel,
}
}
-// In some conditions, R_X86_64_GOTTPOFF/R_X86_64_CODE_4_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_4_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;
@@ -605,7 +607,7 @@ void X86_64::relaxTlsIeToLe(uint8_t *loc, const Relocation &rel,
} else if (rel.type == R_X86_64_CODE_4_GOTTPOFF) {
if (loc[-4] != 0xd5) {
Err(ctx) << getErrorLoc(ctx, loc - 4)
- << "Invalid prefix with R_X86_64_CODE_4_GOTTPOFF!";
+ << "invalid prefix with R_X86_64_CODE_4_GOTTPOFF!";
return;
}
const uint8_t rex = loc[-3];
@@ -623,6 +625,41 @@ void X86_64::relaxTlsIeToLe(uint8_t *loc, const Relocation &rel,
<< "R_X86_64_CODE_4_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;
+ }
+ // Check bits are satisfied:
+ // loc[-5]: X==1 (inverted polarity), (loc[-5] & 0x7) == 0x4
+ // loc[-4]: W==1, X2==1 (inverted polarity), pp==0b00(NP)
+ // loc[-3]: NF==1 or ND==1
+ // loc[-2]: opcode==0x1 or opcode==0x3
+ // loc[-1]: Mod==0b00, RM==0b101
+ if (((loc[-5] & 0x47) == 0x44) && ((loc[-4] & 0x87) == 0x84) &&
+ ((loc[-3] & 0x14) != 0) && (loc[-2] == 0x1 || loc[-2] == 0x3) &&
+ ((loc[-1] & 0xc7) == 0x5)) {
+ // "addq %reg1, foo at GOTTPOFF(%rip), %reg2" -> "addq $foo, %reg1, %reg2"
+ // "addq foo at GOTTPOFF(%rip), %reg1, %reg2" -> "addq $foo, %reg1, %reg2"
+ // "{nf} addq %reg1, foo at GOTTPOFF(%rip), %reg2"
+ // -> "{nf} addq $foo, %reg1, %reg2"
+ // "{nf} addq name at GOTTPOFF(%rip), %reg1, %reg2"
+ // -> "{nf} addq $foo, %reg1, %reg2"
+ // "{nf} addq name at GOTTPOFF(%rip), %reg" -> "{nf} addq $foo, %reg"
+ loc[-2] = 0x81;
+ // Move R bits to B bits in EVEX payloads and ModRM byte.
+ const uint8_t evexPayload0 = loc[-5];
+ if ((evexPayload0 & (1 << 7)) == 0)
+ loc[-5] = (evexPayload0 | (1 << 7)) & ~(1 << 5);
+ if ((evexPayload0 & (1 << 4)) == 0)
+ loc[-5] = evexPayload0 | (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 "
+ "with NDD/NF/NDD+NF only";
+ }
} else {
llvm_unreachable("Unsupported relocation type!");
}
@@ -782,6 +819,7 @@ int64_t X86_64::getImplicitAddend(const uint8_t *buf, RelType type) const {
case R_X86_64_PC32:
case R_X86_64_GOTTPOFF:
case R_X86_64_CODE_4_GOTTPOFF:
+ case R_X86_64_CODE_6_GOTTPOFF:
case R_X86_64_PLT32:
case R_X86_64_TLSGD:
case R_X86_64_TLSLD:
@@ -893,6 +931,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_4_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/invalid/broken-relaxation-x64.test b/lld/test/ELF/invalid/broken-relaxation-x64.test
index 97a977e2c03ac3..daa0b38ec3971e 100644
--- a/lld/test/ELF/invalid/broken-relaxation-x64.test
+++ b/lld/test/ELF/invalid/broken-relaxation-x64.test
@@ -1,15 +1,15 @@
# REQUIRES: x86
-# RUN: yaml2obj %s -o %t.o
-# RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck --check-prefix=ERR %s
-# ERR: R_X86_64_GOTTPOFF must be used in MOVQ or ADDQ instructions only
-# ERR: R_X86_64_GOTTPOFF must be used in MOVQ or ADDQ instructions only
+# RUN: yaml2obj --docnum=1 %s -o %t1.o
+# RUN: not ld.lld %t1.o -o /dev/null 2>&1 | FileCheck --check-prefix=ERR %s
+# ERR: error: {{.*}}: R_X86_64_GOTTPOFF must be used in MOVQ or ADDQ instructions only
+# ERR: error: {{.*}}: R_X86_64_GOTTPOFF must be used in MOVQ or ADDQ instructions only
## YAML below contains 2 relocations of type R_X86_64_GOTTPOFF, and a .text
## with fake content filled by 0xFF. That means instructions for relaxation are
## "broken", so they does not match any known valid relaxations. We also generate
## .tls section because we need it for correct processing of STT_TLS symbol.
-!ELF
+--- !ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
@@ -44,4 +44,131 @@ Symbols:
Value: 0x12345
Size: 4
Binding: STB_GLOBAL
-
+
+
+# RUN: yaml2obj --docnum=2 %s -o %t2.o
+# RUN: not ld.lld %t2.o -o /dev/null 2>&1 | FileCheck --check-prefix=ERR2 %s
+# ERR2: error: {{.*}}: invalid prefix with R_X86_64_CODE_4_GOTTPOFF!
+# ERR2: error: {{.*}}: invalid prefix with R_X86_64_CODE_6_GOTTPOFF!
+
+## YAML below contains 2 relocations of
+## R_X86_64_CODE_4_GOTTPOFF/R_X86_64_CODE_6_GOTTPOFF type, and a .text with
+## fake content filled by 0xFF. It's expected to get "invalid prefix" error
+## message as above.
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_FREEBSD
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Type: SHT_PROGBITS
+ Name: .text
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Content: "FFFFFFFFFFFFFFFFFFFF"
+ - Type: SHT_PROGBITS
+ Name: .tls
+ Flags: [ SHF_ALLOC, SHF_TLS ]
+ - Type: SHT_REL
+ Name: .rel.text
+ Link: .symtab
+ Info: .text
+ AddressAlign: 0x04
+ Relocations:
+ - Offset: 4
+ Symbol: foo
+ Type: R_X86_64_CODE_4_GOTTPOFF
+ - Offset: 6
+ Symbol: foo
+ Type: R_X86_64_CODE_6_GOTTPOFF
+Symbols:
+ - Name: foo
+ Type: STT_TLS
+ Section: .text
+ Value: 0x12345
+ Size: 4
+ Binding: STB_GLOBAL
+
+
+# RUN: yaml2obj --docnum=3 %s -o %t3.o
+# RUN: not ld.lld %t3.o -o /dev/null 2>&1 | FileCheck --check-prefix=ERR3 %s
+# ERR3: error: {{.*}}: R_X86_64_CODE_4_GOTTPOFF must be used in MOVQ or ADDQ instructions only
+
+## YAML below contains R_X86_64_CODE_4_GOTTPOFF relocation type, and a .text
+## with fake content filled by 0xd5, 0xFF, ... and 0xFF. It's expected to get
+## the error message as above.
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_FREEBSD
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Type: SHT_PROGBITS
+ Name: .text
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Content: "d5FFFFFFFFFFFFFFFFFF"
+ - Type: SHT_PROGBITS
+ Name: .tls
+ Flags: [ SHF_ALLOC, SHF_TLS ]
+ - Type: SHT_REL
+ Name: .rel.text
+ Link: .symtab
+ Info: .text
+ AddressAlign: 0x04
+ Relocations:
+ - Offset: 4
+ Symbol: foo
+ Type: R_X86_64_CODE_4_GOTTPOFF
+Symbols:
+ - Name: foo
+ Type: STT_TLS
+ Section: .text
+ Value: 0x12345
+ Size: 4
+ Binding: STB_GLOBAL
+
+
+# RUN: yaml2obj --docnum=4 %s -o %t4.o
+# RUN: not ld.lld %t4.o -o /dev/null 2>&1 | FileCheck --check-prefix=ERR4 %s
+# ERR4: error: {{.*}}: R_X86_64_CODE_6_GOTTPOFF must be used in ADDQ instructions with NDD/NF/NDD+NF only
+
+## YAML below contains R_X86_64_CODE_6_GOTTPOFF relocation type, and a .text
+## with fake content filled by 0x62, 0xFF, ... and 0xFF. It's expected to get
+## the error message as above.
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_FREEBSD
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Type: SHT_PROGBITS
+ Name: .text
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Content: "62FFFFFFFFFFFFFFFFFF"
+ - Type: SHT_PROGBITS
+ Name: .tls
+ Flags: [ SHF_ALLOC, SHF_TLS ]
+ - Type: SHT_REL
+ Name: .rel.text
+ Link: .symtab
+ Info: .text
+ AddressAlign: 0x04
+ Relocations:
+ - Offset: 6
+ Symbol: foo
+ Type: R_X86_64_CODE_6_GOTTPOFF
+Symbols:
+ - Name: foo
+ Type: STT_TLS
+ Section: .text
+ Value: 0x12345
+ Size: 4
+ Binding: STB_GLOBAL
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 c6464b4bece097..c54d6f705080d0 100644
--- a/lld/test/ELF/pack-dyn-relocs-tls-x86-64.s
+++ b/lld/test/ELF/pack-dyn-relocs-tls-x86-64.s
@@ -13,6 +13,7 @@
foo:
movq tlsvar at GOTTPOFF(%rip), %rcx
movq tlsvar2 at GOTTPOFF(%rip), %r31
+ addq tlsvar3 at GOTTPOFF(%rip), %rcx, %r16
.section .tdata,"awT", at progbits
@@ -21,7 +22,11 @@ tlsvar:
.word 42
tlsvar2:
.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: R_X86_64_TPOFF64 - 0x1238
// CHECK-NEXT: }
diff --git a/lld/test/ELF/tls-opt.s b/lld/test/ELF/tls-opt.s
index 818203ee19cb7c..08cc52afd6411e 100644
--- a/lld/test/ELF/tls-opt.s
+++ b/lld/test/ELF/tls-opt.s
@@ -20,12 +20,25 @@
// DISASM-NEXT: leaq -4(%r15), %r15
// DISASM-NEXT: addq $-4, %rsp
// DISASM-NEXT: addq $-4, %r12
+# EGPR
// DISASM-NEXT: movq $-8, %r16
// DISASM-NEXT: movq $-8, %r20
// DISASM-NEXT: movq $-4, %r16
// DISASM-NEXT: addq $-8, %r16
// DISASM-NEXT: addq $-8, %r28
// DISASM-NEXT: addq $-4, %r16
+# NDD
+// 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
+# NDD + NF
+// DISASM-NEXT: {nf} addq $-10, %r8, %r16
+// DISASM-NEXT: {nf} addq $-10, %rax, %r12
+# NF
+// DISASM-NEXT: {nf} addq $-10, %r12
// LD to LE:
// DISASM-NEXT: movq %fs:0, %rax
@@ -82,6 +95,18 @@ _start:
addq tls0 at GOTTPOFF(%rip), %r16
addq tls0 at GOTTPOFF(%rip), %r28
addq tls1 at GOTTPOFF(%rip), %r16
+ # 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
+ # 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-err.s b/lld/test/ELF/x86-64-tls-ie-err.s
new file mode 100644
index 00000000000000..3cc7cb0d417377
--- /dev/null
+++ b/lld/test/ELF/x86-64-tls-ie-err.s
@@ -0,0 +1,35 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
+# RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck -DFILE=%t.o %s
+
+# CHECK: error: [[FILE]]:(.text+0x2): invalid prefix with R_X86_64_CODE_4_GOTTPOFF!
+# CHECK-NEXT: error: [[FILE]]:(.text+0x8): invalid prefix with R_X86_64_CODE_6_GOTTPOFF!
+# CHECK-NEXT: error: [[FILE]]:(.text+0x12): R_X86_64_CODE_4_GOTTPOFF must be used in MOVQ or ADDQ instructions only
+# CHECK-NEXT: error: [[FILE]]:(.text+0x1a): R_X86_64_CODE_6_GOTTPOFF must be used in ADDQ instructions with NDD/NF/NDD+NF only
+
+## These negative tests are to check if the invalid prefix and unsupported
+## instructions for TLS relocation types with APX instructions are handled as
+## errors.
+
+.type tls0, at object
+.section .tbss,"awT", at nobits
+.globl tls0
+.align 4
+tls0:
+ .long 0
+ .size tls0, 4
+
+.text
+.globl _start
+_start:
+ addq 0(%rip), %rax, %r16
+ .reloc .-4, R_X86_64_CODE_4_GOTTPOFF, tls0-4
+
+ movq 0(%rip), %r16
+ .reloc .-4, R_X86_64_CODE_6_GOTTPOFF, tls0-4
+
+ andq 0(%rip), %r16
+ .reloc .-4, R_X86_64_CODE_4_GOTTPOFF, tls0-4
+
+ andq 0(%rip), %rax, %r16
+ .reloc .-4, R_X86_64_CODE_6_GOTTPOFF, tls0-4
diff --git a/lld/test/ELF/x86-64-tls-ie-local.s b/lld/test/ELF/x86-64-tls-ie-local.s
index 340a654ef9c284..0a104e7d67277a 100644
--- a/lld/test/ELF/x86-64-tls-ie-local.s
+++ b/lld/test/ELF/x86-64-tls-ie-local.s
@@ -5,29 +5,47 @@
# 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 0000000000002348 000348 000010 00 WA 0 0 8
+# SEC: .got PROGBITS 0000000000002378 000378 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: 0x2348 R_X86_64_TPOFF64 - 0x0
-# REL-NEXT: 0x2350 R_X86_64_TPOFF64 - 0x4
+# REL-NEXT: 0x2378 R_X86_64_TPOFF64 - 0x0
+# REL-NEXT: 0x2380 R_X86_64_TPOFF64 - 0x4
# REL-NEXT: }
-## &.got[0] - 0x127f = 0x2348 - 0x127f = 4297
-## &.got[1] - 0x1286 = 0x2350 - 0x1286 = 4298
-## &.got[2] - 0x128e = 0x2348 - 0x128e = 4282
-## &.got[3] - 0x1296 = 0x2350 - 0x1296 = 4282
+## &.got[0] - 0x127f = 0x2378 - 0x127f = 4345
+## &.got[1] - 0x1286 = 0x2380 - 0x1286 = 4346
+## &.got[2] - 0x128e = 0x2378 - 0x128e = 4330
+## &.got[3] - 0x1296 = 0x2380 - 0x1296 = 4330
+## &.got[0] - 0x12a0 = 0x2376 - 0x12a0 = 4310
+## &.got[1] - 0x12aa = 0x237e - 0x12aa = 4308
+## &.got[0] - 0x12b4 = 0x2376 - 0x12b4 = 4290
+## &.got[1] - 0x12be = 0x237e - 0x12be = 4288
+## &.got[0] - 0x12c8 = 0x2376 - 0x12c8 = 4270
-# CHECK: 1278: addq 4297(%rip), %rax
-# CHECK-NEXT: 127f: addq 4298(%rip), %rax
-# CHECK-NEXT: 1286: addq 4282(%rip), %r16
-# CHECK-NEXT: 128e: addq 4282(%rip), %r16
+# CHECK: 1278: addq 4345(%rip), %rax
+# CHECK-NEXT: 127f: addq 4346(%rip), %rax
+# CHECK-NEXT: 1286: addq 4330(%rip), %r16
+# CHECK-NEXT: 128e: addq 4330(%rip), %r16
+# CHECK-NEXT: 1296: addq %r8, 4310(%rip), %r16
+# CHECK-NEXT: 12a0: addq 4308(%rip), %rax, %r12
+# CHECK-NEXT: 12aa: {nf} addq %r8, 4290(%rip), %r16
+# CHECK-NEXT: 12b4: {nf} addq 4288(%rip), %rax, %r12
+# CHECK-NEXT: 12be: {nf} addq 4270(%rip), %r12
addq foo at GOTTPOFF(%rip), %rax
addq bar at GOTTPOFF(%rip), %rax
+# EGPR
addq foo at GOTTPOFF(%rip), %r16
addq bar at GOTTPOFF(%rip), %r16
-
+# 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