diff --git a/lld/ELF/Arch/LoongArch.cpp b/lld/ELF/Arch/LoongArch.cpp index 3c4ad53af1b5..fe804cbb0e69 100644 --- a/lld/ELF/Arch/LoongArch.cpp +++ b/lld/ELF/Arch/LoongArch.cpp @@ -39,8 +39,13 @@ public: void relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const override; bool relaxOnce(int pass) const override; + RelExpr adjustTlsExpr(RelType type, RelExpr expr) const override; void relocateAlloc(InputSectionBase &sec, uint8_t *buf) const override; void finalizeRelax(int passes) const override; + +private: + void tlsdescToIe(uint8_t *loc, const Relocation &rel, uint64_t val) const; + void tlsdescToLe(uint8_t *loc, const Relocation &rel, uint64_t val) const; }; } // end anonymous namespace @@ -58,6 +63,7 @@ enum Op { LU12I_W = 0x14000000, PCADDI = 0x18000000, PCADDU12I = 0x1c000000, + PCALAU12I = 0x1a000000, LD_W = 0x28800000, LD_D = 0x28c00000, JIRL = 0x4c000000, @@ -69,6 +75,7 @@ enum Reg { R_ZERO = 0, R_RA = 1, R_TP = 2, + R_A0 = 4, R_T0 = 12, R_T1 = 13, R_T2 = 14, @@ -961,7 +968,8 @@ static bool relax(Ctx &ctx, InputSection &sec) { case R_LARCH_TLS_LD_PC_HI20: case R_LARCH_TLS_DESC_PC_HI20: // The overflow check for i+2 will be carried out in isPairRelaxable. - if (isPairRelaxable(relocs, i)) + if (r.expr != RE_LOONGARCH_RELAX_TLS_GD_TO_IE_PAGE_PC && + r.expr != R_RELAX_TLS_GD_TO_LE && isPairRelaxable(relocs, i)) relaxPCHi20Lo12(ctx, sec, i, loc, r, relocs[i + 2], remove); break; case R_LARCH_CALL36: @@ -1046,6 +1054,104 @@ static void tlsIeToLe(uint8_t *loc, const Relocation &rel, uint64_t val) { } } +// Convert TLSDESC GD/LD to IE. +// In normal or medium code model, there are two forms of code sequences: +// * pcalau12i $a0, %desc_pc_hi20(sym_desc) +// * addi.d $a0, $a0, %desc_pc_lo12(sym_desc) +// * ld.d $ra, $a0, %desc_ld(sym_desc) +// * jirl $ra, $ra, %desc_call(sym_desc) +// ------ +// * pcaddi $a0, %desc_pcrel_20(a) +// * load $ra, $a0, %desc_ld(a) +// * jirl $ra, $ra, %desc_call(a) +// +// The code sequence obtained is as follows: +// * pcalau12i $a0, %ie_pc_hi20(sym_ie) +// * ld.[wd] $a0, $a0, %ie_pc_lo12(sym_ie) +// +// Simplicity, whether tlsdescToIe or tlsdescToLe, we always tend to convert the +// preceding instructions to NOPs, due to both forms of code sequence +// (corresponding to relocation combinations: +// R_LARCH_TLS_DESC_PC_HI20+R_LARCH_TLS_DESC_PC_LO12 and +// R_LARCH_TLS_DESC_PCREL20_S2) have same process. +// +// When relaxation enables, redundant NOPs can be removed. +void LoongArch::tlsdescToIe(uint8_t *loc, const Relocation &rel, + uint64_t val) const { + switch (rel.type) { + case R_LARCH_TLS_DESC_PC_HI20: + case R_LARCH_TLS_DESC_PC_LO12: + case R_LARCH_TLS_DESC_PCREL20_S2: + write32le(loc, insn(ANDI, R_ZERO, R_ZERO, 0)); // nop + break; + case R_LARCH_TLS_DESC_LD: + write32le(loc, insn(PCALAU12I, R_A0, 0, 0)); // pcalau12i $a0, %ie_pc_hi20 + relocateNoSym(loc, R_LARCH_TLS_IE_PC_HI20, val); + break; + case R_LARCH_TLS_DESC_CALL: + write32le(loc, insn(ctx.arg.is64 ? LD_D : LD_W, R_A0, R_A0, + 0)); // ld.[wd] $a0, $a0, %ie_pc_lo12 + relocateNoSym(loc, R_LARCH_TLS_IE_PC_LO12, val); + break; + default: + llvm_unreachable("unsupported relocation for TLSDESC to IE"); + } +} + +// Convert TLSDESC GD/LD to LE. +// The code sequence obtained in the normal or medium code model is as follows: +// * lu12i.w $a0, %le_hi20(sym) # le_hi20 != 0, otherwise NOP +// * ori $a0, src, %le_lo12(sym) # le_hi20 != 0, src = $a0, +// # otherwise, src = $zero +// See the comment in tlsdescToIe for detailed information. +void LoongArch::tlsdescToLe(uint8_t *loc, const Relocation &rel, + uint64_t val) const { + assert(isInt<32>(val) && + "val exceeds the range of medium code model in tlsdescToLe"); + + bool isUInt12 = isUInt<12>(val); + switch (rel.type) { + case R_LARCH_TLS_DESC_PC_HI20: + case R_LARCH_TLS_DESC_PC_LO12: + case R_LARCH_TLS_DESC_PCREL20_S2: + write32le(loc, insn(ANDI, R_ZERO, R_ZERO, 0)); // nop + break; + case R_LARCH_TLS_DESC_LD: + if (isUInt12) + write32le(loc, insn(ANDI, R_ZERO, R_ZERO, 0)); // nop + else + write32le(loc, insn(LU12I_W, R_A0, extractBits(val, 31, 12), + 0)); // lu12i.w $a0, %le_hi20 + break; + case R_LARCH_TLS_DESC_CALL: + if (isUInt12) + write32le(loc, insn(ORI, R_A0, R_ZERO, val)); // ori $a0, $zero, %le_lo12 + else + write32le(loc, + insn(ORI, R_A0, R_A0, lo12(val))); // ori $a0, $a0, %le_lo12 + break; + default: + llvm_unreachable("unsupported relocation for TLSDESC to LE"); + } +} + +// During TLSDESC GD_TO_IE, the converted code sequence always includes an +// instruction related to the Lo12 relocation (ld.[wd]). To obtain correct val +// in `getRelocTargetVA`, expr of this instruction should be adjusted to +// R_RELAX_TLS_GD_TO_IE_ABS, while expr of other instructions related to the +// Hi20 relocation (pcalau12i) should be adjusted to +// RE_LOONGARCH_RELAX_TLS_GD_TO_IE_PAGE_PC. Specifically, in the normal or +// medium code model, the instruction with relocation R_LARCH_TLS_DESC_CALL is +// the candidate of Lo12 relocation. +RelExpr LoongArch::adjustTlsExpr(RelType type, RelExpr expr) const { + if (expr == R_RELAX_TLS_GD_TO_IE) { + if (type != R_LARCH_TLS_DESC_CALL) + return RE_LOONGARCH_RELAX_TLS_GD_TO_IE_PAGE_PC; + return R_RELAX_TLS_GD_TO_IE_ABS; + } + return expr; +} + void LoongArch::relocateAlloc(InputSectionBase &sec, uint8_t *buf) const { const unsigned bits = ctx.arg.is64 ? 64 : 32; uint64_t secAddr = sec.getOutputSection()->addr; @@ -1074,7 +1180,7 @@ void LoongArch::relocateAlloc(InputSectionBase &sec, uint8_t *buf) const { // * i+2 -- R_LARCH_TLS_IE64_PC_LO20 // * i+3 -- R_LARCH_TLS_IE64_PC_HI12 isExtreme = - (i + 2 < size && relocs[i + 2].type == R_LARCH_TLS_IE64_PC_LO20); + i + 2 < size && relocs[i + 2].type == R_LARCH_TLS_IE64_PC_LO20; } if (isExtreme) { rel.expr = getRelExpr(rel.type, *rel.sym, loc); @@ -1088,6 +1194,47 @@ void LoongArch::relocateAlloc(InputSectionBase &sec, uint8_t *buf) const { tlsIeToLe(loc, rel, val); } continue; + case RE_LOONGARCH_RELAX_TLS_GD_TO_IE_PAGE_PC: + if (rel.type == R_LARCH_TLS_DESC_PC_HI20) { + // LoongArch does not support TLSDESC GD/LD to LE/IE optimization in the + // extreme code model. In these cases, the relocs are as follows: + // + // * i -- R_LARCH_TLS_DESC_PC_HI20 + // * i+1 -- R_LARCH_TLS_DESC_PC_LO12 + // * i+2 -- R_LARCH_TLS_DESC64_PC_LO20 + // * i+3 -- R_LARCH_TLS_DESC64_PC_HI12 + isExtreme = + i + 2 < size && relocs[i + 2].type == R_LARCH_TLS_DESC64_PC_LO20; + } + [[fallthrough]]; + case R_RELAX_TLS_GD_TO_IE_ABS: + if (isExtreme) { + if (rel.type == R_LARCH_TLS_DESC_CALL) + continue; + rel.expr = getRelExpr(rel.type, *rel.sym, loc); + val = SignExtend64(sec.getRelocTargetVA(ctx, rel, secAddr + rel.offset), + bits); + relocateNoSym(loc, rel.type, val); + } else { + tlsdescToIe(loc, rel, val); + } + continue; + case R_RELAX_TLS_GD_TO_LE: + if (rel.type == R_LARCH_TLS_DESC_PC_HI20) { + isExtreme = + i + 2 < size && relocs[i + 2].type == R_LARCH_TLS_DESC64_PC_LO20; + } + if (isExtreme) { + if (rel.type == R_LARCH_TLS_DESC_CALL) + continue; + rel.expr = getRelExpr(rel.type, *rel.sym, loc); + val = SignExtend64(sec.getRelocTargetVA(ctx, rel, secAddr + rel.offset), + bits); + relocateNoSym(loc, rel.type, val); + } else { + tlsdescToLe(loc, rel, val); + } + continue; default: break; } diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index f8786265029e..68e3feb1bd04 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -830,6 +830,7 @@ uint64_t InputSectionBase::getRelocTargetVA(Ctx &ctx, const Relocation &r, case R_GOTPLT_PC: return r.sym->getGotPltVA(ctx) + a - p; case RE_LOONGARCH_GOT_PAGE_PC: + case RE_LOONGARCH_RELAX_TLS_GD_TO_IE_PAGE_PC: if (r.sym->hasFlag(NEEDS_TLSGD)) return getLoongArchPageDelta(ctx.in.got->getGlobalDynAddr(*r.sym) + a, p, r.type); diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp index 43f19186f098..cebd564036b2 100644 --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -1340,22 +1340,10 @@ unsigned RelocationScanner::handleTlsRelocation(RelExpr expr, RelType type, if (ctx.arg.emachine == EM_MIPS) return handleMipsTlsRelocation(ctx, type, sym, *sec, offset, addend, expr); - // LoongArch does not yet implement transition from TLSDESC to LE/IE, so - // generate TLSDESC dynamic relocation for the dynamic linker to handle. - if (ctx.arg.emachine == EM_LOONGARCH && - oneof(expr)) { - if (expr != R_TLSDESC_CALL) { - sym.setFlags(NEEDS_TLSDESC); - sec->addReloc({expr, type, offset, addend, &sym}); - } - return 1; - } - bool isRISCV = ctx.arg.emachine == EM_RISCV; if (oneof(expr) && + R_TLSDESC_GOTPLT, RE_LOONGARCH_TLSDESC_PAGE_PC>(expr) && ctx.arg.shared) { // R_RISCV_TLSDESC_{LOAD_LO12,ADD_LO12_I,CALL} reference a label. Do not // set NEEDS_TLSDESC on the label. @@ -1369,10 +1357,14 @@ unsigned RelocationScanner::handleTlsRelocation(RelExpr expr, RelType type, return 1; } - // LoongArch supports IE to LE optimization in non-extreme code model. + // LoongArch supports IE to LE, DESC GD/LD to IE/LE optimizations in + // non-extreme code model. bool execOptimizeInLoongArch = ctx.arg.emachine == EM_LOONGARCH && - (type == R_LARCH_TLS_IE_PC_HI20 || type == R_LARCH_TLS_IE_PC_LO12); + (type == R_LARCH_TLS_IE_PC_HI20 || type == R_LARCH_TLS_IE_PC_LO12 || + type == R_LARCH_TLS_DESC_PC_HI20 || type == R_LARCH_TLS_DESC_PC_LO12 || + type == R_LARCH_TLS_DESC_LD || type == R_LARCH_TLS_DESC_CALL || + type == R_LARCH_TLS_DESC_PCREL20_S2); // ARM, Hexagon, LoongArch and RISC-V do not support GD/LD to IE/LE // optimizations. @@ -1431,9 +1423,23 @@ unsigned RelocationScanner::handleTlsRelocation(RelExpr expr, RelType type, return 1; } + // LoongArch does not support transition from TLSDESC to LE/IE in the extreme + // code model, in which NEEDS_TLSDESC should set, rather than NEEDS_TLSGD. So + // we check independently. + if (ctx.arg.emachine == EM_LOONGARCH && + oneof(expr) && + !execOptimize) { + if (expr != R_TLSDESC_CALL) { + sym.setFlags(NEEDS_TLSDESC); + sec->addReloc({expr, type, offset, addend, &sym}); + } + return 1; + } + if (oneof(expr)) { + RE_LOONGARCH_TLSGD_PAGE_PC, RE_LOONGARCH_TLSDESC_PAGE_PC>(expr)) { if (!execOptimize) { sym.setFlags(NEEDS_TLSGD); sec->addReloc({expr, type, offset, addend, &sym}); diff --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h index d2a77bc95310..02ddf707fd95 100644 --- a/lld/ELF/Relocations.h +++ b/lld/ELF/Relocations.h @@ -131,6 +131,7 @@ enum RelExpr { RE_LOONGARCH_GOT_PAGE_PC, RE_LOONGARCH_TLSGD_PAGE_PC, RE_LOONGARCH_TLSDESC_PAGE_PC, + RE_LOONGARCH_RELAX_TLS_GD_TO_IE_PAGE_PC, }; // Architecture-neutral representation of relocation. diff --git a/lld/test/ELF/loongarch-relax-tlsdesc.s b/lld/test/ELF/loongarch-relax-tlsdesc.s index 9ce7c5881ca9..5f4368343471 100644 --- a/lld/test/ELF/loongarch-relax-tlsdesc.s +++ b/lld/test/ELF/loongarch-relax-tlsdesc.s @@ -9,19 +9,18 @@ # RUN: llvm-readobj -r -x .got a.64.so | FileCheck --check-prefix=GD64-RELA %s # RUN: llvm-objdump --no-show-raw-insn -dr -h a.64.so | FileCheck %s --check-prefix=GD64 -## FIXME: The transition from TLSDESC to IE/LE has not yet been implemented. -## Keep the dynamic relocations and hand them over to dynamic linker. - -# RUN: ld.lld --relax -e 0 -z now a.64.o c.64.o -o a.64.le -# RUN: llvm-readobj -r -x .got a.64.le | FileCheck --check-prefix=LE64-RELA %s -# RUN: llvm-objdump --no-show-raw-insn -d -h a.64.le | FileCheck %s --check-prefix=LE64 +## FIXME: IE/LE relaxation have not yet been implemented, --relax/--no-relax obtain the same results. +## Transition from TLSDESC to IE/LE. Also check --emit-relocs. +# RUN: ld.lld -e 0 -z now --emit-relocs a.64.o c.64.o -o a.64.le +# RUN: llvm-readobj -r -x .got a.64.le 2>&1 | FileCheck --check-prefix=LE64-RELA %s +# RUN: llvm-objdump --no-show-raw-insn -dr -h a.64.le | FileCheck %s --check-prefix=LE64 # RUN: ld.lld --no-relax -e 0 -z now a.64.o c.64.o -o a.64.le.norelax # RUN: llvm-objdump --no-show-raw-insn -d -h a.64.le.norelax | FileCheck %s --check-prefix=LE64-NORELAX -# RUN: ld.lld --relax -e 0 -z now a.64.o c.64.so -o a.64.ie +# RUN: ld.lld --relax -e 0 -z now --emit-relocs a.64.o c.64.so -o a.64.ie # RUN: llvm-readobj -r -x .got a.64.ie | FileCheck --check-prefix=IE64-RELA %s -# RUN: llvm-objdump --no-show-raw-insn -d -h a.64.ie | FileCheck %s --check-prefix=IE64 +# RUN: llvm-objdump --no-show-raw-insn -dr -h a.64.ie | FileCheck %s --check-prefix=IE64 # RUN: ld.lld --no-relax -e 0 -z now a.64.o c.64.so -o a.64.ie.norelax # RUN: llvm-objdump --no-show-raw-insn -d -h a.64.ie.norelax | FileCheck %s --check-prefix=IE64-NORELAX @@ -71,172 +70,199 @@ # GD64-NEXT: jirl $ra, $ra, 0 # GD64-NEXT: add.d $a4, $a0, $tp -# LE64-RELA: .rela.dyn { -# LE64-RELA-NEXT: 0x30280 R_LARCH_TLS_DESC64 - 0x8 -# LE64-RELA-NEXT: 0x30290 R_LARCH_TLS_DESC64 - 0x800 -# LE64-RELA-NEXT: 0x302A0 R_LARCH_TLS_DESC64 - 0x1000 -# LE64-RELA-NEXT: 0x302B0 R_LARCH_TLS_DESC64 - 0x7FF -# LE64-RELA-NEXT: } -# LE64-RELA: Hex dump of section '.got': -# LE64-RELA-NEXT: 0x00030280 00000000 00000000 00000000 00000000 . -# LE64-RELA-NEXT: 0x00030290 00000000 00000000 00000000 00000000 . -# LE64-RELA-NEXT: 0x000302a0 00000000 00000000 00000000 00000000 . -# LE64-RELA-NEXT: 0x000302b0 00000000 00000000 00000000 00000000 . +# LE64-RELA: could not find section '.got' -# LE64: .got 00000040 0000000000030280 - -## &.got[a]-. = 0x30280 - 0x20228 = 16406<<2 -# LE64: 20228: pcaddi $a0, 16406 -# LE64-NEXT: ld.d $ra, $a0, 0 -# LE64-NEXT: jirl $ra, $ra, 0 +## a@tprel = 0x8 +# LE64: 20158: nop +# LE64-NEXT: R_LARCH_TLS_DESC_PC_HI20 a +# LE64-NEXT: R_LARCH_RELAX *ABS* +# LE64-NEXT: nop +# LE64-NEXT: R_LARCH_TLS_DESC_PC_LO12 a +# LE64-NEXT: R_LARCH_RELAX *ABS* +# LE64-NEXT: nop +# LE64-NEXT: R_LARCH_TLS_DESC_LD a +# LE64-NEXT: R_LARCH_RELAX *ABS* +# LE64-NEXT: ori $a0, $zero, 8 +# LE64-NEXT: R_LARCH_TLS_DESC_CALL a +# LE64-NEXT: R_LARCH_RELAX *ABS* # LE64-NEXT: add.d $a1, $a0, $tp -## &.got[b]-. = 0x30280+48 - 0x20238: 0x10 pages, page offset 0x2b0 -## R_LARCH_RELAX does not appear in pairs. No relaxation. -# LE64: 20238: pcalau12i $a0, 16 -# LE64-NEXT: addi.d $a0, $a0, 688 -# LE64-NEXT: ld.d $ra, $a0, 0 -# LE64-NEXT: jirl $ra, $ra, 0 +## b@tprel = 0x7ff +# LE64: 2016c: nop +# LE64-NEXT: R_LARCH_TLS_DESC_PC_HI20 b +# LE64-NEXT: R_LARCH_RELAX *ABS* +# LE64-NEXT: nop +# LE64-NEXT: R_LARCH_TLS_DESC_PC_LO12 b +# LE64-NEXT: nop +# LE64-NEXT: R_LARCH_TLS_DESC_LD b +# LE64-NEXT: ori $a0, $zero, 2047 +# LE64-NEXT: R_LARCH_TLS_DESC_CALL b # LE64-NEXT: add.d $a2, $a0, $tp -## &.got[c]-. = 0x30280+16 - 0x2024c: 0x10 pages, page offset 0x290 +## c@tprel = 0x800 ## Without R_LARCH_RELAX relocation. No relaxation. -# LE64: 2024c: pcalau12i $a0, 16 +# LE64: 20180: nop +# LE64-NEXT: R_LARCH_TLS_DESC_PC_HI20 c # LE64-NEXT: addi.d $t0, $zero, 0 -# LE64-NEXT: addi.d $a0, $a0, 656 +# LE64-NEXT: nop +# LE64-NEXT: R_LARCH_TLS_DESC_PC_LO12 c # LE64-NEXT: addi.d $t0, $t0, 1 -# LE64-NEXT: ld.d $ra, $a0, 0 +# LE64-NEXT: nop +# LE64-NEXT: R_LARCH_TLS_DESC_LD c # LE64-NEXT: addi.d $t0, $t0, 1 -# LE64-NEXT: jirl $ra, $ra, 0 +# LE64-NEXT: ori $a0, $zero, 2048 +# LE64-NEXT: R_LARCH_TLS_DESC_CALL c # LE64-NEXT: add.d $a3, $a0, $tp -## &.got[d]-. = 0x30280+32 - 0x2026c = 16397<<2 -# LE64: 2026c: pcaddi $a0, 16397 -# LE64-NEXT: ld.d $ra, $a0, 0 -# LE64-NEXT: jirl $ra, $ra, 0 +## d@tprel = 0x1000 +# LE64: 201a0: nop +# LE64-NEXT: R_LARCH_TLS_DESC_PC_HI20 d +# LE64-NEXT: R_LARCH_RELAX *ABS* +# LE64-NEXT: nop +# LE64-NEXT: R_LARCH_TLS_DESC_PC_LO12 d +# LE64-NEXT: R_LARCH_RELAX *ABS* +# LE64-NEXT: lu12i.w $a0, 1 +# LE64-NEXT: R_LARCH_TLS_DESC_LD d +# LE64-NEXT: ori $a0, $a0, 0 +# LE64-NEXT: R_LARCH_TLS_DESC_CALL d # LE64-NEXT: add.d $a4, $a0, $tp -# LE64-NORELAX: .got 00000040 0000000000030288 - -## &.got[a]-. = 0x30288 - 0x20228 = 0x10 pages, page offset 0x288 -# LE64-NORELAX: 20228: pcalau12i $a0, 16 -# LE64-NORELAX-NEXT: addi.d $a0, $a0, 648 -# LE64-NORELAX-NEXT: ld.d $ra, $a0, 0 -# LE64-NORELAX-NEXT: jirl $ra, $ra, 0 +## a@tprel = 0x8 +# LE64-NORELAX: 20158: nop +# LE64-NORELAX-NEXT: nop +# LE64-NORELAX-NEXT: nop +# LE64-NORELAX-NEXT: ori $a0, $zero, 8 # LE64-NORELAX-NEXT: add.d $a1, $a0, $tp -## &.got[b]-. = 0x30288+48 - 0x2023c: 0x10 pages, page offset 0x2b8 -## R_LARCH_RELAX does not appear in pairs. No relaxation. -# LE64-NORELAX: 2023c: pcalau12i $a0, 16 -# LE64-NORELAX-NEXT: addi.d $a0, $a0, 696 -# LE64-NORELAX-NEXT: ld.d $ra, $a0, 0 -# LE64-NORELAX-NEXT: jirl $ra, $ra, 0 +## b@tprel = 0x7ff +# LE64-NORELAX: 2016c: nop +# LE64-NORELAX-NEXT: nop +# LE64-NORELAX-NEXT: nop +# LE64-NORELAX-NEXT: ori $a0, $zero, 2047 # LE64-NORELAX-NEXT: add.d $a2, $a0, $tp -## &.got[c]-. = 0x30288+16 - 0x20250: 0x10 pages, page offset 0x298 +## c@tprel = 0x800 ## Without R_LARCH_RELAX relocation. No relaxation. -# LE64-NORELAX: 20250: pcalau12i $a0, 16 +# LE64-NORELAX: 20180: nop # LE64-NORELAX-NEXT: addi.d $t0, $zero, 0 -# LE64-NORELAX-NEXT: addi.d $a0, $a0, 664 +# LE64-NORELAX-NEXT: nop # LE64-NORELAX-NEXT: addi.d $t0, $t0, 1 -# LE64-NORELAX-NEXT: ld.d $ra, $a0, 0 +# LE64-NORELAX-NEXT: nop # LE64-NORELAX-NEXT: addi.d $t0, $t0, 1 -# LE64-NORELAX-NEXT: jirl $ra, $ra, 0 +# LE64-NORELAX-NEXT: ori $a0, $zero, 2048 # LE64-NORELAX-NEXT: add.d $a3, $a0, $tp -## &.got[d]-. = 0x30288+32 - 0x20270: 0x10 pages, page offset 0x2a8 -# LE64-NORELAX: 20270: pcalau12i $a0, 16 -# LE64-NORELAX-NEXT: addi.d $a0, $a0, 680 -# LE64-NORELAX-NEXT: ld.d $ra, $a0, 0 -# LE64-NORELAX-NEXT: jirl $ra, $ra, 0 +## d@tprel = 0x1000 +# LE64-NORELAX: 201a0: nop +# LE64-NORELAX-NEXT: nop +# LE64-NORELAX-NEXT: lu12i.w $a0, 1 +# LE64-NORELAX-NEXT: ori $a0, $a0, 0 # LE64-NORELAX-NEXT: add.d $a4, $a0, $tp # IE64-RELA: .rela.dyn { -# IE64-RELA-NEXT: 0x30430 R_LARCH_TLS_DESC64 - 0x8 -# IE64-RELA-NEXT: 0x30460 R_LARCH_TLS_DESC64 - 0x7FF -# IE64-RELA-NEXT: 0x30440 R_LARCH_TLS_DESC64 c 0x0 -# IE64-RELA-NEXT: 0x30450 R_LARCH_TLS_DESC64 d 0x0 +# IE64-RELA-NEXT: 0x30408 R_LARCH_TLS_TPREL64 c 0x0 +# IE64-RELA-NEXT: 0x30410 R_LARCH_TLS_TPREL64 d 0x0 # IE64-RELA-NEXT: } # IE64-RELA: Hex dump of section '.got': -# IE64-RELA-NEXT: 0x00030430 00000000 00000000 00000000 00000000 . -# IE64-RELA-NEXT: 0x00030440 00000000 00000000 00000000 00000000 . -# IE64-RELA-NEXT: 0x00030450 00000000 00000000 00000000 00000000 . -# IE64-RELA-NEXT: 0x00030460 00000000 00000000 00000000 00000000 . +# IE64-RELA-NEXT: 0x00030408 00000000 00000000 00000000 00000000 . -# IE64: .got 00000040 0000000000030430 +# IE64: .got 00000010 0000000000030408 ## a and b are optimized to use LE. c and d are optimized to IE. -## &.got[a]-. = 0x30430 - 0x202f8 = 16462<<2 -# IE64: 202f8: pcaddi $a0, 16462 -# IE64-NEXT: ld.d $ra, $a0, 0 -# IE64-NEXT: jirl $ra, $ra, 0 +## a@tprel = 0x8 +# IE64: 202c8: nop +# IE64-NEXT: R_LARCH_TLS_DESC_PC_HI20 a +# IE64-NEXT: R_LARCH_RELAX *ABS* +# IE64-NEXT: nop +# IE64-NEXT: R_LARCH_TLS_DESC_PC_LO12 a +# IE64-NEXT: R_LARCH_RELAX *ABS* +# IE64-NEXT: nop +# IE64-NEXT: R_LARCH_TLS_DESC_LD a +# IE64-NEXT: R_LARCH_RELAX *ABS* +# IE64-NEXT: ori $a0, $zero, 8 +# IE64-NEXT: R_LARCH_TLS_DESC_CALL a +# IE64-NEXT: R_LARCH_RELAX *ABS* # IE64-NEXT: add.d $a1, $a0, $tp -## &.got[b]-. = 0x30430+48 - 0x20308: 0x10 pages, page offset 0x460 -## R_LARCH_RELAX does not appear in pairs. No relaxation. -# IE64: 20308: pcalau12i $a0, 16 -# IE64-NEXT: addi.d $a0, $a0, 1120 -# IE64-NEXT: ld.d $ra, $a0, 0 -# IE64-NEXT: jirl $ra, $ra, 0 +## b@tprel = 0x7ff +# IE64: 202dc: nop +# IE64-NEXT: R_LARCH_TLS_DESC_PC_HI20 b +# IE64-NEXT: R_LARCH_RELAX *ABS* +# IE64-NEXT: nop +# IE64-NEXT: R_LARCH_TLS_DESC_PC_LO12 b +# IE64-NEXT: nop +# IE64-NEXT: R_LARCH_TLS_DESC_LD b +# IE64-NEXT: ori $a0, $zero, 2047 +# IE64-NEXT: R_LARCH_TLS_DESC_CALL b # IE64-NEXT: add.d $a2, $a0, $tp -## &.got[c]-. = 0x30430+16 - 0x2031c: 0x10 pages, page offset 0x440 +## &.got[c]-. = 0x30408 - 0x20300: 0x10 pages, page offset 0x408 ## Without R_LARCH_RELAX relocation. No relaxation. -# IE64: 2031c: pcalau12i $a0, 16 +# IE64: 202f0: nop +# IE64-NEXT: R_LARCH_TLS_DESC_PC_HI20 c # IE64-NEXT: addi.d $t0, $zero, 0 -# IE64-NEXT: addi.d $a0, $a0, 1088 +# IE64-NEXT: nop +# IE64-NEXT: R_LARCH_TLS_DESC_PC_LO12 c # IE64-NEXT: addi.d $t0, $t0, 1 -# IE64-NEXT: ld.d $ra, $a0, 0 +# IE64-NEXT: pcalau12i $a0, 16 +# IE64-NEXT: R_LARCH_TLS_DESC_LD c # IE64-NEXT: addi.d $t0, $t0, 1 -# IE64-NEXT: jirl $ra, $ra, 0 +# IE64-NEXT: ld.d $a0, $a0, 1032 +# IE64-NEXT: R_LARCH_TLS_DESC_CALL c # IE64-NEXT: add.d $a3, $a0, $tp -## &.got[d]-. = 0x30430+32 - 0x2033c = 16453<<2 -# IE64: 2033c: pcaddi $a0, 16453 -# IE64-NEXT: ld.d $ra, $a0, 0 -# IE64-NEXT: jirl $ra, $ra, 0 +## &.got[d]-. = 0x30408+8 - 0x20318: 0x10 pages, page offset 0x410 +# IE64: 20310: nop +# IE64-NEXT: R_LARCH_TLS_DESC_PC_HI20 d +# IE64-NEXT: R_LARCH_RELAX *ABS* +# IE64-NEXT: nop +# IE64-NEXT: R_LARCH_TLS_DESC_PC_LO12 d +# IE64-NEXT: R_LARCH_RELAX *ABS* +# IE64-NEXT: pcalau12i $a0, 16 +# IE64-NEXT: R_LARCH_TLS_DESC_LD d +# IE64-NEXT: ld.d $a0, $a0, 1040 +# IE64-NEXT: R_LARCH_TLS_DESC_CALL d # IE64-NEXT: add.d $a4, $a0, $tp -# IE64-NORELAX: .got 00000040 0000000000030438 +# IE64-NORELAX: .got 00000010 0000000000030408 -## &.got[a]-. = 0x30438 - 0x202f8 = 0x10 pages, page offset 0x438 -# IE64-NORELAX: 202f8: pcalau12i $a0, 16 -# IE64-NORELAX-NEXT: addi.d $a0, $a0, 1080 -# IE64-NORELAX-NEXT: ld.d $ra, $a0, 0 -# IE64-NORELAX-NEXT: jirl $ra, $ra, 0 +## a@tprel = 0x8 +# IE64-NORELAX: 202c8: nop +# IE64-NORELAX-NEXT: nop +# IE64-NORELAX-NEXT: nop +# IE64-NORELAX-NEXT: ori $a0, $zero, 8 # IE64-NORELAX-NEXT: add.d $a1, $a0, $tp -## &.got[b]-. = 0x30438+48 - 0x2030c: 0x10 pages, page offset 0x468 -## R_LARCH_RELAX does not appear in pairs. No relaxation. -# IE64-NORELAX: 2030c: pcalau12i $a0, 16 -# IE64-NORELAX-NEXT: addi.d $a0, $a0, 1128 -# IE64-NORELAX-NEXT: ld.d $ra, $a0, 0 -# IE64-NORELAX-NEXT: jirl $ra, $ra, 0 +## b@tprel = 0x7ff +# IE64-NORELAX: 202dc: nop +# IE64-NORELAX-NEXT: nop +# IE64-NORELAX-NEXT: nop +# IE64-NORELAX-NEXT: ori $a0, $zero, 2047 # IE64-NORELAX-NEXT: add.d $a2, $a0, $tp -## &.got[c]-. = 0x30438+16 - 0x20320: 0x10 pages, page offset 0x448 +## &.got[c]-. = 0x30408 - 0x20300: 0x10 pages, page offset 0x408 ## Without R_LARCH_RELAX relocation. No relaxation. -# IE64-NORELAX: 20320: pcalau12i $a0, 16 +# IE64-NORELAX: 202f0: nop # IE64-NORELAX-NEXT: addi.d $t0, $zero, 0 -# IE64-NORELAX-NEXT: addi.d $a0, $a0, 1096 +# IE64-NORELAX-NEXT: nop # IE64-NORELAX-NEXT: addi.d $t0, $t0, 1 -# IE64-NORELAX-NEXT: ld.d $ra, $a0, 0 +# IE64-NORELAX-NEXT: pcalau12i $a0, 16 # IE64-NORELAX-NEXT: addi.d $t0, $t0, 1 -# IE64-NORELAX-NEXT: jirl $ra, $ra, 0 +# IE64-NORELAX-NEXT: ld.d $a0, $a0, 1032 # IE64-NORELAX-NEXT: add.d $a3, $a0, $tp -## &.got[d]-. = 0x30438+32 - 0x20340: 0x10 pages, page offset 0x458 -# IE64-NORELAX: 20340: pcalau12i $a0, 16 -# IE64-NORELAX-NEXT: addi.d $a0, $a0, 1112 -# IE64-NORELAX-NEXT: ld.d $ra, $a0, 0 -# IE64-NORELAX-NEXT: jirl $ra, $ra, 0 +## &.got[d]-. = 0x30408+8 - 0x20318: 0x10 pages, page offset 0x410 +# IE64-NORELAX: 20310: nop +# IE64-NORELAX-NEXT: nop +# IE64-NORELAX-NEXT: pcalau12i $a0, 16 +# IE64-NORELAX-NEXT: ld.d $a0, $a0, 1040 # IE64-NORELAX-NEXT: add.d $a4, $a0, $tp #--- a.s la.tls.desc $a0, a add.d $a1, $a0, $tp -# ADDI.D does not have R_LARCH_RELAX. No relaxation. +# ADDI.D does not have R_LARCH_RELAX. No relaxation when it is not optimized to IE/LE (--shared). pcalau12i $a0, %desc_pc_hi20(b) .reloc .-4, R_LARCH_RELAX, 0 addi.d $a0, $a0, %desc_pc_lo12(b) diff --git a/lld/test/ELF/loongarch-tlsdesc-pcrel20-s2.s b/lld/test/ELF/loongarch-tlsdesc-pcrel20-s2.s index 99e21d993519..422592980d28 100644 --- a/lld/test/ELF/loongarch-tlsdesc-pcrel20-s2.s +++ b/lld/test/ELF/loongarch-tlsdesc-pcrel20-s2.s @@ -14,14 +14,14 @@ # RUN: ld.lld -shared -z now a.64.o c.64.o -o rel.64.so -z rel # RUN: llvm-readobj -r -x .got rel.64.so | FileCheck --check-prefix=GD64-REL %s -## FIXME: The transition frome TLSDESC to IE/LE has not yet been implemented. -## Keep the dynamic relocations and hand them over to dynamic linker. - +## Transition from TLSDESC to IE/LE. # RUN: ld.lld -e 0 -z now a.64.o c.64.o -o a.64.le -# RUN: llvm-readobj -r -x .got a.64.le | FileCheck --check-prefix=LE64-RELA %s +# RUN: llvm-readobj -r -x .got a.64.le 2>&1 | FileCheck --check-prefix=LE64-RELA %s +# RUN: llvm-objdump --no-show-raw-insn -d a.64.le | FileCheck --check-prefix=LE64 %s # RUN: ld.lld -e 0 -z now a.64.o c.64.so -o a.64.ie # RUN: llvm-readobj -r -x .got a.64.ie | FileCheck --check-prefix=IE64-RELA %s +# RUN: llvm-objdump --no-show-raw-insn -d a.64.ie | FileCheck --check-prefix=IE64 %s ## 32-bit code is mostly the same. We only test a few variants. @@ -68,25 +68,46 @@ # GD64-NEXT: jirl $ra, $ra, 0 # GD64-NEXT: add.d $a3, $a0, $tp -# LE64-RELA: .rela.dyn { -# LE64-RELA-NEXT: 0x30240 R_LARCH_TLS_DESC64 - 0x8 -# LE64-RELA-NEXT: 0x30250 R_LARCH_TLS_DESC64 - 0x800 -# LE64-RELA-NEXT: 0x30260 R_LARCH_TLS_DESC64 - 0x7FF -# LE64-RELA-NEXT: } -# LE64-RELA: Hex dump of section '.got': -# LE64-RELA-NEXT: 0x00030240 00000000 00000000 00000000 00000000 . -# LE64-RELA-NEXT: 0x00030250 00000000 00000000 00000000 00000000 . -# LE64-RELA-NEXT: 0x00030260 00000000 00000000 00000000 00000000 . +# LE64-RELA: could not find section '.got' + +# LE64-LABEL: <.text>: +## st_value(a) = 8 +# LE64-NEXT: nop +# LE64-NEXT: nop +# LE64-NEXT: ori $a0, $zero, 8 +# LE64-NEXT: add.d $a1, $a0, $tp +## st_value(b) = 2047 +# LE64-NEXT: nop +# LE64-NEXT: nop +# LE64-NEXT: ori $a0, $zero, 2047 +# LE64-NEXT: add.d $a2, $a0, $tp +## st_value(c) = 2048 +# LE64-NEXT: nop +# LE64-NEXT: nop +# LE64-NEXT: ori $a0, $zero, 2048 +# LE64-NEXT: add.d $a3, $a0, $tp # IE64-RELA: .rela.dyn { -# IE64-RELA-NEXT: 0x303C8 R_LARCH_TLS_DESC64 - 0x8 -# IE64-RELA-NEXT: 0x303E8 R_LARCH_TLS_DESC64 - 0x7FF -# IE64-RELA-NEXT: 0x303D8 R_LARCH_TLS_DESC64 c 0x0 +# IE64-RELA-NEXT: 0x30398 R_LARCH_TLS_TPREL64 c 0x0 # IE64-RELA-NEXT: } # IE64-RELA: Hex dump of section '.got': -# IE64-RELA-NEXT: 0x000303c8 00000000 00000000 00000000 00000000 . -# IE64-RELA-NEXT: 0x000303d8 00000000 00000000 00000000 00000000 . -# IE64-RELA-NEXT: 0x000303e8 00000000 00000000 00000000 00000000 . +# IE64-RELA-NEXT: 0x00030398 00000000 00000000 . + +## a and b are optimized to use LE. c is optimized to IE. +# IE64-LABEL: <.text>: +# IE64-NEXT: nop +# IE64-NEXT: nop +# IE64-NEXT: ori $a0, $zero, 8 +# IE64-NEXT: add.d $a1, $a0, $tp +# IE64-NEXT: nop +# IE64-NEXT: nop +# IE64-NEXT: ori $a0, $zero, 2047 +# IE64-NEXT: add.d $a2, $a0, $tp +## &.got[c]-. = 0x30398 - 0x202ac: 0x10 pages, page offset 0x398 +# IE64-NEXT: nop +# IE64-NEXT: 202ac: pcalau12i $a0, 16 +# IE64-NEXT: ld.d $a0, $a0, 920 +# IE64-NEXT: add.d $a3, $a0, $tp # GD32-REL: .rel.dyn { # GD32-REL-NEXT: 0x20264 R_LARCH_TLS_DESC32 - diff --git a/lld/test/ELF/loongarch-tlsdesc.s b/lld/test/ELF/loongarch-tlsdesc.s index bf09b1e4bbae..3dc31210d7dd 100644 --- a/lld/test/ELF/loongarch-tlsdesc.s +++ b/lld/test/ELF/loongarch-tlsdesc.s @@ -14,14 +14,14 @@ # RUN: ld.lld -shared -z now a.64.o c.64.o -o rel.64.so -z rel # RUN: llvm-readobj -r -x .got rel.64.so | FileCheck --check-prefix=GD64-REL %s -## FIXME: The transition frome TLSDESC to IE/LE has not yet been implemented. -## Keep the dynamic relocations and hand them over to dynamic linker. - +## Transition from TLSDESC to IE/LE. # RUN: ld.lld -e 0 -z now a.64.o c.64.o -o a.64.le -# RUN: llvm-readobj -r -x .got a.64.le | FileCheck --check-prefix=LE64-RELA %s +# RUN: llvm-readobj -r -x .got a.64.le 2>&1 | FileCheck --check-prefix=LE64-RELA %s +# RUN: llvm-objdump --no-show-raw-insn -d a.64.le | FileCheck --check-prefix=LE64 %s # RUN: ld.lld -e 0 -z now a.64.o c.64.so -o a.64.ie # RUN: llvm-readobj -r -x .got a.64.ie | FileCheck --check-prefix=IE64-RELA %s +# RUN: llvm-objdump --no-show-raw-insn -d a.64.ie | FileCheck --check-prefix=IE64 %s ## 32-bit code is mostly the same. We only test a few variants. @@ -71,25 +71,52 @@ # GD64-NEXT: jirl $ra, $ra, 0 # GD64-NEXT: add.d $a3, $a0, $tp -# LE64-RELA: .rela.dyn { -# LE64-RELA-NEXT: 0x30250 R_LARCH_TLS_DESC64 - 0x8 -# LE64-RELA-NEXT: 0x30260 R_LARCH_TLS_DESC64 - 0x800 -# LE64-RELA-NEXT: 0x30270 R_LARCH_TLS_DESC64 - 0x7FF -# LE64-RELA-NEXT: } -# LE64-RELA: Hex dump of section '.got': -# LE64-RELA-NEXT: 0x00030250 00000000 00000000 00000000 00000000 . -# LE64-RELA-NEXT: 0x00030260 00000000 00000000 00000000 00000000 . -# LE64-RELA-NEXT: 0x00030270 00000000 00000000 00000000 00000000 . +# LE64-RELA: could not find section '.got' + +# LE64-LABEL: <.text>: +## st_value(a) = 8 +# LE64-NEXT: nop +# LE64-NEXT: nop +# LE64-NEXT: nop +# LE64-NEXT: ori $a0, $zero, 8 +# LE64-NEXT: add.d $a1, $a0, $tp +## st_value(b) = 2047 +# LE64-NEXT: nop +# LE64-NEXT: nop +# LE64-NEXT: nop +# LE64-NEXT: ori $a0, $zero, 2047 +# LE64-NEXT: add.d $a2, $a0, $tp +## st_value(c) = 2048 +# LE64-NEXT: nop +# LE64-NEXT: nop +# LE64-NEXT: nop +# LE64-NEXT: ori $a0, $zero, 2048 +# LE64-NEXT: add.d $a3, $a0, $tp # IE64-RELA: .rela.dyn { -# IE64-RELA-NEXT: 0x303D8 R_LARCH_TLS_DESC64 - 0x8 -# IE64-RELA-NEXT: 0x303F8 R_LARCH_TLS_DESC64 - 0x7FF -# IE64-RELA-NEXT: 0x303E8 R_LARCH_TLS_DESC64 c 0x0 +# IE64-RELA-NEXT: 0x303A8 R_LARCH_TLS_TPREL64 c 0x0 # IE64-RELA-NEXT: } # IE64-RELA: Hex dump of section '.got': -# IE64-RELA-NEXT: 0x000303d8 00000000 00000000 00000000 00000000 . -# IE64-RELA-NEXT: 0x000303e8 00000000 00000000 00000000 00000000 . -# IE64-RELA-NEXT: 0x000303f8 00000000 00000000 00000000 00000000 . +# IE64-RELA-NEXT: 0x000303a8 00000000 00000000 . + +## a and b are optimized to use LE. c is optimized to IE. +# IE64-LABEL: <.text>: +# IE64-NEXT: nop +# IE64-NEXT: nop +# IE64-NEXT: nop +# IE64-NEXT: ori $a0, $zero, 8 +# IE64-NEXT: add.d $a1, $a0, $tp +# IE64-NEXT: nop +# IE64-NEXT: nop +# IE64-NEXT: nop +# IE64-NEXT: ori $a0, $zero, 2047 +# IE64-NEXT: add.d $a2, $a0, $tp +## &.got[c]-. = 0x303a8 - 0x202b8: 0x10 pages, page offset 0x3a8 +# IE64-NEXT: nop +# IE64-NEXT: nop +# IE64-NEXT: 202b8: pcalau12i $a0, 16 +# IE64-NEXT: ld.d $a0, $a0, 936 +# IE64-NEXT: add.d $a3, $a0, $tp # GD32-REL: .rel.dyn { # GD32-REL-NEXT: 0x20270 R_LARCH_TLS_DESC32 -