Index: lld/ELF/Arch/SPARCV9.cpp =================================================================== --- lld/ELF/Arch/SPARCV9.cpp +++ lld/ELF/Arch/SPARCV9.cpp @@ -29,6 +29,10 @@ uint64_t pltEntryAddr) const override; void relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const override; + void relaxTlsGdToIe(uint8_t *loc, const Relocation &rel, + uint64_t val) const override; + void relaxTlsGdToLe(uint8_t *loc, const Relocation &rel, + uint64_t val) const override; }; } // namespace @@ -42,9 +46,15 @@ pltEntrySize = 32; pltHeaderSize = 4 * pltEntrySize; + tlsGotRel = R_SPARC_TLS_TPOFF64; + tlsModuleIndexRel = R_SPARC_TLS_DTPMOD64; + tlsOffsetRel = R_SPARC_TLS_DTPOFF64; + defaultCommonPageSize = 8192; defaultMaxPageSize = 0x100000; defaultImageBase = 0x100000; + + gotBaseSymInGotPlt = false; } RelExpr SPARCV9::getRelExpr(RelType type, const Symbol &s, @@ -79,6 +89,11 @@ case R_SPARC_TLS_LE_HIX22: case R_SPARC_TLS_LE_LOX10: return R_TPREL; + case R_SPARC_TLS_GD_HI22: + case R_SPARC_TLS_GD_LO10: + case R_SPARC_TLS_GD_ADD: + case R_SPARC_TLS_GD_CALL: + return R_TLSGD_GOT; default: error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) + ") against symbol " + toString(s)); @@ -100,6 +115,7 @@ checkInt(loc, val, 32, rel); write32be(loc, val); break; + case R_SPARC_TLS_GD_CALL: case R_SPARC_WDISP30: case R_SPARC_WPLT30: // V-disp30 @@ -111,6 +127,7 @@ checkUInt(loc, val, 22, rel); write32be(loc, (read32be(loc) & ~0x003fffff) | (val & 0x003fffff)); break; + case R_SPARC_TLS_GD_HI22: case R_SPARC_GOT22: case R_SPARC_PC22: case R_SPARC_LM22: @@ -132,12 +149,14 @@ // T-simm10 write32be(loc, (read32be(loc) & ~0x000003ff) | (val & 0x000003ff)); break; + case R_SPARC_TLS_GD_LO10: case R_SPARC_LO10: // T-simm13 write32be(loc, (read32be(loc) & ~0x00001fff) | (val & 0x000003ff)); break; case R_SPARC_64: case R_SPARC_UA64: + case R_SPARC_TLS_DTPOFF64: // V-xword64 write64be(loc, val); break; @@ -171,8 +190,55 @@ // T-simm13 write32be(loc, (read32be(loc) & ~0x00001fff) | (val & 0x000003ff) | 0x1C00); break; + case R_SPARC_TLS_GD_ADD: + break; default: - llvm_unreachable("unknown relocation"); + error(getErrorLocation(loc) + "unknown relocation (" + Twine(rel.type) + + ") against symbol " + toString(*rel.sym)); + } +} + +void SPARCV9::relaxTlsGdToIe(uint8_t *loc, const Relocation &rel, + uint64_t val) const { + switch (rel.type) { + case R_SPARC_TLS_GD_ADD: + // add %r1, %r2, %r3 -> ldx [ %r1 + %r2 ], %r3 + write32be(loc, read32be(loc) | 0xc0580000); + break; + case R_SPARC_TLS_GD_CALL: + // call __tls_get_addr -> add %g7, %o0, %o0 + write32(loc, 0x9001c008); + break; + case R_SPARC_TLS_GD_HI22: + relocateNoSym(loc, R_SPARC_HI22, val); + return; + case R_SPARC_TLS_GD_LO10: + relocateNoSym(loc, R_SPARC_LO10, val); + return; + default: + llvm_unreachable("unsupported relocation for TLS GD to IE relaxation"); + } +} + +void SPARCV9::relaxTlsGdToLe(uint8_t *loc, const Relocation &rel, + uint64_t val) const { + switch (rel.type) { + case R_SPARC_TLS_GD_ADD: + // add %r1, %r2, %r3 -> mov %g7, %r2, %r3 + write32be(loc, (read32be(loc) & ~0x0007c000) | 0x0001c000); + break; + case R_SPARC_TLS_GD_CALL: + // call __tls_get_addr -> nop + write32(loc, 0x01000000); + break; + case R_SPARC_TLS_GD_HI22: + relocateNoSym(loc, R_SPARC_TLS_LE_HIX22, val); + return; + case R_SPARC_TLS_GD_LO10: + relocateNoSym(loc, R_SPARC_TLS_LE_LOX10, val); + return; + default: + llvm_unreachable("unsupported relocation for TLS GD to IE relaxation"); } } Index: lld/ELF/Driver.cpp =================================================================== --- lld/ELF/Driver.cpp +++ lld/ELF/Driver.cpp @@ -926,7 +926,7 @@ // Otherwise use the psABI defined relocation entry format. uint16_t m = config->emachine; return m == EM_AARCH64 || m == EM_AMDGPU || m == EM_HEXAGON || m == EM_PPC || - m == EM_PPC64 || m == EM_RISCV || m == EM_X86_64; + m == EM_PPC64 || m == EM_RISCV || m == EM_SPARCV9 || m == EM_X86_64; } static void parseClangOption(StringRef opt, const Twine &msg) { Index: lld/ELF/Relocations.cpp =================================================================== --- lld/ELF/Relocations.cpp +++ lld/ELF/Relocations.cpp @@ -178,6 +178,15 @@ return 0; } +template +static void addPltEntry(PltSection *plt, GotPltSection *gotPlt, + RelocationBaseSection *rel, RelType type, Symbol &sym) { + plt->addEntry(sym); + gotPlt->addEntry(sym); + rel->addReloc( + {type, gotPlt, sym.getGotPltOffset(), !sym.isPreemptible, &sym, 0}); +} + // Notes about General Dynamic and Local Dynamic TLS models below. They may // require the generation of a pair of GOT entries that have associated dynamic // relocations. The pair of GOT entries created are of the form GOT[e0] Module @@ -275,6 +284,22 @@ if (oneof(expr)) { if (!toExecRelax) { + if (config->emachine == EM_SPARCV9 && + (type == R_SPARC_TLS_GD_CALL || type == R_SPARC_TLS_LDM_CALL)) { + // These relocations are applied on call instructions like + // call __tls_get_addr, %rel(sym) + // If this relocation won't be relaxed we have to replace it with a + // PLT-relative one to __tls_get_addr. + Symbol *call_sym = symtab->find("__tls_get_addr"); + assert(call_sym && "__tls_get_addr symbol is not defined"); + + if (!call_sym->isInPlt()) + addPltEntry(in.plt, in.gotPlt, in.relaPlt, target->pltRel, *call_sym); + + c.relocations.push_back({R_PLT_PC, type, offset, 0, call_sym}); + return 1; + } + if (in.got->addDynTlsEntry(sym)) { uint64_t off = in.got->getGlobalDynOffset(sym); @@ -1066,15 +1091,6 @@ expr, type); } -template -static void addPltEntry(PltSection *plt, GotPltSection *gotPlt, - RelocationBaseSection *rel, RelType type, Symbol &sym) { - plt->addEntry(sym); - gotPlt->addEntry(sym); - rel->addReloc( - {type, gotPlt, sym.getGotPltOffset(), !sym.isPreemptible, &sym, 0}); -} - static void addGotEntry(Symbol &sym) { in.got->addEntry(sym); @@ -1374,7 +1390,7 @@ (type == R_HEX_GD_PLT_B22_PCREL || type == R_HEX_GD_PLT_B22_PCREL_X || type == R_HEX_GD_PLT_B32_PCREL_X))) - expr = fromPlt(expr); + expr = fromPlt(expr); } else if (!isAbsoluteValue(sym)) { expr = target->adjustGotPcExpr(type, addend, relocatedAddr); } Index: lld/test/ELF/sparcv9-tls-gd.s =================================================================== --- /dev/null +++ lld/test/ELF/sparcv9-tls-gd.s @@ -0,0 +1,66 @@ +! REQUIRES: sparc +! RUN: echo '.tbss; .globl y; y: .word 0' > %t.s +! RUN: llvm-mc -filetype=obj -triple=sparcv9 %s -o %t.o +! RUN: llvm-mc -filetype=obj -triple=sparcv9 %t.s -o %tx.o +! RUN: ld.lld %tx.o -shared -o %tx.so +! RUN: ld.lld %t.o %tx.o -shared -o %t.so +! RUN: ld.lld %t.o %tx.so -o %t1.o +! RUN: llvm-readobj -r %t.so | FileCheck --check-prefix=RELOC %s +! RUN: llvm-objdump -d --no-show-raw-insn %t.so | FileCheck %s +! RUN: llvm-objdump -d --no-show-raw-insn %t1.o | FileCheck --check-prefix=RELAX %s + +! Call __tls_get_addr + +! CHECK: sethi 0, %o0 +! CHECK-NEXT: add %o0, 0, %o0 +! CHECK-NEXT: add %l7, %o0, %o0 +! CHECK-NEXT: call 1048732 +! CHECK-NEXT: nop +! CHECK-NEXT: sethi 0, %o0 +! CHECK-NEXT: add %o0, 16, %o0 +! CHECK-NEXT: add %l7, %o0, %o0 +! CHECK-NEXT: call 1048712 +! CHECK-NEXT: nop + +! GD -> LE Relaxation + +! RELAX: sethi 4194303, %o0 +! RELAX-NEXT: add %o0, -1024, %o0 +! RELAX-NEXT: add %g7, %o0, %o0 +! RELAX-NEXT: nop +! RELAX-NEXT: nop + +! GD -> IE Relaxation + +! RELAX-NEXT: sethi 1024, %o0 +! RELAX-NEXT: add %o0, 208, %o0 +! RELAX-NEXT: ldx [%l7+%o0], %o0 +! RELAX-NEXT: add %g7, %o0, %o0 +! RELAX-NEXT: nop + +sethi %tgd_hi22(x), %o0 +add %o0, %tgd_lo10(x), %o0 +add %l7, %o0, %o0, %tgd_add(x) +call __tls_get_addr, %tgd_call(x) +nop + +sethi %tgd_hi22(y), %o0 +add %o0, %tgd_lo10(y), %o0 +add %l7, %o0, %o0, %tgd_add(y) +call __tls_get_addr, %tgd_call(y) +nop + +.section .tbss +.zero 128 +.globl x +x: + +! RELOC: .rela.dyn { +! RELOC-NEXT: R_SPARC_TLS_DTPMOD64 x +! RELOC-NEXT: R_SPARC_TLS_DTPOFF64 x +! RELOC-NEXT: R_SPARC_TLS_DTPMOD64 y +! RELOC-NEXT: R_SPARC_TLS_DTPOFF64 y +! RELOC-NEXT: } +! RELOC: .rela.plt { +! RELOC-NEXT: R_SPARC_JMP_SLOT __tls_get_addr +! RELOC-NEXT: }