Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[lld][ELF] Add basic TLSDESC support for LoongArch #94451

Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions lld/ELF/Arch/LoongArch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
}

Expand Down Expand Up @@ -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:
//
Expand All @@ -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;
}
}
Expand Down Expand Up @@ -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;

Expand All @@ -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;

Expand All @@ -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;

Expand All @@ -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;

Expand Down Expand Up @@ -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");
}
Expand Down
2 changes: 2 additions & 0 deletions lld/ELF/InputSection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
12 changes: 12 additions & 0 deletions lld/ELF/Relocations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 TLS DESC to LE/IE, so
wangleiat marked this conversation as resolved.
Show resolved Hide resolved
// 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,
Expand Down
1 change: 1 addition & 0 deletions lld/ELF/Relocations.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
23 changes: 23 additions & 0 deletions lld/test/ELF/loongarch-tlsdesc-gd-mixed.s
Original file line number Diff line number Diff line change
@@ -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
132 changes: 132 additions & 0 deletions lld/test/ELF/loongarch-tlsdesc.s
Original file line number Diff line number Diff line change
@@ -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
Loading