diff --git a/lld/ELF/Arch/X86.cpp b/lld/ELF/Arch/X86.cpp index eb068f408685a3..8d4f258e2cf24e 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@tlsgd(, %ebx, 1), %eax - // call __tls_get_addr@plt + // call ___tls_get_addr@plt + // or + // leal x@tlsgd(%reg), %eax + // call *___tls_get_addr@got(%reg) // to - // movl %gs:0, %eax - // subl $x@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@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@tlsdesc(%ebx), %eax to leal x@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@tlsgd(, %ebx, 1), %eax - // call __tls_get_addr@plt - // to - // movl %gs:0, %eax - // addl x@gotntpoff(%ebx), %eax + // call ___tls_get_addr@plt + // or + // leal x@tlsgd(%reg), %eax + // call *___tls_get_addr@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@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@tlsdesc(%ebx), %eax to movl x@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@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@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 f349975f892cb6..e698088c9f0b48 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,@object .section .tbss,"awT",@nobits @@ -59,3 +63,9 @@ leal tlsexe1@tlsgd(,%ebx,1),%eax call ___tls_get_addr@plt leal tlsexe2@tlsgd(,%ebx,1),%eax call ___tls_get_addr@plt + +// -fno-plt GD->IE and GD->LE +leal tlsshared1@tlsgd(%edx),%eax +call *___tls_get_addr@GOT(%edx) +leal tlsexe2@tlsgd(%edx),%eax +call *___tls_get_addr@GOT(%edx) diff --git a/lld/test/ELF/i386-tls-opt.s b/lld/test/ELF/i386-tls-opt.s index 4ca640ad9eec94..9cb63f6292dcd6 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@dtpoff(%eax),%edx leal tls1@tlsldm(%ebx),%eax call ___tls_get_addr@plt leal tls1@dtpoff(%eax),%edx +// -fno-plt LD -> LE +leal tls1@tlsldm(%edx),%eax +call *___tls_get_addr@GOT(%edx) +movl tls1@dtpoff(%eax), %edx //IE -> LE: movl %gs:0,%eax movl tls0@gotntpoff(%ebx),%eax