Skip to content

Commit 8dc7366

Browse files
committed
[ELF] Support TLS GD/LD relaxations for x86-32 -fno-plt
For x86-32, {clang,gcc} -fno-plt uses `call *___tls_get_addr@GOT(%reg)` instead of `call ___tls_get_addr@PLT`. GD to IE/LE relaxations need to shift the offset by one while LD to LE relaxation needs to use a different code sequence. While here, fix some comments. Fix #59769 Differential Revision: https://reviews.llvm.org/D140813
1 parent 1e48ed3 commit 8dc7366

File tree

3 files changed

+54
-24
lines changed

3 files changed

+54
-24
lines changed

lld/ELF/Arch/X86.cpp

Lines changed: 35 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -346,18 +346,20 @@ void X86::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
346346

347347
static void relaxTlsGdToLe(uint8_t *loc, const Relocation &rel, uint64_t val) {
348348
if (rel.type == R_386_TLS_GD) {
349-
// Convert
349+
// Convert (loc[-2] == 0x04)
350350
// leal x@tlsgd(, %ebx, 1), %eax
351-
// call __tls_get_addr@plt
351+
// call ___tls_get_addr@plt
352+
// or
353+
// leal x@tlsgd(%reg), %eax
354+
// call *___tls_get_addr@got(%reg)
352355
// to
353-
// movl %gs:0, %eax
354-
// subl $x@tpoff, %eax
355356
const uint8_t inst[] = {
356357
0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0, %eax
357-
0x81, 0xe8, 0, 0, 0, 0, // subl val(%ebx), %eax
358+
0x81, 0xe8, 0, 0, 0, 0, // subl x@ntpoff(%ebx), %eax
358359
};
359-
memcpy(loc - 3, inst, sizeof(inst));
360-
write32le(loc + 5, val);
360+
uint8_t *w = loc[-2] == 0x04 ? loc - 3 : loc - 2;
361+
memcpy(w, inst, sizeof(inst));
362+
write32le(w + 8, val);
361363
} else if (rel.type == R_386_TLS_GOTDESC) {
362364
// Convert leal x@tlsdesc(%ebx), %eax to leal x@ntpoff, %eax.
363365
//
@@ -379,18 +381,19 @@ static void relaxTlsGdToLe(uint8_t *loc, const Relocation &rel, uint64_t val) {
379381

380382
static void relaxTlsGdToIe(uint8_t *loc, const Relocation &rel, uint64_t val) {
381383
if (rel.type == R_386_TLS_GD) {
382-
// Convert
384+
// Convert (loc[-2] == 0x04)
383385
// leal x@tlsgd(, %ebx, 1), %eax
384-
// call __tls_get_addr@plt
385-
// to
386-
// movl %gs:0, %eax
387-
// addl x@gotntpoff(%ebx), %eax
386+
// call ___tls_get_addr@plt
387+
// or
388+
// leal x@tlsgd(%reg), %eax
389+
// call *___tls_get_addr@got(%reg)
388390
const uint8_t inst[] = {
389391
0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0, %eax
390-
0x03, 0x83, 0, 0, 0, 0, // addl val(%ebx), %eax
392+
0x03, 0x83, 0, 0, 0, 0, // addl x@gottpoff(%ebx), %eax
391393
};
392-
memcpy(loc - 3, inst, sizeof(inst));
393-
write32le(loc + 5, val);
394+
uint8_t *w = loc[-2] == 0x04 ? loc - 3 : loc - 2;
395+
memcpy(w, inst, sizeof(inst));
396+
write32le(w + 8, val);
394397
} else if (rel.type == R_386_TLS_GOTDESC) {
395398
// Convert leal x@tlsdesc(%ebx), %eax to movl x@gotntpoff(%ebx), %eax.
396399
if (memcmp(loc - 2, "\x8d\x83", 2)) {
@@ -453,17 +456,27 @@ static void relaxTlsLdToLe(uint8_t *loc, const Relocation &rel, uint64_t val) {
453456
return;
454457
}
455458

459+
if (loc[4] == 0xe8) {
460+
// Convert
461+
// leal x(%reg),%eax
462+
// call ___tls_get_addr@plt
463+
// to
464+
const uint8_t inst[] = {
465+
0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0,%eax
466+
0x90, // nop
467+
0x8d, 0x74, 0x26, 0x00, // leal 0(%esi,1),%esi
468+
};
469+
memcpy(loc - 2, inst, sizeof(inst));
470+
return;
471+
}
472+
456473
// Convert
457-
// leal foo(%reg),%eax
458-
// call ___tls_get_addr
474+
// leal x(%reg),%eax
475+
// call *___tls_get_addr@got(%reg)
459476
// to
460-
// movl %gs:0,%eax
461-
// nop
462-
// leal 0(%esi,1),%esi
463477
const uint8_t inst[] = {
464478
0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0,%eax
465-
0x90, // nop
466-
0x8d, 0x74, 0x26, 0x00, // leal 0(%esi,1),%esi
479+
0x8d, 0xb6, 0x00, 0x00, 0x00, 0x00, // leal (%esi),%esi
467480
};
468481
memcpy(loc - 2, inst, sizeof(inst));
469482
}

lld/test/ELF/i386-tls-gdiele.s

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88

99
// NORELOC: Relocations [
1010
// NORELOC-NEXT: Section ({{.*}}) .rel.dyn {
11-
// NORELOC-NEXT: 0x402258 R_386_TLS_TPOFF tlsshared0
12-
// NORELOC-NEXT: 0x40225C R_386_TLS_TPOFF tlsshared1
11+
// NORELOC-NEXT: 0x402270 R_386_TLS_TPOFF tlsshared0
12+
// NORELOC-NEXT: 0x402274 R_386_TLS_TPOFF tlsshared1
1313
// NORELOC-NEXT: }
1414
// NORELOC-NEXT: ]
1515

@@ -24,6 +24,10 @@
2424
// DISASM-NEXT: subl $8, %eax
2525
// DISASM-NEXT: movl %gs:0, %eax
2626
// DISASM-NEXT: subl $4, %eax
27+
// DISASM-NEXT: movl %gs:0, %eax
28+
// DISASM-NEXT: addl -4100(%ebx), %eax
29+
// DISASM-NEXT: movl %gs:0, %eax
30+
// DISASM-NEXT: subl $4, %eax
2731

2832
.type tlsexe1,@object
2933
.section .tbss,"awT",@nobits
@@ -59,3 +63,9 @@ leal tlsexe1@tlsgd(,%ebx,1),%eax
5963
call ___tls_get_addr@plt
6064
leal tlsexe2@tlsgd(,%ebx,1),%eax
6165
call ___tls_get_addr@plt
66+
67+
// -fno-plt GD->IE and GD->LE
68+
leal tlsshared1@tlsgd(%edx),%eax
69+
call *___tls_get_addr@GOT(%edx)
70+
leal tlsexe2@tlsgd(%edx),%eax
71+
call *___tls_get_addr@GOT(%edx)

lld/test/ELF/i386-tls-opt.s

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
// DISASM-NEXT: nop
2020
// DISASM-NEXT: leal (%esi,%eiz), %esi
2121
// DISASM-NEXT: leal -4(%eax), %edx
22+
// DISASM-NEXT: movl %gs:0, %eax
23+
// DISASM-NEXT: leal (%esi), %esi
24+
// DISASM-NEXT: movl -4(%eax), %edx
2225
// IE -> LE:
2326
// 4294967288 == 0xFFFFFFF8
2427
// 4294967292 == 0xFFFFFFFC
@@ -60,6 +63,10 @@ leal tls0@dtpoff(%eax),%edx
6063
leal tls1@tlsldm(%ebx),%eax
6164
call ___tls_get_addr@plt
6265
leal tls1@dtpoff(%eax),%edx
66+
// -fno-plt LD -> LE
67+
leal tls1@tlsldm(%edx),%eax
68+
call *___tls_get_addr@GOT(%edx)
69+
movl tls1@dtpoff(%eax), %edx
6370
//IE -> LE:
6471
movl %gs:0,%eax
6572
movl tls0@gotntpoff(%ebx),%eax

0 commit comments

Comments
 (0)