[lld] 8dc7366 - [ELF] Support TLS GD/LD relaxations for x86-32 -fno-plt
Fangrui Song via llvm-commits
llvm-commits at lists.llvm.org
Sat Dec 31 20:51:02 PST 2022
Author: Fangrui Song
Date: 2022-12-31T20:50:54-08:00
New Revision: 8dc73662ab5f7c992f9d7778de7c3611c1d5367e
URL: https://github.com/llvm/llvm-project/commit/8dc73662ab5f7c992f9d7778de7c3611c1d5367e
DIFF: https://github.com/llvm/llvm-project/commit/8dc73662ab5f7c992f9d7778de7c3611c1d5367e.diff
LOG: [ELF] Support TLS GD/LD relaxations for x86-32 -fno-plt
For x86-32, {clang,gcc} -fno-plt uses `call *___tls_get_addr at GOT(%reg)` instead
of `call ___tls_get_addr at 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 https://github.com/llvm/llvm-project/issues/59769
Differential Revision: https://reviews.llvm.org/D140813
Added:
Modified:
lld/ELF/Arch/X86.cpp
lld/test/ELF/i386-tls-gdiele.s
lld/test/ELF/i386-tls-opt.s
Removed:
################################################################################
diff --git a/lld/ELF/Arch/X86.cpp b/lld/ELF/Arch/X86.cpp
index eb068f408685a..8d4f258e2cf24 100644
--- a/lld/ELF/Arch/X86.cpp
+++ b/lld/ELF/Arch/X86.cpp
@@ -346,18 +346,20 @@ void X86::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
static void relaxTlsGdToLe(uint8_t *loc, const Relocation &rel, uint64_t val) {
if (rel.type == R_386_TLS_GD) {
- // Convert
+ // Convert (loc[-2] == 0x04)
// leal x at tlsgd(, %ebx, 1), %eax
- // call __tls_get_addr at plt
+ // call ___tls_get_addr at plt
+ // or
+ // leal x at tlsgd(%reg), %eax
+ // call *___tls_get_addr at got(%reg)
// to
- // movl %gs:0, %eax
- // subl $x at tpoff, %eax
const uint8_t inst[] = {
0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0, %eax
- 0x81, 0xe8, 0, 0, 0, 0, // subl val(%ebx), %eax
+ 0x81, 0xe8, 0, 0, 0, 0, // subl x at ntpoff(%ebx), %eax
};
- memcpy(loc - 3, inst, sizeof(inst));
- write32le(loc + 5, val);
+ uint8_t *w = loc[-2] == 0x04 ? loc - 3 : loc - 2;
+ memcpy(w, inst, sizeof(inst));
+ write32le(w + 8, val);
} else if (rel.type == R_386_TLS_GOTDESC) {
// Convert leal x at tlsdesc(%ebx), %eax to leal x at ntpoff, %eax.
//
@@ -379,18 +381,19 @@ static void relaxTlsGdToLe(uint8_t *loc, const Relocation &rel, uint64_t val) {
static void relaxTlsGdToIe(uint8_t *loc, const Relocation &rel, uint64_t val) {
if (rel.type == R_386_TLS_GD) {
- // Convert
+ // Convert (loc[-2] == 0x04)
// leal x at tlsgd(, %ebx, 1), %eax
- // call __tls_get_addr at plt
- // to
- // movl %gs:0, %eax
- // addl x at gotntpoff(%ebx), %eax
+ // call ___tls_get_addr at plt
+ // or
+ // leal x at tlsgd(%reg), %eax
+ // call *___tls_get_addr at got(%reg)
const uint8_t inst[] = {
0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0, %eax
- 0x03, 0x83, 0, 0, 0, 0, // addl val(%ebx), %eax
+ 0x03, 0x83, 0, 0, 0, 0, // addl x at gottpoff(%ebx), %eax
};
- memcpy(loc - 3, inst, sizeof(inst));
- write32le(loc + 5, val);
+ uint8_t *w = loc[-2] == 0x04 ? loc - 3 : loc - 2;
+ memcpy(w, inst, sizeof(inst));
+ write32le(w + 8, val);
} else if (rel.type == R_386_TLS_GOTDESC) {
// Convert leal x at tlsdesc(%ebx), %eax to movl x at gotntpoff(%ebx), %eax.
if (memcmp(loc - 2, "\x8d\x83", 2)) {
@@ -453,17 +456,27 @@ static void relaxTlsLdToLe(uint8_t *loc, const Relocation &rel, uint64_t val) {
return;
}
+ if (loc[4] == 0xe8) {
+ // Convert
+ // leal x(%reg),%eax
+ // call ___tls_get_addr at plt
+ // to
+ const uint8_t inst[] = {
+ 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0,%eax
+ 0x90, // nop
+ 0x8d, 0x74, 0x26, 0x00, // leal 0(%esi,1),%esi
+ };
+ memcpy(loc - 2, inst, sizeof(inst));
+ return;
+ }
+
// Convert
- // leal foo(%reg),%eax
- // call ___tls_get_addr
+ // leal x(%reg),%eax
+ // call *___tls_get_addr at got(%reg)
// to
- // movl %gs:0,%eax
- // nop
- // leal 0(%esi,1),%esi
const uint8_t inst[] = {
0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0,%eax
- 0x90, // nop
- 0x8d, 0x74, 0x26, 0x00, // leal 0(%esi,1),%esi
+ 0x8d, 0xb6, 0x00, 0x00, 0x00, 0x00, // leal (%esi),%esi
};
memcpy(loc - 2, inst, sizeof(inst));
}
diff --git a/lld/test/ELF/i386-tls-gdiele.s b/lld/test/ELF/i386-tls-gdiele.s
index f349975f892cb..e698088c9f0b4 100644
--- a/lld/test/ELF/i386-tls-gdiele.s
+++ b/lld/test/ELF/i386-tls-gdiele.s
@@ -8,8 +8,8 @@
// NORELOC: Relocations [
// NORELOC-NEXT: Section ({{.*}}) .rel.dyn {
-// NORELOC-NEXT: 0x402258 R_386_TLS_TPOFF tlsshared0
-// NORELOC-NEXT: 0x40225C R_386_TLS_TPOFF tlsshared1
+// NORELOC-NEXT: 0x402270 R_386_TLS_TPOFF tlsshared0
+// NORELOC-NEXT: 0x402274 R_386_TLS_TPOFF tlsshared1
// NORELOC-NEXT: }
// NORELOC-NEXT: ]
@@ -24,6 +24,10 @@
// DISASM-NEXT: subl $8, %eax
// DISASM-NEXT: movl %gs:0, %eax
// DISASM-NEXT: subl $4, %eax
+// DISASM-NEXT: movl %gs:0, %eax
+// DISASM-NEXT: addl -4100(%ebx), %eax
+// DISASM-NEXT: movl %gs:0, %eax
+// DISASM-NEXT: subl $4, %eax
.type tlsexe1, at object
.section .tbss,"awT", at nobits
@@ -59,3 +63,9 @@ leal tlsexe1 at tlsgd(,%ebx,1),%eax
call ___tls_get_addr at plt
leal tlsexe2 at tlsgd(,%ebx,1),%eax
call ___tls_get_addr at plt
+
+// -fno-plt GD->IE and GD->LE
+leal tlsshared1 at tlsgd(%edx),%eax
+call *___tls_get_addr at GOT(%edx)
+leal tlsexe2 at tlsgd(%edx),%eax
+call *___tls_get_addr at GOT(%edx)
diff --git a/lld/test/ELF/i386-tls-opt.s b/lld/test/ELF/i386-tls-opt.s
index 4ca640ad9eec9..9cb63f6292dcd 100644
--- a/lld/test/ELF/i386-tls-opt.s
+++ b/lld/test/ELF/i386-tls-opt.s
@@ -19,6 +19,9 @@
// DISASM-NEXT: nop
// DISASM-NEXT: leal (%esi,%eiz), %esi
// DISASM-NEXT: leal -4(%eax), %edx
+// DISASM-NEXT: movl %gs:0, %eax
+// DISASM-NEXT: leal (%esi), %esi
+// DISASM-NEXT: movl -4(%eax), %edx
// IE -> LE:
// 4294967288 == 0xFFFFFFF8
// 4294967292 == 0xFFFFFFFC
@@ -60,6 +63,10 @@ leal tls0 at dtpoff(%eax),%edx
leal tls1 at tlsldm(%ebx),%eax
call ___tls_get_addr at plt
leal tls1 at dtpoff(%eax),%edx
+// -fno-plt LD -> LE
+leal tls1 at tlsldm(%edx),%eax
+call *___tls_get_addr at GOT(%edx)
+movl tls1 at dtpoff(%eax), %edx
//IE -> LE:
movl %gs:0,%eax
movl tls0 at gotntpoff(%ebx),%eax
More information about the llvm-commits
mailing list