-
Notifications
You must be signed in to change notification settings - Fork 11.9k
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
[lld][ELF] Add basic TLSDESC support for LoongArch #94451
Conversation
Created using spr 1.3.5-bogner
@llvm/pr-subscribers-lld @llvm/pr-subscribers-lld-elf Author: wanglei (wangleiat) ChangesLoongArch does not yet implemented TLSDESC transition of DESC to LE/IE. Full diff: https://github.com/llvm/llvm-project/pull/94451.diff 6 Files Affected:
diff --git a/lld/ELF/Arch/LoongArch.cpp b/lld/ELF/Arch/LoongArch.cpp
index 2c5d5df922c0f..c6ee73f23d471 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 e6c5996c0b392..03a66552d075b 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 2c02c2e572bfd..b6a4a6d7953b1 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -1303,6 +1303,19 @@ static unsigned handleTlsRelocation(RelType type, Symbol &sym,
if (config->emachine == EM_MIPS)
return handleMipsTlsRelocation(type, sym, c, offset, addend, expr);
+
+ // LoongArch does not yet implemented TLSDESC transition of DESC to LE/IE.
+ // Generates TLSDESC dynamic relocation for the symbol that is handled by the
+ // dynamic linker.
+ 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 b7b9c09e1b892..e299d23dd7db3 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 0000000000000..16f8d288b1898
--- /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
+
+## 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 0000000000000..3d3c309ea73c2
--- /dev/null
+++ b/lld/test/ELF/loongarch-tlsdesc.s
@@ -0,0 +1,134 @@
+# 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
+.section .tbss,"awT",@nobits
+.globl a
+.zero 8
+a:
+.zero 2039 ## Place b at 0x7ff
+b:
+.zero 1
+
+#--- c.s
+.section .tbss,"awT",@nobits
+#.tbss
+.globl c
+c: .zero 4
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't manually verified the test case yet but it seems okay.
Created using spr 1.3.5-bogner
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code change looks good. Do you have plan for TLSDESC to LE/IE optimization?
Consider mentioning #79239 in the description. |
Sorry for the late reply due to the holiday. No plans in the near future. |
Created using spr 1.3.5-bogner
Thanks very much! |
gentle ping. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.
Created using spr 1.3.5-bogner
LoongArch does not yet implement transition from TLSDESC to LE/IE, so TLSDESC dynamic relocation needs to be generated for each desc, which is ultimately handled by the dynamic linker. The test cases reference RISC-V: llvm#79239 Reviewed By: MaskRay, SixWeining Pull Request: llvm#94451
LoongArch does not yet implement transition from TLSDESC to LE/IE,
so TLSDESC dynamic relocation needs to be generated for each desc,
which is ultimately handled by the dynamic linker.
The test cases reference RISC-V: #79239