[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