[lld] e39c138 - [ELF] Implement TLSDESC for x86-32

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Thu Oct 28 17:52:07 PDT 2021


Author: Fangrui Song
Date: 2021-10-28T17:52:03-07:00
New Revision: e39c138f4522baef5cd060fd8b5e715d72e77a6a

URL: https://github.com/llvm/llvm-project/commit/e39c138f4522baef5cd060fd8b5e715d72e77a6a
DIFF: https://github.com/llvm/llvm-project/commit/e39c138f4522baef5cd060fd8b5e715d72e77a6a.diff

LOG: [ELF] Implement TLSDESC for x86-32

`-z rela` is also supported.

Tested with:

```
cat > ./a.c <<eof
#include <assert.h>
int foo();
int bar();
int main() {
  assert(foo() == 2);
  assert(foo() == 4);
  assert(bar() == 2);
  assert(bar() == 4);
}
eof

cat > ./b.c <<eof
#include <stdio.h>
__thread int tls0;
extern __thread int tls1;
int foo() { return ++tls0 + ++tls1; }
static __thread int tls2, tls3;
int bar() { return ++tls2 + ++tls3; }
eof

echo '__thread int tls1;' > ./c.c

sed 's/        /\t/' > ./Makefile <<'eof'
.MAKE.MODE = meta curDirOk=true

CC := gcc -m32 -g -fpic -mtls-dialect=gnu2
LDFLAGS := -m32 -Wl,-rpath=.

all: a0 a1 a2

run: all
        ./a0 && ./a1 && ./a2

c.so: c.o; ${LINK.c} -shared $> -o $@
bc.so: b.o c.o; ${LINK.c} -shared $> -o $@
b.so: b.o c.so; ${LINK.c} -shared $> -o $@

a0: a.o b.o c.o; ${LINK.c} $> -o $@
a1: a.o b.so; ${LINK.c} $> -o $@
a2: a.o bc.so; ${LINK.c} $> -o $@
eof
```
and glibc `elf/tst-gnu2-tls1`.

`/usr/local/bin/ld` points to the freshly built `lld`.

`bmake run && bmake CFLAGS=-O1 run` => ok.

Differential Revision: https://reviews.llvm.org/D112582

Added: 
    lld/test/ELF/i386-tlsdesc-gd.s
    lld/test/ELF/i386-tlsdesc-ld.s
    lld/test/ELF/invalid/i386-tlsdesc-gd.s

Modified: 
    lld/ELF/Arch/X86.cpp
    lld/ELF/InputSection.cpp
    lld/ELF/Relocations.cpp
    lld/ELF/Relocations.h
    lld/ELF/Writer.cpp
    lld/docs/ReleaseNotes.rst

Removed: 
    


################################################################################
diff  --git a/lld/ELF/Arch/X86.cpp b/lld/ELF/Arch/X86.cpp
index 726160c7b5017..5d34b769e80ec 100644
--- a/lld/ELF/Arch/X86.cpp
+++ b/lld/ELF/Arch/X86.cpp
@@ -56,6 +56,7 @@ X86::X86() {
   iRelativeRel = R_386_IRELATIVE;
   relativeRel = R_386_RELATIVE;
   symbolicRel = R_386_32;
+  tlsDescRel = R_386_TLS_DESC;
   tlsGotRel = R_386_TLS_TPOFF;
   tlsModuleIndexRel = R_386_TLS_DTPMOD32;
   tlsOffsetRel = R_386_TLS_DTPOFF32;
@@ -71,7 +72,8 @@ X86::X86() {
 }
 
 int X86::getTlsGdRelaxSkip(RelType type) const {
-  return 2;
+  // TLSDESC relocations are processed separately. See relaxTlsGdToLe below.
+  return type == R_386_TLS_GOTDESC || type == R_386_TLS_DESC_CALL ? 1 : 2;
 }
 
 RelExpr X86::getRelExpr(RelType type, const Symbol &s,
@@ -143,6 +145,10 @@ RelExpr X86::getRelExpr(RelType type, const Symbol &s,
     // the byte, we can determine whether the instruction uses the operand as an
     // absolute address (R_GOT) or a register-relative address (R_GOTPLT).
     return (loc[-1] & 0xc7) == 0x5 ? R_GOT : R_GOTPLT;
+  case R_386_TLS_GOTDESC:
+    return R_TLSDESC_GOTPLT;
+  case R_386_TLS_DESC_CALL:
+    return R_TLSDESC_CALL;
   case R_386_TLS_GOTIE:
     return R_GOTPLT;
   case R_386_GOTOFF:
@@ -167,7 +173,8 @@ RelExpr X86::adjustTlsExpr(RelType type, RelExpr expr) const {
   case R_RELAX_TLS_GD_TO_IE:
     return R_RELAX_TLS_GD_TO_IE_GOTPLT;
   case R_RELAX_TLS_GD_TO_LE:
-    return R_RELAX_TLS_GD_TO_LE_NEG;
+    return type == R_386_TLS_GD ? R_RELAX_TLS_GD_TO_LE_NEG
+                                : R_RELAX_TLS_GD_TO_LE;
   }
 }
 
@@ -259,6 +266,8 @@ int64_t X86::getImplicitAddend(const uint8_t *buf, RelType type) const {
   case R_386_PC32:
   case R_386_PLT32:
   case R_386_RELATIVE:
+  case R_386_TLS_GOTDESC:
+  case R_386_TLS_DESC_CALL:
   case R_386_TLS_DTPMOD32:
   case R_386_TLS_DTPOFF32:
   case R_386_TLS_LDO_32:
@@ -273,6 +282,8 @@ int64_t X86::getImplicitAddend(const uint8_t *buf, RelType type) const {
   case R_386_TLS_TPOFF:
   case R_386_TLS_TPOFF32:
     return SignExtend64<32>(read32le(buf));
+  case R_386_TLS_DESC:
+    return SignExtend64<32>(read32le(buf + 4));
   case R_386_NONE:
   case R_386_JUMP_SLOT:
     // These relocations are defined as not having an implicit addend.
@@ -323,6 +334,8 @@ void X86::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
   case R_386_PC32:
   case R_386_PLT32:
   case R_386_RELATIVE:
+  case R_386_TLS_GOTDESC:
+  case R_386_TLS_DESC_CALL:
   case R_386_TLS_DTPMOD32:
   case R_386_TLS_DTPOFF32:
   case R_386_TLS_GD:
@@ -337,39 +350,79 @@ void X86::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
     checkInt(loc, val, 32, rel);
     write32le(loc, val);
     break;
+  case R_386_TLS_DESC:
+    // The addend is stored in the second 32-bit word.
+    write32le(loc + 4, val);
+    break;
   default:
     llvm_unreachable("unknown relocation");
   }
 }
 
-void X86::relaxTlsGdToLe(uint8_t *loc, const Relocation &, uint64_t val) const {
-  // Convert
-  //   leal x at tlsgd(, %ebx, 1),
-  //   call __tls_get_addr at plt
-  // to
-  //   movl %gs:0,%eax
-  //   subl $x at ntpoff,%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
-  };
-  memcpy(loc - 3, inst, sizeof(inst));
-  write32le(loc + 5, val);
+void X86::relaxTlsGdToLe(uint8_t *loc, const Relocation &rel,
+                         uint64_t val) const {
+  if (rel.type == R_386_TLS_GD) {
+    // Convert
+    //   leal x at tlsgd(, %ebx, 1), %eax
+    //   call __tls_get_addr at plt
+    // 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
+    };
+    memcpy(loc - 3, inst, sizeof(inst));
+    write32le(loc + 5, val);
+  } else if (rel.type == R_386_TLS_GOTDESC) {
+    // Convert leal x at tlsdesc(%ebx), %eax to leal x at ntpoff, %eax.
+    //
+    // Note: call *x at tlsdesc(%eax) may not immediately follow this instruction.
+    if (memcmp(loc - 2, "\x8d\x83", 2)) {
+      error(getErrorLocation(loc - 2) +
+            "R_386_TLS_GOTDESC must be used in leal x at tlsdesc(%ebx), %eax");
+      return;
+    }
+    loc[-1] = 0x05;
+    write32le(loc, val);
+  } else {
+    // Convert call *x at tlsdesc(%eax) to xchg ax, ax.
+    assert(rel.type == R_386_TLS_DESC_CALL);
+    loc[0] = 0x66;
+    loc[1] = 0x90;
+  }
 }
 
-void X86::relaxTlsGdToIe(uint8_t *loc, const Relocation &, uint64_t val) const {
-  // Convert
-  //   leal x at tlsgd(, %ebx, 1),
-  //   call __tls_get_addr at plt
-  // to
-  //   movl %gs:0, %eax
-  //   addl x at gotntpoff(%ebx), %eax
-  const uint8_t inst[] = {
-      0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0, %eax
-      0x03, 0x83, 0, 0, 0, 0,             // addl Val(%ebx), %eax
-  };
-  memcpy(loc - 3, inst, sizeof(inst));
-  write32le(loc + 5, val);
+void X86::relaxTlsGdToIe(uint8_t *loc, const Relocation &rel,
+                         uint64_t val) const {
+  if (rel.type == R_386_TLS_GD) {
+    // Convert
+    //   leal x at tlsgd(, %ebx, 1), %eax
+    //   call __tls_get_addr at plt
+    // to
+    //   movl %gs:0, %eax
+    //   addl x at gotntpoff(%ebx), %eax
+    const uint8_t inst[] = {
+        0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0, %eax
+        0x03, 0x83, 0,    0,    0,    0,    // addl val(%ebx), %eax
+    };
+    memcpy(loc - 3, inst, sizeof(inst));
+    write32le(loc + 5, 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)) {
+      error(getErrorLocation(loc - 2) +
+            "R_386_TLS_GOTDESC must be used in leal x at tlsdesc(%ebx), %eax");
+      return;
+    }
+    loc[-2] = 0x8b;
+    write32le(loc, val);
+  } else {
+    // Convert call *x at tlsdesc(%eax) to xchg ax, ax.
+    assert(rel.type == R_386_TLS_DESC_CALL);
+    loc[0] = 0x66;
+    loc[1] = 0x90;
+  }
 }
 
 // In some conditions, relocations can be optimized to avoid using GOT.

diff  --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index b447918984942..de6333162fd60 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -832,6 +832,8 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type,
     return in.got->getGlobalDynAddr(sym) + a;
   case R_TLSDESC_PC:
     return in.got->getGlobalDynAddr(sym) + a - p;
+  case R_TLSDESC_GOTPLT:
+    return in.got->getGlobalDynAddr(sym) + a - in.gotPlt->getVA();
   case R_AARCH64_TLSDESC_PAGE:
     return getAArch64Page(in.got->getGlobalDynAddr(sym) + a) -
            getAArch64Page(p);

diff  --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index 6c2076f142b82..71d1024d7017f 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -230,8 +230,9 @@ static bool isStaticLinkTimeConstant(RelExpr e, RelType type, const Symbol &sym,
             R_AARCH64_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC, R_GOTPLTONLY_PC,
             R_PLT_PC, R_PLT_GOTPLT, R_TLSGD_GOT, R_TLSGD_GOTPLT, R_TLSGD_PC,
             R_PPC32_PLTREL, R_PPC64_CALL_PLT, R_PPC64_RELAX_TOC, R_RISCV_ADD,
-            R_TLSDESC_CALL, R_TLSDESC_PC, R_AARCH64_TLSDESC_PAGE, R_TLSLD_HINT,
-            R_TLSIE_HINT, R_AARCH64_GOT_PAGE>(e))
+            R_TLSDESC_CALL, R_TLSDESC_PC, R_TLSDESC_GOTPLT,
+            R_AARCH64_TLSDESC_PAGE, R_TLSLD_HINT, R_TLSIE_HINT,
+            R_AARCH64_GOT_PAGE>(e))
     return true;
 
   // These never do, except if the entire file is position dependent or if
@@ -1157,8 +1158,8 @@ handleTlsRelocation(RelType type, Symbol &sym, InputSectionBase &c,
   if (config->emachine == EM_MIPS)
     return handleMipsTlsRelocation(type, sym, c, offset, addend, expr);
 
-  if (oneof<R_AARCH64_TLSDESC_PAGE, R_TLSDESC, R_TLSDESC_CALL, R_TLSDESC_PC>(
-          expr) &&
+  if (oneof<R_AARCH64_TLSDESC_PAGE, R_TLSDESC, R_TLSDESC_CALL, R_TLSDESC_PC,
+            R_TLSDESC_GOTPLT>(expr) &&
       config->shared) {
     if (in.got->addDynTlsEntry(sym)) {
       uint64_t off = in.got->getGlobalDynOffset(sym);
@@ -1235,7 +1236,7 @@ handleTlsRelocation(RelType type, Symbol &sym, InputSectionBase &c,
   }
 
   if (oneof<R_AARCH64_TLSDESC_PAGE, R_TLSDESC, R_TLSDESC_CALL, R_TLSDESC_PC,
-            R_TLSGD_GOT, R_TLSGD_GOTPLT, R_TLSGD_PC>(expr)) {
+            R_TLSDESC_GOTPLT, R_TLSGD_GOT, R_TLSGD_GOTPLT, R_TLSGD_PC>(expr)) {
     if (!toExecRelax) {
       if (in.got->addDynTlsEntry(sym)) {
         uint64_t off = in.got->getGlobalDynOffset(sym);
@@ -1401,7 +1402,7 @@ static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i,
   //
   // The 5 types that relative GOTPLT are all x86 and x86-64 specific.
   if (oneof<R_GOTPLTONLY_PC, R_GOTPLTREL, R_GOTPLT, R_PLT_GOTPLT,
-            R_TLSGD_GOTPLT>(expr)) {
+            R_TLSDESC_GOTPLT, R_TLSGD_GOTPLT>(expr)) {
     in.gotPlt->hasGotPltOffRel = true;
   } else if (oneof<R_GOTONLY_PC, R_GOTREL, R_PPC64_TOCBASE, R_PPC64_RELAX_TOC>(
                  expr)) {

diff  --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h
index d7569ac9ac48d..86e6cf4bc1f5a 100644
--- a/lld/ELF/Relocations.h
+++ b/lld/ELF/Relocations.h
@@ -63,6 +63,7 @@ enum RelExpr {
   R_TLSDESC,
   R_TLSDESC_CALL,
   R_TLSDESC_PC,
+  R_TLSDESC_GOTPLT,
   R_TLSGD_GOT,
   R_TLSGD_GOTPLT,
   R_TLSGD_PC,

diff  --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index 516b5b9cd147a..ff16922d80fd6 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -1960,7 +1960,7 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
                            0x800, STV_DEFAULT);
   }
 
-  if (config->emachine == EM_X86_64) {
+  if (config->emachine == EM_386 || config->emachine == EM_X86_64) {
     // On targets that support TLSDESC, _TLS_MODULE_BASE_ is defined in such a
     // way that:
     //

diff  --git a/lld/docs/ReleaseNotes.rst b/lld/docs/ReleaseNotes.rst
index 91a1417b0db73..f196a9fd42ef9 100644
--- a/lld/docs/ReleaseNotes.rst
+++ b/lld/docs/ReleaseNotes.rst
@@ -32,6 +32,11 @@ ELF Improvements
   Instead, a value of 0 will be written.
   (`D110014 <https://reviews.llvm.org/D110014>`_)
 
+Architecture specific changes:
+
+* The x86-32 port now supports TLSDESC (``-mtls-dialect=gnu2``).
+  (`D112582 <https://reviews.llvm.org/D112582 >`_)
+
 Breaking changes
 ----------------
 

diff  --git a/lld/test/ELF/i386-tlsdesc-gd.s b/lld/test/ELF/i386-tlsdesc-gd.s
new file mode 100644
index 0000000000000..a2fc0f8f66450
--- /dev/null
+++ b/lld/test/ELF/i386-tlsdesc-gd.s
@@ -0,0 +1,113 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=i386 %s -o %t.o
+# RUN: echo '.tbss; .globl c; c: .zero 4' | llvm-mc -filetype=obj -triple=i386 - -o %t1.o
+# RUN: ld.lld -shared -soname=t1.so %t1.o -o %t1.so
+
+# RUN: ld.lld -shared -z now %t.o %t1.o -o %t.so
+# RUN: llvm-readobj -r -x .got %t.so | FileCheck --check-prefix=GD-REL %s
+# RUN: llvm-objdump -h -d --no-show-raw-insn %t.so | FileCheck --check-prefix=GD %s
+
+# RUN: ld.lld -shared -z now %t.o %t1.o -o %t-rela.so -z rela
+# RUN: llvm-readobj -r -x .got %t-rela.so | FileCheck --check-prefix=GD-RELA %s
+
+# RUN: ld.lld -z now %t.o %t1.o -o %t
+# RUN: llvm-readelf -r %t | FileCheck --check-prefix=NOREL %s
+# RUN: llvm-objdump -h -d --no-show-raw-insn %t | FileCheck --check-prefix=LE %s
+
+# RUN: ld.lld -z now %t.o %t1.so -o %t
+# RUN: llvm-readobj -r %t | FileCheck --check-prefix=IE-REL %s
+# RUN: llvm-objdump -h -d --no-show-raw-insn %t | FileCheck --check-prefix=IE %s
+
+# GD-REL:      .rel.dyn {
+# GD-REL-NEXT:   0x2250 R_386_TLS_DESC -
+# GD-REL-NEXT:   0x2248 R_386_TLS_DESC a
+# GD-REL-NEXT:   0x2258 R_386_TLS_DESC c
+# GD-REL-NEXT: }
+# GD-REL:      Hex dump of section '.got':
+# GD-REL-NEXT: 0x00002248 00000000 00000000 00000000 0b000000
+# GD-REL-NEXT: 0x00002258 00000000 00000000
+
+# GD-RELA:      .rela.dyn {
+# GD-RELA-NEXT:   0x225C R_386_TLS_DESC - 0xB
+# GD-RELA-NEXT:   0x2254 R_386_TLS_DESC a 0x0
+# GD-RELA-NEXT:   0x2264 R_386_TLS_DESC c 0x0
+# GD-RELA-NEXT: }
+# GD-RELA:      Hex dump of section '.got':
+# GD-RELA-NEXT: 0x00002254 00000000 00000000 00000000 00000000
+# GD-RELA-NEXT: 0x00002264 00000000 00000000
+
+# GD:      .got     00000018 00002248
+# GD:      .got.plt 0000000c 00002260
+
+# &.rel.dyn[a]-.got.plt = 0x2248-0x2260 = -24
+# GD:      leal -24(%ebx), %eax
+# GD-NEXT: calll *(%eax)
+# GD-NEXT: movl %gs:(%eax), %eax
+
+# &.rel.dyn[b]-.got.plt = 0x2250-0x2260 = -16
+# GD-NEXT: leal -16(%ebx), %eax
+# GD-NEXT: movl %edx, %ebx
+# GD-NEXT: calll *(%eax)
+# GD-NEXT: movl %gs:(%eax), %eax
+
+# &.rel.dyn[c]-.got.plt = 0x2258-0x2260 = -8
+# GD-NEXT: leal -8(%ebx), %eax
+# GD-NEXT: calll *(%eax)
+# GD-NEXT: movl %gs:(%eax), %eax
+
+# NOREL: no relocations
+
+## st_value(a) - tls_size = -8
+# LE:      leal -8, %eax
+# LE-NEXT: nop
+# LE-NEXT: movl %gs:(%eax), %eax
+## st_value(b) - tls_size = -5
+# LE:      leal -5, %eax
+# LE-NEXT: movl %edx, %ebx
+# LE-NEXT: nop
+# LE-NEXT: movl %gs:(%eax), %eax
+## st_value(c) - tls_size = -4
+# LE:      leal -4, %eax
+# LE-NEXT: nop
+# LE-NEXT: movl %gs:(%eax), %eax
+
+# IE-REL:      .rel.dyn {
+# IE-REL-NEXT:   0x40222C R_386_TLS_TPOFF c
+# IE-REL-NEXT: }
+
+# IE:      .got     00000004 0040222c
+# IE:      .got.plt 0000000c 00402230
+
+## a and b are relaxed to use LE.
+# IE:      leal -4, %eax
+# IE-NEXT: nop
+# IE-NEXT: movl %gs:(%eax), %eax
+# IE-NEXT: leal -1, %eax
+# IE-NEXT: movl %edx, %ebx
+# IE-NEXT: nop
+# IE-NEXT: movl %gs:(%eax), %eax
+## &.got[a]-.got.plt = 0x2220 - 0x2224 = -4
+# IE-NEXT: movl -4(%ebx), %eax
+# IE-NEXT: nop
+# IE-NEXT: movl %gs:(%eax), %eax
+
+leal a at tlsdesc(%ebx), %eax
+call *a at tlscall(%eax)
+movl %gs:(%eax), %eax
+
+leal b at tlsdesc(%ebx), %eax
+movl %edx, %ebx  # GCC -O0 may add an extra insn in between.
+call *b at tlscall(%eax)
+movl %gs:(%eax), %eax
+
+leal c at tlsdesc(%ebx), %eax
+call *c at tlscall(%eax)
+movl %gs:(%eax), %eax
+
+.section .tbss
+.globl a
+.zero 8
+a:
+.zero 3
+b:
+.zero 1

diff  --git a/lld/test/ELF/i386-tlsdesc-ld.s b/lld/test/ELF/i386-tlsdesc-ld.s
new file mode 100644
index 0000000000000..b69c5c393ff59
--- /dev/null
+++ b/lld/test/ELF/i386-tlsdesc-ld.s
@@ -0,0 +1,49 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=i386 %s -o %t.o
+
+# RUN: ld.lld -shared -z now %t.o -o %t.so
+# RUN: llvm-readobj -r %t.so | FileCheck --check-prefix=LD-REL %s
+# RUN: llvm-objdump -d --no-show-raw-insn %t.so | FileCheck --check-prefix=LD %s
+
+# RUN: ld.lld -z now %t.o -o %t
+# RUN: llvm-readelf -r %t | FileCheck --check-prefix=NOREL %s
+# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=LE %s
+
+## Check _TLS_MODULE_BASE_ used by LD produces a dynamic relocation with a value of 0.
+# LD-REL:      .rel.dyn {
+# LD-REL-NEXT:   R_386_TLS_DESC -
+# LD-REL-NEXT: }
+
+## 0x2318-0x1267 = 4273
+## dtpoff(a) = 8, dtpoff(b) = 12
+# LD:      leal -8(%ebx), %eax
+# LD-NEXT: calll *(%eax)
+# LD-NEXT: leal 8(%eax), %ecx
+# LD-NEXT: leal 12(%eax), %edx
+
+## When producing an executable, the LD code sequence can be relaxed to LE.
+## It is the same as GD->LE.
+## tpoff(_TLS_MODULE_BASE_) = 0, tpoff(a) = -8, tpoff(b) = -4
+
+# NOREL: no relocations
+
+# LE:      leal 0, %eax
+# LE-NEXT: nop
+# LE-NEXT: leal -8(%eax), %ecx
+# LE-NEXT: leal -4(%eax), %edx
+# LE-NEXT: addl %gs:0, %ecx
+# LE-NEXT: addl %gs:0, %edx
+
+leal _TLS_MODULE_BASE_ at tlsdesc(%ebx), %eax
+call *_TLS_MODULE_BASE_ at tlscall(%eax)
+leal a at dtpoff(%eax), %ecx
+leal b at dtpoff(%eax), %edx
+addl %gs:0, %ecx
+addl %gs:0, %edx
+
+.section .tbss
+.zero 8
+a:
+.zero 4
+b:
+.zero 4

diff  --git a/lld/test/ELF/invalid/i386-tlsdesc-gd.s b/lld/test/ELF/invalid/i386-tlsdesc-gd.s
new file mode 100644
index 0000000000000..804fbf0789314
--- /dev/null
+++ b/lld/test/ELF/invalid/i386-tlsdesc-gd.s
@@ -0,0 +1,14 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=i386 %s -o %t.o
+# RUN: echo '.tbss; .globl a; a:' | llvm-mc -filetype=obj -triple=i386 - -o %t1.o
+# RUN: ld.lld -shared %t1.o -o %t1.so
+
+## GD to LE relaxation.
+# RUN: not ld.lld %t.o %t1.o -o /dev/null 2>&1 | FileCheck -DINPUT=%t.o %s
+## GD to IE relaxation.
+# RUN: not ld.lld %t.o %t1.so -o /dev/null 2>&1 | FileCheck -DINPUT=%t.o %s
+
+# CHECK: error: [[INPUT]]:(.text+0x0): R_386_TLS_GOTDESC must be used in leal x at tlsdesc(%ebx), %eax
+
+leal a at tlsdesc(%ebx), %ecx
+call *a at tlscall(%eax)


        


More information about the llvm-commits mailing list