Skip to content

[RISCV] Support RISC-V TLSDESC in LLD #77516

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

Closed
Show file tree
Hide file tree
Changes from all 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
20 changes: 20 additions & 0 deletions lld/ELF/Arch/RISCV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ class RISCV final : public TargetInfo {
void relocate(uint8_t *loc, const Relocation &rel,
uint64_t val) const override;
void relocateAlloc(InputSectionBase &sec, uint8_t *buf) const override;
RelExpr adjustTlsExpr(RelType type, RelExpr expr) const override;
bool relaxOnce(int pass) const override;
};

Expand Down Expand Up @@ -120,6 +121,8 @@ RISCV::RISCV() {
}
gotRel = symbolicRel;

tlsDescRel = R_RISCV_TLSDESC_CALL;

// .got[0] = _DYNAMIC
gotHeaderEntriesNum = 1;

Expand Down Expand Up @@ -298,6 +301,13 @@ RelExpr RISCV::getRelExpr(const RelType type, const Symbol &s,
return R_TLSGD_PC;
case R_RISCV_TLS_GOT_HI20:
return R_GOT_PC;
case R_RISCV_TLSDESC_HI20:
return R_TLSDESC_PC;
case R_RISCV_TLSDESC_LOAD_LO12:
case R_RISCV_TLSDESC_ADD_LO12:
return R_TLSDESC;
case R_RISCV_TLSDESC_CALL:
return R_TLSDESC_CALL;
case R_RISCV_TPREL_HI20:
case R_RISCV_TPREL_LO12_I:
case R_RISCV_TPREL_LO12_S:
Expand Down Expand Up @@ -420,6 +430,7 @@ void RISCV::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
case R_RISCV_PCREL_HI20:
case R_RISCV_TLS_GD_HI20:
case R_RISCV_TLS_GOT_HI20:
case R_RISCV_TLSDESC_HI20:
case R_RISCV_TPREL_HI20:
case R_RISCV_HI20: {
uint64_t hi = val + 0x800;
Expand All @@ -430,6 +441,8 @@ void RISCV::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {

case R_RISCV_PCREL_LO12_I:
case R_RISCV_TPREL_LO12_I:
case R_RISCV_TLSDESC_LOAD_LO12:
case R_RISCV_TLSDESC_ADD_LO12:
case R_RISCV_LO12_I: {
uint64_t hi = (val + 0x800) >> 12;
uint64_t lo = val - (hi << 12);
Expand Down Expand Up @@ -557,6 +570,13 @@ void RISCV::relocateAlloc(InputSectionBase &sec, uint8_t *buf) const {
}
}

RelExpr RISCV::adjustTlsExpr(RelType type, RelExpr expr) const {
if (expr == R_RELAX_TLS_GD_TO_IE) {
return R_RELAX_TLS_GD_TO_IE_ABS;
}
return expr;
}

namespace {
struct SymbolAnchor {
uint64_t offset;
Expand Down
1 change: 1 addition & 0 deletions lld/ELF/InputSection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -851,6 +851,7 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type,
return sym.getSize() + a;
case R_TLSDESC:
return in.got->getTlsDescAddr(sym) + a;
case R_RISCV_TLSDESC_HI:
case R_TLSDESC_PC:
return in.got->getTlsDescAddr(sym) + a - p;
case R_TLSDESC_GOTPLT:
Expand Down
4 changes: 2 additions & 2 deletions lld/ELF/Relocations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1269,7 +1269,7 @@ static unsigned handleTlsRelocation(RelType type, Symbol &sym,
return handleMipsTlsRelocation(type, sym, c, offset, addend, expr);

if (oneof<R_AARCH64_TLSDESC_PAGE, R_TLSDESC, R_TLSDESC_CALL, R_TLSDESC_PC,
R_TLSDESC_GOTPLT>(expr) &&
R_TLSDESC_GOTPLT, R_RISCV_TLSDESC_HI>(expr) &&
config->shared) {
if (expr != R_TLSDESC_CALL) {
sym.setFlags(NEEDS_TLSDESC);
Expand Down Expand Up @@ -1333,7 +1333,7 @@ static unsigned handleTlsRelocation(RelType type, Symbol &sym,

if (oneof<R_AARCH64_TLSDESC_PAGE, R_TLSDESC, R_TLSDESC_CALL, R_TLSDESC_PC,
R_TLSDESC_GOTPLT, R_TLSGD_GOT, R_TLSGD_GOTPLT, R_TLSGD_PC,
R_LOONGARCH_TLSGD_PAGE_PC>(expr)) {
R_LOONGARCH_TLSGD_PAGE_PC, R_RISCV_TLSDESC_HI>(expr)) {
if (!toExecRelax) {
sym.setFlags(NEEDS_TLSGD);
c.addReloc({expr, type, offset, addend, &sym});
Expand Down
4 changes: 4 additions & 0 deletions lld/ELF/Relocations.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@ enum RelExpr {
R_RISCV_ADD,
R_RISCV_LEB128,
R_RISCV_PC_INDIRECT,
R_RISCV_TLSDESC_HI,
R_RISCV_TLSDESC_LOAD_LO,
R_RISCV_TLSDESC_ADD_LO,
R_RISCV_TLSDESC_CALLER,
// Same as R_PC but with page-aligned semantics.
R_LOONGARCH_PAGE_PC,
// Same as R_PLT_PC but with page-aligned semantics.
Expand Down
3 changes: 2 additions & 1 deletion lld/ELF/Writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1950,7 +1950,8 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
}
}

if (config->emachine == EM_386 || config->emachine == EM_X86_64) {
if (config->emachine == EM_386 || config->emachine == EM_X86_64 ||
config->emachine == EM_RISCV) {
// On targets that support TLSDESC, _TLS_MODULE_BASE_ is defined in such a
// way that:
//
Expand Down
60 changes: 60 additions & 0 deletions lld/test/ELF/riscv-tlsdesc-le.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// RUN: llvm-mc -filetype=obj -triple=riscv64-pc-linux %s -o %t.o
// RUN: ld.lld -shared %t.o -o %t.so
// RUN: llvm-objdump --no-print-imm-hex -d --no-show-raw-insn %t.so | FileCheck %s
// RUN: llvm-readelf -r %t.so | FileCheck --check-prefix=REL %s

// CHECK: 0000000000001318 <_start>:
// CHECK-NEXT: 1318: auipc a0, 1
// CHECK-NEXT: 131c: ld a1, 1008(a0)
// CHECK-NEXT: 1320: addi a0, a0, 1008
// CHECK-NEXT: 1324: jalr t0, a1
// CHECK-NEXT: 1328: add a0, a0, tp
// CHECK-NEXT: 132c: auipc a0, 1
// CHECK-NEXT: 1330: ld a1, 1040(a0)
// CHECK-NEXT: 1334: addi a0, a0, 1040
// CHECK-NEXT: 1338: jalr t0, a1
// CHECK-NEXT: 133c: add a0, a0, tp
// CHECK-NEXT: 1340: ret

// REL: Relocation section '.rela.dyn' at offset 0x{{[0-9a-f]+}} contains 3 entries
// REL: R_RISCV_TLSDESC_CALL ffffffffffffffd4
// REL-NEXT: R_RISCV_TLSDESC_CALL 4
// REL-NEXT: R_RISCV_TLSDESC_CALL ffffffffffffffe8

.text
.attribute 4, 16
.attribute 5, "rv64i2p1"
.file "<stdin>"
.globl _start # -- Begin function _start
.p2align 2
.type _start,@function
_start: # @_start
// access local variable
.Ltlsdesc_hi0:
auipc a0, %tlsdesc_hi(unspecified)
ld a1, %tlsdesc_load_lo(.Ltlsdesc_hi0)(a0)
addi a0, a0, %tlsdesc_add_lo(.Ltlsdesc_hi0)
jalr t0, 0(a1), %tlsdesc_call(.Ltlsdesc_hi0)
add a0, a0, tp

// access global variable
.Ltlsdesc_hi1:
auipc a0, %tlsdesc_hi(unspecified)
ld a1, %tlsdesc_load_lo(.Ltlsdesc_hi1)(a0)
addi a0, a0, %tlsdesc_add_lo(.Ltlsdesc_hi1)
jalr t0, 0(a1), %tlsdesc_call(.Ltlsdesc_hi1)
add a0, a0, tp
ret
.Lfunc_end0:
.size _start, .Lfunc_end0-_start
# -- End function
.section ".note.GNU-stack","",@progbits

.section .tbss,"awT",@nobits
.p2align 2
.global v1
v1:
.zero 4

unspecified:
.zero 4