diff options
-rw-r--r-- | lld/ELF/Arch/LoongArch.cpp | 40 | ||||
-rw-r--r-- | lld/ELF/InputSection.cpp | 2 | ||||
-rw-r--r-- | lld/ELF/Relocations.cpp | 12 | ||||
-rw-r--r-- | lld/ELF/Relocations.h | 1 | ||||
-rw-r--r-- | lld/test/ELF/loongarch-tlsdesc-gd-mixed.s | 23 | ||||
-rw-r--r-- | lld/test/ELF/loongarch-tlsdesc.s | 132 |
6 files changed, 210 insertions, 0 deletions
diff --git a/lld/ELF/Arch/LoongArch.cpp b/lld/ELF/Arch/LoongArch.cpp index 2c5d5df..c6ee73f 100644 --- a/lld/ELF/Arch/LoongArch.cpp +++ b/lld/ELF/Arch/LoongArch.cpp @@ -98,11 +98,13 @@ uint64_t elf::getLoongArchPageDelta(uint64_t dest, uint64_t pc, RelType type) { case R_LARCH_PCALA64_LO20: case R_LARCH_GOT64_PC_LO20: case R_LARCH_TLS_IE64_PC_LO20: + case R_LARCH_TLS_DESC64_PC_LO20: pcalau12i_pc = pc - 8; break; case R_LARCH_PCALA64_HI12: case R_LARCH_GOT64_PC_HI12: case R_LARCH_TLS_IE64_PC_HI12: + case R_LARCH_TLS_DESC64_PC_HI12: pcalau12i_pc = pc - 12; break; default: @@ -190,11 +192,13 @@ LoongArch::LoongArch() { tlsModuleIndexRel = R_LARCH_TLS_DTPMOD64; tlsOffsetRel = R_LARCH_TLS_DTPREL64; tlsGotRel = R_LARCH_TLS_TPREL64; + tlsDescRel = R_LARCH_TLS_DESC64; } else { symbolicRel = R_LARCH_32; tlsModuleIndexRel = R_LARCH_TLS_DTPMOD32; tlsOffsetRel = R_LARCH_TLS_DTPREL32; tlsGotRel = R_LARCH_TLS_TPREL32; + tlsDescRel = R_LARCH_TLS_DESC32; } gotRel = symbolicRel; @@ -294,6 +298,10 @@ int64_t LoongArch::getImplicitAddend(const uint8_t *buf, RelType type) const { case R_LARCH_JUMP_SLOT: // These relocations are defined as not having an implicit addend. return 0; + case R_LARCH_TLS_DESC32: + return read32le(buf + 4); + case R_LARCH_TLS_DESC64: + return read64le(buf + 8); } } @@ -486,6 +494,19 @@ RelExpr LoongArch::getRelExpr(const RelType type, const Symbol &s, return config->relax ? R_RELAX_HINT : R_NONE; case R_LARCH_ALIGN: return R_RELAX_HINT; + case R_LARCH_TLS_DESC_PC_HI20: + case R_LARCH_TLS_DESC64_PC_LO20: + case R_LARCH_TLS_DESC64_PC_HI12: + return R_LOONGARCH_TLSDESC_PAGE_PC; + case R_LARCH_TLS_DESC_PC_LO12: + case R_LARCH_TLS_DESC_LD: + case R_LARCH_TLS_DESC_HI20: + case R_LARCH_TLS_DESC_LO12: + case R_LARCH_TLS_DESC64_LO20: + case R_LARCH_TLS_DESC64_HI12: + return R_TLSDESC; + case R_LARCH_TLS_DESC_CALL: + return R_TLSDESC_CALL; // Other known relocs that are explicitly unimplemented: // @@ -510,6 +531,8 @@ bool LoongArch::usesOnlyLowPageBits(RelType type) const { case R_LARCH_GOT_LO12: case R_LARCH_GOT_PC_LO12: case R_LARCH_TLS_IE_PC_LO12: + case R_LARCH_TLS_DESC_LO12: + case R_LARCH_TLS_DESC_PC_LO12: return true; } } @@ -594,6 +617,8 @@ void LoongArch::relocate(uint8_t *loc, const Relocation &rel, case R_LARCH_TLS_LE_LO12: case R_LARCH_TLS_IE_PC_LO12: case R_LARCH_TLS_IE_LO12: + case R_LARCH_TLS_DESC_PC_LO12: + case R_LARCH_TLS_DESC_LO12: write32le(loc, setK12(read32le(loc), extractBits(val, 11, 0))); return; @@ -609,6 +634,8 @@ void LoongArch::relocate(uint8_t *loc, const Relocation &rel, case R_LARCH_TLS_LD_HI20: case R_LARCH_TLS_GD_PC_HI20: case R_LARCH_TLS_GD_HI20: + case R_LARCH_TLS_DESC_PC_HI20: + case R_LARCH_TLS_DESC_HI20: write32le(loc, setJ20(read32le(loc), extractBits(val, 31, 12))); return; @@ -620,6 +647,8 @@ void LoongArch::relocate(uint8_t *loc, const Relocation &rel, case R_LARCH_TLS_LE64_LO20: case R_LARCH_TLS_IE64_PC_LO20: case R_LARCH_TLS_IE64_LO20: + case R_LARCH_TLS_DESC64_PC_LO20: + case R_LARCH_TLS_DESC64_LO20: write32le(loc, setJ20(read32le(loc), extractBits(val, 51, 32))); return; @@ -631,6 +660,8 @@ void LoongArch::relocate(uint8_t *loc, const Relocation &rel, case R_LARCH_TLS_LE64_HI12: case R_LARCH_TLS_IE64_PC_HI12: case R_LARCH_TLS_IE64_HI12: + case R_LARCH_TLS_DESC64_PC_HI12: + case R_LARCH_TLS_DESC64_HI12: write32le(loc, setK12(read32le(loc), extractBits(val, 63, 52))); return; @@ -679,6 +710,15 @@ void LoongArch::relocate(uint8_t *loc, const Relocation &rel, case R_LARCH_RELAX: return; // Ignored (for now) + case R_LARCH_TLS_DESC_LD: + return; // nothing to do. + case R_LARCH_TLS_DESC32: + write32le(loc + 4, val); + return; + case R_LARCH_TLS_DESC64: + write64le(loc + 8, val); + return; + default: llvm_unreachable("unknown relocation"); } diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index f4287bc..be12218 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -877,6 +877,8 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type, return in.got->getTlsDescAddr(sym) + a - in.gotPlt->getVA(); case R_AARCH64_TLSDESC_PAGE: return getAArch64Page(in.got->getTlsDescAddr(sym) + a) - getAArch64Page(p); + case R_LOONGARCH_TLSDESC_PAGE_PC: + return getLoongArchPageDelta(in.got->getTlsDescAddr(sym) + a, p, type); case R_TLSGD_GOT: return in.got->getGlobalDynOffset(sym) + a; case R_TLSGD_GOTPLT: diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp index 04db413..1b08339 100644 --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -1297,6 +1297,18 @@ static unsigned handleTlsRelocation(RelType type, Symbol &sym, if (config->emachine == EM_MIPS) return handleMipsTlsRelocation(type, sym, c, 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 (config->emachine == EM_LOONGARCH && + oneof<R_LOONGARCH_TLSDESC_PAGE_PC, R_TLSDESC, R_TLSDESC_CALL>(expr)) { + if (expr != R_TLSDESC_CALL) { + sym.setFlags(NEEDS_TLSDESC); + c.addReloc({expr, type, offset, addend, &sym}); + } + return 1; + } + bool isRISCV = config->emachine == EM_RISCV; if (oneof<R_AARCH64_TLSDESC_PAGE, R_TLSDESC, R_TLSDESC_CALL, R_TLSDESC_PC, diff --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h index b7b9c09..e299d23 100644 --- a/lld/ELF/Relocations.h +++ b/lld/ELF/Relocations.h @@ -116,6 +116,7 @@ enum RelExpr { R_LOONGARCH_GOT, R_LOONGARCH_GOT_PAGE_PC, R_LOONGARCH_TLSGD_PAGE_PC, + R_LOONGARCH_TLSDESC_PAGE_PC, }; // Architecture-neutral representation of relocation. diff --git a/lld/test/ELF/loongarch-tlsdesc-gd-mixed.s b/lld/test/ELF/loongarch-tlsdesc-gd-mixed.s new file mode 100644 index 0000000..9f9f21b --- /dev/null +++ b/lld/test/ELF/loongarch-tlsdesc-gd-mixed.s @@ -0,0 +1,23 @@ +# REQUIRES: loongarch +# RUN: llvm-mc -filetype=obj -triple=loongarch64 %s -o %t.o +# RUN: ld.lld -shared %t.o -o %t.so +# RUN: llvm-readobj -r %t.so | FileCheck %s --check-prefix=RELA + +## Both TLSDESC and DTPMOD64/DTPREL64 should be present. +# RELA: .rela.dyn { +# RELA-NEXT: 0x[[#%X,ADDR:]] R_LARCH_TLS_DESC64 a 0x0 +# RELA-NEXT: 0x[[#ADDR+16]] R_LARCH_TLS_DTPMOD64 a 0x0 +# RELA-NEXT: 0x[[#ADDR+24]] R_LARCH_TLS_DTPREL64 a 0x0 +# RELA-NEXT: } + + la.tls.gd $a0,a + bl %plt(__tls_get_addr) + + la.tls.desc $a0, a + add.d $a1, $a0, $tp + +.section .tbss,"awT",@nobits +.globl a +.zero 8 +a: +.zero 4 diff --git a/lld/test/ELF/loongarch-tlsdesc.s b/lld/test/ELF/loongarch-tlsdesc.s new file mode 100644 index 0000000..bf09b1e --- /dev/null +++ b/lld/test/ELF/loongarch-tlsdesc.s @@ -0,0 +1,132 @@ +# REQUIRES: loongarch +# RUN: rm -rf %t && split-file %s %t && cd %t +# RUN: llvm-mc -filetype=obj -triple=loongarch64 a.s -o a.64.o +# RUN: llvm-mc -filetype=obj -triple=loongarch64 c.s -o c.64.o +# RUN: ld.lld -shared -soname=c.64.so c.64.o -o c.64.so +# RUN: llvm-mc -filetype=obj -triple=loongarch32 --defsym ELF32=1 a.s -o a.32.o +# RUN: llvm-mc -filetype=obj -triple=loongarch32 --defsym ELF32=1 c.s -o c.32.o +# RUN: ld.lld -shared -soname=c.32.so c.32.o -o c.32.so + +# RUN: ld.lld -shared -z now a.64.o c.64.o -o a.64.so +# RUN: llvm-readobj -r -x .got a.64.so | FileCheck --check-prefix=GD64-RELA %s +# RUN: llvm-objdump --no-show-raw-insn -h -d a.64.so | FileCheck %s --check-prefix=GD64 + +# 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. + +# 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: 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 + +## 32-bit code is mostly the same. We only test a few variants. + +# RUN: ld.lld -shared -z now a.32.o c.32.o -o rel.32.so -z rel +# RUN: llvm-readobj -r -x .got rel.32.so | FileCheck --check-prefix=GD32-REL %s + +# GD64-RELA: .rela.dyn { +# GD64-RELA-NEXT: 0x20400 R_LARCH_TLS_DESC64 - 0x7FF +# GD64-RELA-NEXT: 0x203E0 R_LARCH_TLS_DESC64 a 0x0 +# GD64-RELA-NEXT: 0x203F0 R_LARCH_TLS_DESC64 c 0x0 +# GD64-RELA-NEXT: } +# GD64-RELA: Hex dump of section '.got': +# GD64-RELA-NEXT: 0x000203e0 00000000 00000000 00000000 00000000 . +# GD64-RELA-NEXT: 0x000203f0 00000000 00000000 00000000 00000000 . +# GD64-RELA-NEXT: 0x00020400 00000000 00000000 00000000 00000000 . + +# GD64-REL: .rel.dyn { +# GD64-REL-NEXT: 0x203E8 R_LARCH_TLS_DESC64 - +# GD64-REL-NEXT: 0x203C8 R_LARCH_TLS_DESC64 a +# GD64-REL-NEXT: 0x203D8 R_LARCH_TLS_DESC64 c +# GD64-REL-NEXT: } +# GD64-REL: Hex dump of section '.got': +# GD64-REL-NEXT: 0x000203c8 00000000 00000000 00000000 00000000 . +# GD64-REL-NEXT: 0x000203d8 00000000 00000000 00000000 00000000 . +# GD64-REL-NEXT: 0x000203e8 00000000 00000000 ff070000 00000000 . + +# GD64: .got 00000030 00000000000203e0 + +## &.got[a]-. = 0x203e0 - 0x102e0: 0x10 pages, page offset 0x3e0 +# GD64: 102e0: pcalau12i $a0, 16 +# GD64-NEXT: addi.d $a0, $a0, 992 +# GD64-NEXT: ld.d $ra, $a0, 0 +# GD64-NEXT: jirl $ra, $ra, 0 +# GD64-NEXT: add.d $a1, $a0, $tp + +## &.got[b]-. = 0x203e0+32 - 0x102f4: 0x10 pages, page offset 0x400 +# GD64: 102f4: pcalau12i $a0, 16 +# GD64-NEXT: addi.d $a0, $a0, 1024 +# GD64-NEXT: ld.d $ra, $a0, 0 +# GD64-NEXT: jirl $ra, $ra, 0 +# GD64-NEXT: add.d $a2, $a0, $tp + +## &.got[c]-. = 0x23e0+16 - 0x10308: 0x10 pages, page offset 0x3f0 +# GD64: 10308: pcalau12i $a0, 16 +# GD64-NEXT: addi.d $a0, $a0, 1008 +# GD64-NEXT: ld.d $ra, $a0, 0 +# 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 . + +# 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: } +# 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 . + +# GD32-REL: .rel.dyn { +# GD32-REL-NEXT: 0x20270 R_LARCH_TLS_DESC32 - +# GD32-REL-NEXT: 0x20260 R_LARCH_TLS_DESC32 a +# GD32-REL-NEXT: 0x20268 R_LARCH_TLS_DESC32 c +# GD32-REL-NEXT: } +# GD32-REL: Hex dump of section '.got': +# GD32-REL-NEXT: 0x00020260 00000000 00000000 00000000 00000000 . +# GD32-REL-NEXT: 0x00020270 00000000 ff070000 . + +#--- a.s +.macro add dst, src1, src2 +.ifdef ELF32 +add.w \dst, \src1, \src2 +.else +add.d \dst, \src1, \src2 +.endif +.endm + +la.tls.desc $a0, a +add $a1, $a0, $tp + +la.tls.desc $a0, b +add $a2, $a0, $tp + +la.tls.desc $a0, c +add $a3, $a0, $tp + +.section .tbss,"awT",@nobits +.globl a +.zero 8 +a: +.zero 2039 ## Place b at 0x7ff +b: +.zero 1 + +#--- c.s +.section .tbss,"awT",@nobits +.globl c +c: .zero 4 |