Skip to content

Commit 7193224

Browse files
committedMay 29, 2019
[ELF] Implement General Dynamic style TLSDESC for x86-64
This handles two initial relocation types R_X86_64_GOTPC32_TLSDESC and R_X86_64_TLSDESC_CALL, as well as the GD->LE and GD->IE relaxations. Reviewed By: ruiu Differential Revision: https://reviews.llvm.org/D62513 llvm-svn: 361911
1 parent 656afe3 commit 7193224

File tree

6 files changed

+172
-41
lines changed

6 files changed

+172
-41
lines changed
 

‎lld/ELF/Arch/X86_64.cpp

+79-36
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ X86_64::X86_64() {
5555
PltRel = R_X86_64_JUMP_SLOT;
5656
RelativeRel = R_X86_64_RELATIVE;
5757
IRelativeRel = R_X86_64_IRELATIVE;
58+
TlsDescRel = R_X86_64_TLSDESC;
5859
TlsGotRel = R_X86_64_TPOFF64;
5960
TlsModuleIndexRel = R_X86_64_DTPMOD64;
6061
TlsOffsetRel = R_X86_64_DTPOFF64;
@@ -88,6 +89,8 @@ RelExpr X86_64::getRelExpr(RelType Type, const Symbol &S,
8889
return R_DTPREL;
8990
case R_X86_64_TPOFF32:
9091
return R_TLS;
92+
case R_X86_64_TLSDESC_CALL:
93+
return R_TLSDESC_CALL;
9194
case R_X86_64_TLSLD:
9295
return R_TLSLD_PC;
9396
case R_X86_64_TLSGD:
@@ -105,6 +108,8 @@ RelExpr X86_64::getRelExpr(RelType Type, const Symbol &S,
105108
case R_X86_64_GOT32:
106109
case R_X86_64_GOT64:
107110
return R_GOTPLT;
111+
case R_X86_64_GOTPC32_TLSDESC:
112+
return R_TLSDESC_PC;
108113
case R_X86_64_GOTPCREL:
109114
case R_X86_64_GOTPCRELX:
110115
case R_X86_64_REX_GOTPCRELX:
@@ -173,45 +178,82 @@ RelType X86_64::getDynRel(RelType Type) const {
173178
}
174179

175180
void X86_64::relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
176-
// Convert
177-
// .byte 0x66
178-
// leaq x@tlsgd(%rip), %rdi
179-
// .word 0x6666
180-
// rex64
181-
// call __tls_get_addr@plt
182-
// to
183-
// mov %fs:0x0,%rax
184-
// lea x@tpoff,%rax
185-
const uint8_t Inst[] = {
186-
0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00, // mov %fs:0x0,%rax
187-
0x48, 0x8d, 0x80, 0, 0, 0, 0, // lea x@tpoff,%rax
188-
};
189-
memcpy(Loc - 4, Inst, sizeof(Inst));
190-
191-
// The original code used a pc relative relocation and so we have to
192-
// compensate for the -4 in had in the addend.
193-
write32le(Loc + 8, Val + 4);
181+
if (Type == R_X86_64_TLSGD) {
182+
// Convert
183+
// .byte 0x66
184+
// leaq x@tlsgd(%rip), %rdi
185+
// .word 0x6666
186+
// rex64
187+
// call __tls_get_addr@plt
188+
// to the following two instructions.
189+
const uint8_t Inst[] = {
190+
0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00,
191+
0x00, 0x00, // mov %fs:0x0,%rax
192+
0x48, 0x8d, 0x80, 0, 0, 0, 0, // lea x@tpoff,%rax
193+
};
194+
memcpy(Loc - 4, Inst, sizeof(Inst));
195+
196+
// The original code used a pc relative relocation and so we have to
197+
// compensate for the -4 in had in the addend.
198+
write32le(Loc + 8, Val + 4);
199+
} else {
200+
// Convert
201+
// lea x@tlsgd(%rip), %rax
202+
// call *(%rax)
203+
// to the following two instructions.
204+
assert(Type == R_X86_64_GOTPC32_TLSDESC);
205+
if (memcmp(Loc - 3, "\x48\x8d\x05", 3)) {
206+
error(getErrorLocation(Loc - 3) + "R_X86_64_GOTPC32_TLSDESC must be used "
207+
"in callq *x@tlsdesc(%rip), %rax");
208+
return;
209+
}
210+
// movq $x@tpoff(%rip),%rax
211+
Loc[-2] = 0xc7;
212+
Loc[-1] = 0xc0;
213+
write32le(Loc, Val + 4);
214+
// xchg ax,ax
215+
Loc[4] = 0x66;
216+
Loc[5] = 0x90;
217+
}
194218
}
195219

196220
void X86_64::relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const {
197-
// Convert
198-
// .byte 0x66
199-
// leaq x@tlsgd(%rip), %rdi
200-
// .word 0x6666
201-
// rex64
202-
// call __tls_get_addr@plt
203-
// to
204-
// mov %fs:0x0,%rax
205-
// addq x@tpoff,%rax
206-
const uint8_t Inst[] = {
207-
0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00, // mov %fs:0x0,%rax
208-
0x48, 0x03, 0x05, 0, 0, 0, 0, // addq x@tpoff,%rax
209-
};
210-
memcpy(Loc - 4, Inst, sizeof(Inst));
211-
212-
// Both code sequences are PC relatives, but since we are moving the constant
213-
// forward by 8 bytes we have to subtract the value by 8.
214-
write32le(Loc + 8, Val - 8);
221+
if (Type == R_X86_64_TLSGD) {
222+
// Convert
223+
// .byte 0x66
224+
// leaq x@tlsgd(%rip), %rdi
225+
// .word 0x6666
226+
// rex64
227+
// call __tls_get_addr@plt
228+
// to the following two instructions.
229+
const uint8_t Inst[] = {
230+
0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00,
231+
0x00, 0x00, // mov %fs:0x0,%rax
232+
0x48, 0x03, 0x05, 0, 0, 0, 0, // addq x@gottpoff(%rip),%rax
233+
};
234+
memcpy(Loc - 4, Inst, sizeof(Inst));
235+
236+
// Both code sequences are PC relatives, but since we are moving the
237+
// constant forward by 8 bytes we have to subtract the value by 8.
238+
write32le(Loc + 8, Val - 8);
239+
} else {
240+
// Convert
241+
// lea x@tlsgd(%rip), %rax
242+
// call *(%rax)
243+
// to the following two instructions.
244+
assert(Type == R_X86_64_GOTPC32_TLSDESC);
245+
if (memcmp(Loc - 3, "\x48\x8d\x05", 3)) {
246+
error(getErrorLocation(Loc - 3) + "R_X86_64_GOTPC32_TLSDESC must be used "
247+
"in callq *x@tlsdesc(%rip), %rax");
248+
return;
249+
}
250+
// movq x@gottpoff(%rip),%rax
251+
Loc[-2] = 0x8b;
252+
write32le(Loc, Val);
253+
// xchg ax,ax
254+
Loc[4] = 0x66;
255+
Loc[5] = 0x90;
256+
}
215257
}
216258

217259
// In some conditions, R_X86_64_GOTTPOFF relocation can be optimized to
@@ -331,6 +373,7 @@ void X86_64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
331373
case R_X86_64_TPOFF32:
332374
case R_X86_64_GOT32:
333375
case R_X86_64_GOTPC32:
376+
case R_X86_64_GOTPC32_TLSDESC:
334377
case R_X86_64_GOTPCREL:
335378
case R_X86_64_GOTPCRELX:
336379
case R_X86_64_REX_GOTPCRELX:

‎lld/ELF/InputSection.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -755,6 +755,8 @@ static uint64_t getRelocTargetVA(const InputFile *File, RelType Type, int64_t A,
755755
return Sym.getSize() + A;
756756
case R_TLSDESC:
757757
return In.Got->getGlobalDynAddr(Sym) + A;
758+
case R_TLSDESC_PC:
759+
return In.Got->getGlobalDynAddr(Sym) + A - P;
758760
case R_AARCH64_TLSDESC_PAGE:
759761
return getAArch64Page(In.Got->getGlobalDynAddr(Sym) + A) -
760762
getAArch64Page(P);

‎lld/ELF/Relocations.cpp

+6-5
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,8 @@ handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C,
217217
if (Config->EMachine == EM_MIPS)
218218
return handleMipsTlsRelocation(Type, Sym, C, Offset, Addend, Expr);
219219

220-
if (oneof<R_TLSDESC, R_AARCH64_TLSDESC_PAGE, R_TLSDESC_CALL>(Expr) &&
220+
if (oneof<R_AARCH64_TLSDESC_PAGE, R_TLSDESC, R_TLSDESC_CALL, R_TLSDESC_PC>(
221+
Expr) &&
221222
Config->Shared) {
222223
if (In.Got->addDynTlsEntry(Sym)) {
223224
uint64_t Off = In.Got->getGlobalDynOffset(Sym);
@@ -273,8 +274,8 @@ handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C,
273274
return 1;
274275
}
275276

276-
if (oneof<R_TLSDESC, R_AARCH64_TLSDESC_PAGE, R_TLSDESC_CALL, R_TLSGD_GOT,
277-
R_TLSGD_GOTPLT, R_TLSGD_PC>(Expr)) {
277+
if (oneof<R_AARCH64_TLSDESC_PAGE, R_TLSDESC, R_TLSDESC_CALL, R_TLSDESC_PC,
278+
R_TLSGD_GOT, R_TLSGD_GOTPLT, R_TLSGD_PC>(Expr)) {
278279
if (Config->Shared) {
279280
if (In.Got->addDynTlsEntry(Sym)) {
280281
uint64_t Off = In.Got->getGlobalDynOffset(Sym);
@@ -403,8 +404,8 @@ static bool isStaticLinkTimeConstant(RelExpr E, RelType Type, const Symbol &Sym,
403404
R_MIPS_GOT_OFF32, R_MIPS_GOT_GP_PC, R_MIPS_TLSGD,
404405
R_AARCH64_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC, R_GOTPLTONLY_PC,
405406
R_PLT_PC, R_TLSGD_GOT, R_TLSGD_GOTPLT, R_TLSGD_PC, R_PPC_CALL_PLT,
406-
R_PPC64_RELAX_TOC, R_TLSDESC_CALL, R_AARCH64_TLSDESC_PAGE, R_HINT, R_TLSLD_HINT,
407-
R_TLSIE_HINT>(E))
407+
R_PPC64_RELAX_TOC, R_TLSDESC_CALL, R_TLSDESC_PC,
408+
R_AARCH64_TLSDESC_PAGE, R_HINT, R_TLSLD_HINT, R_TLSIE_HINT>(E))
408409
return true;
409410

410411
// These never do, except if the entire file is position dependent or if

‎lld/ELF/Relocations.h

+1
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ enum RelExpr {
6161
R_TLS,
6262
R_TLSDESC,
6363
R_TLSDESC_CALL,
64+
R_TLSDESC_PC,
6465
R_TLSGD_GOT,
6566
R_TLSGD_GOTPLT,
6667
R_TLSGD_PC,
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# REQUIRES: x86
2+
# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
3+
# RUN: echo '.tbss; .globl a; a:' | llvm-mc -filetype=obj -triple=x86_64 - -o %t1.o
4+
# RUN: ld.lld -shared %t1.o -o %t1.so
5+
6+
## GD to LE relaxation.
7+
# RUN: not ld.lld %t.o %t1.o -o /dev/null 2>&1 | FileCheck -DINPUT=%t.o %s
8+
## GD to IE relaxation.
9+
# RUN: not ld.lld %t.o %t1.so -o /dev/null 2>&1 | FileCheck -DINPUT=%t.o %s
10+
11+
# CHECK: error: [[INPUT]]:(.text+0x0): R_X86_64_GOTPC32_TLSDESC must be used in callq *x@tlsdesc(%rip), %rax
12+
13+
leaq a@tlsdesc(%rip), %rdx
14+
call *a@tlscall(%rdx)
15+
movl %fs:(%rax), %eax

‎lld/test/ELF/x86-64-tlsdesc-gd.s

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# REQUIRES: x86
2+
# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
3+
# RUN: echo '.tbss; .globl b; b:' | llvm-mc -filetype=obj -triple=x86_64 - -o %t1.o
4+
# RUN: ld.lld -shared -soname=t1.so %t1.o -o %t1.so
5+
6+
# RUN: ld.lld -shared %t.o %t1.o -o %t.so
7+
# RUN: llvm-readobj -r %t.so | FileCheck --check-prefix=GD-REL %s
8+
# RUN: llvm-objdump -d --no-show-raw-insn %t.so | FileCheck --check-prefix=GD %s
9+
10+
# RUN: ld.lld %t.o %t1.o -o %t
11+
# RUN: llvm-readelf -r %t | FileCheck --check-prefix=NOREL %s
12+
# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=LE %s
13+
14+
# RUN: ld.lld %t.o %t1.so -o %t
15+
# RUN: llvm-readobj -r %t | FileCheck --check-prefix=IE-REL %s
16+
# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=IE %s
17+
18+
# GD-REL: .rela.dyn {
19+
# GD-REL-NEXT: 0x20A0 R_X86_64_TLSDESC a 0x0
20+
# GD-REL-NEXT: 0x20B0 R_X86_64_TLSDESC b 0x0
21+
# GD-REL-NEXT: }
22+
23+
# 0x20a0-0x1007 = 4249
24+
# GD: leaq 4249(%rip), %rax
25+
# GD-NEXT: 1007: callq *(%rax)
26+
# GD-NEXT: movl %fs:(%rax), %eax
27+
28+
# 0x20b0-0x1013 = 4253
29+
# GD-NEXT: leaq 4253(%rip), %rax
30+
# GD-NEXT: 1013: callq *(%rax)
31+
# GD-NEXT: movl %fs:(%rax), %eax
32+
33+
# NOREL: no relocations
34+
35+
## offset(a) = -4
36+
# LE: movq $-4, %rax
37+
# LE-NEXT: nop
38+
# LE-NEXT: movl %fs:(%rax), %eax
39+
## offset(b) = 0
40+
# LE: movq $0, %rax
41+
# LE-NEXT: nop
42+
# LE-NEXT: movl %fs:(%rax), %eax
43+
44+
# IE-REL: .rela.dyn {
45+
# IE-REL-NEXT: 0x2020C0 R_X86_64_TPOFF64 b 0x0
46+
# IE-REL-NEXT: }
47+
48+
## a is relaxed to use LE.
49+
# IE: movq $-4, %rax
50+
# IE-NEXT: nop
51+
# IE-NEXT: movl %fs:(%rax), %eax
52+
## 0x2020C0 - 0x201013 = 4269
53+
# IE-NEXT: movq 4269(%rip), %rax
54+
# IE-NEXT: 201013: nop
55+
# IE-NEXT: movl %fs:(%rax), %eax
56+
57+
leaq a@tlsdesc(%rip), %rax
58+
call *a@tlscall(%rax)
59+
movl %fs:(%rax), %eax
60+
61+
leaq b@tlsdesc(%rip), %rax
62+
call *b@tlscall(%rax)
63+
movl %fs:(%rax), %eax
64+
65+
.section .tbss
66+
.globl a
67+
.zero 8
68+
a:
69+
.zero 4

0 commit comments

Comments
 (0)
Please sign in to comment.