Skip to content

Commit 36ea5a1

Browse files
fzou1KornevNikita
authored andcommitted
[X86][LLD] Handle R_X86_64_CODE_6_GOTTPOFF relocation type (#117675)
For add %reg1, name@GOTTPOFF(%rip), %reg2 add name@GOTTPOFF(%rip), %reg1, %reg2 {nf} add %reg1, name@GOTTPOFF(%rip), %reg2 {nf} add name@GOTTPOFF(%rip), %reg1, %reg2 {nf} add name@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@tpoff, %reg1, %reg2 add $name@tpoff, %reg1, %reg2 {nf} add $name@tpoff, %reg1, %reg2 {nf} add $name@tpoff, %reg1, %reg2 {nf} add $name@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@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
1 parent aa20a05 commit 36ea5a1

File tree

6 files changed

+270
-21
lines changed

6 files changed

+270
-21
lines changed

lld/ELF/Arch/X86_64.cpp

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,7 @@ RelExpr X86_64::getRelExpr(RelType type, const Symbol &s,
397397
case R_X86_64_CODE_4_GOTPCRELX:
398398
case R_X86_64_GOTTPOFF:
399399
case R_X86_64_CODE_4_GOTTPOFF:
400+
case R_X86_64_CODE_6_GOTTPOFF:
400401
return R_GOT_PC;
401402
case R_X86_64_GOTOFF64:
402403
return R_GOTPLTREL;
@@ -548,8 +549,9 @@ void X86_64::relaxTlsGdToIe(uint8_t *loc, const Relocation &rel,
548549
}
549550
}
550551

551-
// In some conditions, R_X86_64_GOTTPOFF/R_X86_64_CODE_4_GOTTPOFF relocation can
552-
// be optimized to R_X86_64_TPOFF32 so that it does not use GOT.
552+
// In some conditions,
553+
// R_X86_64_GOTTPOFF/R_X86_64_CODE_4_GOTTPOFF/R_X86_64_CODE_6_GOTTPOFF
554+
// relocation can be optimized to R_X86_64_TPOFF32 so that it does not use GOT.
553555
void X86_64::relaxTlsIeToLe(uint8_t *loc, const Relocation &rel,
554556
uint64_t val) const {
555557
uint8_t *inst = loc - 3;
@@ -591,7 +593,7 @@ void X86_64::relaxTlsIeToLe(uint8_t *loc, const Relocation &rel,
591593
} else if (rel.type == R_X86_64_CODE_4_GOTTPOFF) {
592594
if (loc[-4] != 0xd5) {
593595
Err(ctx) << getErrorLoc(ctx, loc - 4)
594-
<< "Invalid prefix with R_X86_64_CODE_4_GOTTPOFF!";
596+
<< "invalid prefix with R_X86_64_CODE_4_GOTTPOFF!";
595597
return;
596598
}
597599
const uint8_t rex = loc[-3];
@@ -609,6 +611,41 @@ void X86_64::relaxTlsIeToLe(uint8_t *loc, const Relocation &rel,
609611
<< "R_X86_64_CODE_4_GOTTPOFF must be used in MOVQ or ADDQ "
610612
"instructions only";
611613
}
614+
} else if (rel.type == R_X86_64_CODE_6_GOTTPOFF) {
615+
if (loc[-6] != 0x62) {
616+
Err(ctx) << getErrorLoc(ctx, loc - 6)
617+
<< "invalid prefix with R_X86_64_CODE_6_GOTTPOFF!";
618+
return;
619+
}
620+
// Check bits are satisfied:
621+
// loc[-5]: X==1 (inverted polarity), (loc[-5] & 0x7) == 0x4
622+
// loc[-4]: W==1, X2==1 (inverted polarity), pp==0b00(NP)
623+
// loc[-3]: NF==1 or ND==1
624+
// loc[-2]: opcode==0x1 or opcode==0x3
625+
// loc[-1]: Mod==0b00, RM==0b101
626+
if (((loc[-5] & 0x47) == 0x44) && ((loc[-4] & 0x87) == 0x84) &&
627+
((loc[-3] & 0x14) != 0) && (loc[-2] == 0x1 || loc[-2] == 0x3) &&
628+
((loc[-1] & 0xc7) == 0x5)) {
629+
// "addq %reg1, foo@GOTTPOFF(%rip), %reg2" -> "addq $foo, %reg1, %reg2"
630+
// "addq foo@GOTTPOFF(%rip), %reg1, %reg2" -> "addq $foo, %reg1, %reg2"
631+
// "{nf} addq %reg1, foo@GOTTPOFF(%rip), %reg2"
632+
// -> "{nf} addq $foo, %reg1, %reg2"
633+
// "{nf} addq name@GOTTPOFF(%rip), %reg1, %reg2"
634+
// -> "{nf} addq $foo, %reg1, %reg2"
635+
// "{nf} addq name@GOTTPOFF(%rip), %reg" -> "{nf} addq $foo, %reg"
636+
loc[-2] = 0x81;
637+
// Move R bits to B bits in EVEX payloads and ModRM byte.
638+
const uint8_t evexPayload0 = loc[-5];
639+
if ((evexPayload0 & (1 << 7)) == 0)
640+
loc[-5] = (evexPayload0 | (1 << 7)) & ~(1 << 5);
641+
if ((evexPayload0 & (1 << 4)) == 0)
642+
loc[-5] = evexPayload0 | (1 << 4) | (1 << 3);
643+
*regSlot = 0xc0 | reg;
644+
} else {
645+
Err(ctx) << getErrorLoc(ctx, loc - 6)
646+
<< "R_X86_64_CODE_6_GOTTPOFF must be used in ADDQ instructions "
647+
"with NDD/NF/NDD+NF only";
648+
}
612649
} else {
613650
llvm_unreachable("Unsupported relocation type!");
614651
}
@@ -768,6 +805,7 @@ int64_t X86_64::getImplicitAddend(const uint8_t *buf, RelType type) const {
768805
case R_X86_64_PC32:
769806
case R_X86_64_GOTTPOFF:
770807
case R_X86_64_CODE_4_GOTTPOFF:
808+
case R_X86_64_CODE_6_GOTTPOFF:
771809
case R_X86_64_PLT32:
772810
case R_X86_64_TLSGD:
773811
case R_X86_64_TLSLD:
@@ -879,6 +917,7 @@ void X86_64::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
879917
break;
880918
case R_X86_64_GOTTPOFF:
881919
case R_X86_64_CODE_4_GOTTPOFF:
920+
case R_X86_64_CODE_6_GOTTPOFF:
882921
if (rel.expr == R_RELAX_TLS_IE_TO_LE) {
883922
relaxTlsIeToLe(loc, rel, val);
884923
} else {

lld/test/ELF/invalid/broken-relaxation-x64.test

Lines changed: 133 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
# REQUIRES: x86
22

3-
# RUN: yaml2obj %s -o %t.o
4-
# RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck --check-prefix=ERR %s
5-
# ERR: R_X86_64_GOTTPOFF must be used in MOVQ or ADDQ instructions only
6-
# ERR: R_X86_64_GOTTPOFF must be used in MOVQ or ADDQ instructions only
3+
# RUN: yaml2obj --docnum=1 %s -o %t1.o
4+
# RUN: not ld.lld %t1.o -o /dev/null 2>&1 | FileCheck --check-prefix=ERR %s
5+
# ERR: error: {{.*}}: R_X86_64_GOTTPOFF must be used in MOVQ or ADDQ instructions only
6+
# ERR: error: {{.*}}: R_X86_64_GOTTPOFF must be used in MOVQ or ADDQ instructions only
77

88
## YAML below contains 2 relocations of type R_X86_64_GOTTPOFF, and a .text
99
## with fake content filled by 0xFF. That means instructions for relaxation are
1010
## "broken", so they does not match any known valid relaxations. We also generate
1111
## .tls section because we need it for correct processing of STT_TLS symbol.
12-
!ELF
12+
--- !ELF
1313
FileHeader:
1414
Class: ELFCLASS64
1515
Data: ELFDATA2LSB
@@ -44,4 +44,131 @@ Symbols:
4444
Value: 0x12345
4545
Size: 4
4646
Binding: STB_GLOBAL
47-
47+
48+
49+
# RUN: yaml2obj --docnum=2 %s -o %t2.o
50+
# RUN: not ld.lld %t2.o -o /dev/null 2>&1 | FileCheck --check-prefix=ERR2 %s
51+
# ERR2: error: {{.*}}: invalid prefix with R_X86_64_CODE_4_GOTTPOFF!
52+
# ERR2: error: {{.*}}: invalid prefix with R_X86_64_CODE_6_GOTTPOFF!
53+
54+
## YAML below contains 2 relocations of
55+
## R_X86_64_CODE_4_GOTTPOFF/R_X86_64_CODE_6_GOTTPOFF type, and a .text with
56+
## fake content filled by 0xFF. It's expected to get "invalid prefix" error
57+
## message as above.
58+
--- !ELF
59+
FileHeader:
60+
Class: ELFCLASS64
61+
Data: ELFDATA2LSB
62+
OSABI: ELFOSABI_FREEBSD
63+
Type: ET_REL
64+
Machine: EM_X86_64
65+
Sections:
66+
- Type: SHT_PROGBITS
67+
Name: .text
68+
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
69+
AddressAlign: 0x04
70+
Content: "FFFFFFFFFFFFFFFFFFFF"
71+
- Type: SHT_PROGBITS
72+
Name: .tls
73+
Flags: [ SHF_ALLOC, SHF_TLS ]
74+
- Type: SHT_REL
75+
Name: .rel.text
76+
Link: .symtab
77+
Info: .text
78+
AddressAlign: 0x04
79+
Relocations:
80+
- Offset: 4
81+
Symbol: foo
82+
Type: R_X86_64_CODE_4_GOTTPOFF
83+
- Offset: 6
84+
Symbol: foo
85+
Type: R_X86_64_CODE_6_GOTTPOFF
86+
Symbols:
87+
- Name: foo
88+
Type: STT_TLS
89+
Section: .text
90+
Value: 0x12345
91+
Size: 4
92+
Binding: STB_GLOBAL
93+
94+
95+
# RUN: yaml2obj --docnum=3 %s -o %t3.o
96+
# RUN: not ld.lld %t3.o -o /dev/null 2>&1 | FileCheck --check-prefix=ERR3 %s
97+
# ERR3: error: {{.*}}: R_X86_64_CODE_4_GOTTPOFF must be used in MOVQ or ADDQ instructions only
98+
99+
## YAML below contains R_X86_64_CODE_4_GOTTPOFF relocation type, and a .text
100+
## with fake content filled by 0xd5, 0xFF, ... and 0xFF. It's expected to get
101+
## the error message as above.
102+
--- !ELF
103+
FileHeader:
104+
Class: ELFCLASS64
105+
Data: ELFDATA2LSB
106+
OSABI: ELFOSABI_FREEBSD
107+
Type: ET_REL
108+
Machine: EM_X86_64
109+
Sections:
110+
- Type: SHT_PROGBITS
111+
Name: .text
112+
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
113+
AddressAlign: 0x04
114+
Content: "d5FFFFFFFFFFFFFFFFFF"
115+
- Type: SHT_PROGBITS
116+
Name: .tls
117+
Flags: [ SHF_ALLOC, SHF_TLS ]
118+
- Type: SHT_REL
119+
Name: .rel.text
120+
Link: .symtab
121+
Info: .text
122+
AddressAlign: 0x04
123+
Relocations:
124+
- Offset: 4
125+
Symbol: foo
126+
Type: R_X86_64_CODE_4_GOTTPOFF
127+
Symbols:
128+
- Name: foo
129+
Type: STT_TLS
130+
Section: .text
131+
Value: 0x12345
132+
Size: 4
133+
Binding: STB_GLOBAL
134+
135+
136+
# RUN: yaml2obj --docnum=4 %s -o %t4.o
137+
# RUN: not ld.lld %t4.o -o /dev/null 2>&1 | FileCheck --check-prefix=ERR4 %s
138+
# ERR4: error: {{.*}}: R_X86_64_CODE_6_GOTTPOFF must be used in ADDQ instructions with NDD/NF/NDD+NF only
139+
140+
## YAML below contains R_X86_64_CODE_6_GOTTPOFF relocation type, and a .text
141+
## with fake content filled by 0x62, 0xFF, ... and 0xFF. It's expected to get
142+
## the error message as above.
143+
--- !ELF
144+
FileHeader:
145+
Class: ELFCLASS64
146+
Data: ELFDATA2LSB
147+
OSABI: ELFOSABI_FREEBSD
148+
Type: ET_REL
149+
Machine: EM_X86_64
150+
Sections:
151+
- Type: SHT_PROGBITS
152+
Name: .text
153+
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
154+
AddressAlign: 0x04
155+
Content: "62FFFFFFFFFFFFFFFFFF"
156+
- Type: SHT_PROGBITS
157+
Name: .tls
158+
Flags: [ SHF_ALLOC, SHF_TLS ]
159+
- Type: SHT_REL
160+
Name: .rel.text
161+
Link: .symtab
162+
Info: .text
163+
AddressAlign: 0x04
164+
Relocations:
165+
- Offset: 6
166+
Symbol: foo
167+
Type: R_X86_64_CODE_6_GOTTPOFF
168+
Symbols:
169+
- Name: foo
170+
Type: STT_TLS
171+
Section: .text
172+
Value: 0x12345
173+
Size: 4
174+
Binding: STB_GLOBAL

lld/test/ELF/pack-dyn-relocs-tls-x86-64.s

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
foo:
1414
movq tlsvar@GOTTPOFF(%rip), %rcx
1515
movq tlsvar2@GOTTPOFF(%rip), %r31
16+
addq tlsvar3@GOTTPOFF(%rip), %rcx, %r16
1617

1718

1819
.section .tdata,"awT",@progbits
@@ -21,7 +22,11 @@ tlsvar:
2122
.word 42
2223
tlsvar2:
2324
.word 42
25+
tlsvar3:
26+
.word 42
27+
2428
// CHECK: Section ({{.+}}) .rela.dyn {
2529
// CHECK-NEXT: R_X86_64_TPOFF64 - 0x1234
2630
// CHECK-NEXT: R_X86_64_TPOFF64 - 0x1236
31+
// CHECK-NEXT: R_X86_64_TPOFF64 - 0x1238
2732
// CHECK-NEXT: }

lld/test/ELF/tls-opt.s

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,25 @@
2020
// DISASM-NEXT: leaq -4(%r15), %r15
2121
// DISASM-NEXT: addq $-4, %rsp
2222
// DISASM-NEXT: addq $-4, %r12
23+
# EGPR
2324
// DISASM-NEXT: movq $-8, %r16
2425
// DISASM-NEXT: movq $-8, %r20
2526
// DISASM-NEXT: movq $-4, %r16
2627
// DISASM-NEXT: addq $-8, %r16
2728
// DISASM-NEXT: addq $-8, %r28
2829
// DISASM-NEXT: addq $-4, %r16
30+
# NDD
31+
// DISASM-NEXT: addq $-10, %r16, %r16
32+
// DISASM-NEXT: addq $-10, %r16, %r20
33+
// DISASM-NEXT: addq $-10, %r16, %rax
34+
// DISASM-NEXT: addq $-10, %rax, %r16
35+
// DISASM-NEXT: addq $-10, %r8, %r16
36+
// DISASM-NEXT: addq $-10, %rax, %r12
37+
# NDD + NF
38+
// DISASM-NEXT: {nf} addq $-10, %r8, %r16
39+
// DISASM-NEXT: {nf} addq $-10, %rax, %r12
40+
# NF
41+
// DISASM-NEXT: {nf} addq $-10, %r12
2942

3043
// LD to LE:
3144
// DISASM-NEXT: movq %fs:0, %rax
@@ -82,6 +95,18 @@ _start:
8295
addq tls0@GOTTPOFF(%rip), %r16
8396
addq tls0@GOTTPOFF(%rip), %r28
8497
addq tls1@GOTTPOFF(%rip), %r16
98+
# NDD
99+
addq tls0@GOTTPOFF(%rip), %r16, %r16
100+
addq tls0@GOTTPOFF(%rip), %r16, %r20
101+
addq tls0@GOTTPOFF(%rip), %r16, %rax
102+
addq tls0@GOTTPOFF(%rip), %rax, %r16
103+
addq %r8, tls0@GOTTPOFF(%rip), %r16
104+
addq tls0@GOTTPOFF(%rip), %rax, %r12
105+
# NDD + NF
106+
{nf} addq %r8, tls0@GOTTPOFF(%rip), %r16
107+
{nf} addq tls0@GOTTPOFF(%rip), %rax, %r12
108+
# NF
109+
{nf} addq tls0@GOTTPOFF(%rip), %r12
85110

86111
// LD to LE
87112
leaq tls0@tlsld(%rip), %rdi

lld/test/ELF/x86-64-tls-ie-err.s

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# REQUIRES: x86
2+
# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
3+
# RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck -DFILE=%t.o %s
4+
5+
# CHECK: error: [[FILE]]:(.text+0x2): invalid prefix with R_X86_64_CODE_4_GOTTPOFF!
6+
# CHECK-NEXT: error: [[FILE]]:(.text+0x8): invalid prefix with R_X86_64_CODE_6_GOTTPOFF!
7+
# CHECK-NEXT: error: [[FILE]]:(.text+0x12): R_X86_64_CODE_4_GOTTPOFF must be used in MOVQ or ADDQ instructions only
8+
# CHECK-NEXT: error: [[FILE]]:(.text+0x1a): R_X86_64_CODE_6_GOTTPOFF must be used in ADDQ instructions with NDD/NF/NDD+NF only
9+
10+
## These negative tests are to check if the invalid prefix and unsupported
11+
## instructions for TLS relocation types with APX instructions are handled as
12+
## errors.
13+
14+
.type tls0,@object
15+
.section .tbss,"awT",@nobits
16+
.globl tls0
17+
.align 4
18+
tls0:
19+
.long 0
20+
.size tls0, 4
21+
22+
.text
23+
.globl _start
24+
_start:
25+
addq 0(%rip), %rax, %r16
26+
.reloc .-4, R_X86_64_CODE_4_GOTTPOFF, tls0-4
27+
28+
movq 0(%rip), %r16
29+
.reloc .-4, R_X86_64_CODE_6_GOTTPOFF, tls0-4
30+
31+
andq 0(%rip), %r16
32+
.reloc .-4, R_X86_64_CODE_4_GOTTPOFF, tls0-4
33+
34+
andq 0(%rip), %rax, %r16
35+
.reloc .-4, R_X86_64_CODE_6_GOTTPOFF, tls0-4

0 commit comments

Comments
 (0)