Index: ELF/Arch/RISCV.cpp =================================================================== --- ELF/Arch/RISCV.cpp +++ ELF/Arch/RISCV.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "InputFiles.h" +#include "SyntheticSections.h" #include "Target.h" using namespace llvm; @@ -22,14 +23,83 @@ public: RISCV(); uint32_t calcEFlags() const override; + void writeGotHeader(uint8_t *Buf) const override; + void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; + void writePltHeader(uint8_t *Buf) const override; + void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, + int32_t Index, unsigned RelOff) const override; + RelType getDynRel(RelType Type) const override; RelExpr getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const override; void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; + void relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const override; + void relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; + void relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; + void relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; }; } // end anonymous namespace -RISCV::RISCV() { NoneRel = R_RISCV_NONE; } +static uint64_t DTPOffset = 0x800; + +enum Op { + ADDI = 0x13, + AUIPC = 0x17, + JALR = 0x67, + LD = 0x3003, + LW = 0x2003, + SRLI = 0x5013, + SUB = 0x40000033, +}; + +enum Reg { + X_RA = 1, + X_T0 = 5, + X_T1 = 6, + X_T2 = 7, + X_T3 = 28, +}; + +static uint32_t hi20(uint32_t Val) { return (Val + 0x800) >> 12; } +static uint32_t lo12(uint32_t Val) { return Val & 4095; } + +static uint32_t itype(uint32_t Op, uint32_t Rd, uint32_t Rs1, uint32_t Imm) { + return Op | (Rd << 7) | (Rs1 << 15) | (Imm << 20); +} +static uint32_t rtype(uint32_t Op, uint32_t Rd, uint32_t Rs1, uint32_t Rs2) { + return Op | (Rd << 7) | (Rs1 << 15) | (Rs2 << 20); +} +static uint32_t utype(uint32_t Op, uint32_t Rd, uint32_t Imm) { + return Op | (Rd << 7) | (Imm << 12); +} + +RISCV::RISCV() { + CopyRel = R_RISCV_COPY; + NoneRel = R_RISCV_NONE; + PltRel = R_RISCV_JUMP_SLOT; + RelativeRel = R_RISCV_RELATIVE; + SymbolicRel = Config->Is64 ? R_RISCV_64 : R_RISCV_32; + if (Config->Is64) { + TlsModuleIndexRel = R_RISCV_TLS_DTPMOD64; + TlsOffsetRel = R_RISCV_TLS_DTPREL64; + TlsGotRel = R_RISCV_TLS_TPREL64; + } else { + TlsModuleIndexRel = R_RISCV_TLS_DTPMOD32; + TlsOffsetRel = R_RISCV_TLS_DTPREL32; + TlsGotRel = R_RISCV_TLS_TPREL32; + } + GotRel = SymbolicRel; + + // .got[0] = _DYNAMIC + GotBaseSymInGotPlt = false; + GotHeaderEntriesNum = 1; + + // .got.plt[0] = _dl_runtime_resolve, .got.plt[1] = link_map + GotPltHeaderEntriesNum = 2; + + PltEntrySize = 16; + PltHeaderSize = 32; +} static uint32_t getEFlags(InputFile *F) { if (Config->Is64) @@ -59,6 +129,62 @@ return Target; } +void RISCV::writeGotHeader(uint8_t *Buf) const { + if (Config->Is64) + write64le(Buf, Main->Dynamic->getVA()); + else + write32le(Buf, Main->Dynamic->getVA()); +} + +void RISCV::writeGotPlt(uint8_t *Buf, const Symbol &S) const { + if (Config->Is64) + write64le(Buf, In.Plt->getVA()); + else + write32le(Buf, In.Plt->getVA()); +} + +void RISCV::writePltHeader(uint8_t *Buf) const { + if (Config->EFlags & EF_RISCV_RVE) + error("PLT is not supported for RVE"); + + // 1: auipc t2, %pcrel_hi(.got.plt) + // sub t1, t1, t3 + // l[wd] t3, %pcrel_lo(1b)(t2); t3 = _dl_runtime_resolve + // addi t1, t1, -PltHeaderSize-12; t1 = &.plt[i] - &.plt[0] + // addi t0, t2, %pcrel_lo(1b) + // srli t1, t1, (rv64?1:2); t1 = &.got.plt[i] - &.got.plt[0] + // l[wd] t0, Wordsize(t0); t0 = link_map + // jr t3 + uint32_t Offset = In.GotPlt->getVA() - In.Plt->getVA(); + uint32_t Load = Config->Is64 ? LD : LW; + write32le(Buf + 0, utype(AUIPC, X_T2, hi20(Offset))); + write32le(Buf + 4, rtype(SUB, X_T1, X_T1, X_T3)); + write32le(Buf + 8, itype(Load, X_T3, X_T2, lo12(Offset))); + write32le(Buf + 12, itype(ADDI, X_T1, X_T1, -Target->PltHeaderSize - 12)); + write32le(Buf + 16, itype(ADDI, X_T0, X_T2, lo12(Offset))); + write32le(Buf + 20, itype(SRLI, X_T1, X_T1, Config->Is64 ? 1 : 2)); + write32le(Buf + 24, itype(Load, X_T0, X_T0, Config->Wordsize)); + write32le(Buf + 28, itype(JALR, 0, X_T3, 0)); +} + +void RISCV::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff) const { + // 1: auipc t3, %pcrel_hi(f@.got.plt) + // l[wd] t3, %pcrel_lo(1b)(t3) + // jalr t1, t3 + // nop + uint32_t Offset = GotPltEntryAddr - PltEntryAddr; + write32le(Buf + 0, utype(AUIPC, X_T3, hi20(Offset))); + write32le(Buf + 4, itype(Config->Is64 ? LD : LW, X_T3, X_T3, lo12(Offset))); + write32le(Buf + 8, itype(JALR, X_T1, X_T3, 0)); + write32le(Buf + 12, itype(ADDI, 0, 0, 0)); +} + +RelType RISCV::getDynRel(RelType Type) const { + return Type == Target->GotRel ? Type : R_RISCV_NONE; +} + RelExpr RISCV::getRelExpr(const RelType Type, const Symbol &S, const uint8_t *Loc) const { switch (Type) { @@ -84,9 +210,17 @@ case R_RISCV_RVC_JUMP: case R_RISCV_32_PCREL: return R_PC; + case R_RISCV_CALL_PLT: + return R_PLT_PC; + case R_RISCV_GOT_HI20: + return R_GOT_PC; case R_RISCV_PCREL_LO12_I: case R_RISCV_PCREL_LO12_S: return R_RISCV_PC_INDIRECT; + case R_RISCV_TLS_GD_HI20: + return R_TLSGD_PC; + case R_RISCV_TLS_GOT_HI20: + return R_GOT_OFF; case R_RISCV_RELAX: case R_RISCV_ALIGN: return R_HINT; @@ -189,7 +323,8 @@ } // auipc + jalr pair - case R_RISCV_CALL: { + case R_RISCV_CALL: + case R_RISCV_CALL_PLT: { int64_t Hi = SignExtend64(Val + 0x800, Bits) >> 12; checkInt(Loc, Hi, 20, Type); if (isInt<20>(Hi)) { @@ -199,8 +334,10 @@ return; } + case R_RISCV_GOT_HI20: case R_RISCV_PCREL_HI20: - case R_RISCV_HI20: { + case R_RISCV_HI20: + case R_RISCV_TLS_GD_HI20: { uint64_t Hi = Val + 0x800; checkInt(Loc, SignExtend64(Hi, Bits) >> 12, 20, Type); write32le(Loc, (read32le(Loc) & 0xFFF) | (Hi & 0xFFFFF000)); @@ -266,6 +403,13 @@ write32le(Loc, Val); return; + case R_RISCV_TLS_DTPREL32: + write32le(Loc, Val - DTPOffset); + break; + case R_RISCV_TLS_DTPREL64: + write64le(Loc, Val - DTPOffset); + break; + case R_RISCV_ALIGN: case R_RISCV_RELAX: return; // Ignored (for now) @@ -287,6 +431,22 @@ } } +void RISCV::relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const { + relocateOne(Loc, Type, Val); +} + +void RISCV::relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { + relocateOne(Loc, Type, Val); +} + +void RISCV::relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { + relocateOne(Loc, Type, Val); +} + +void RISCV::relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { + relocateOne(Loc, Type, Val); +} + TargetInfo *elf::getRISCVTargetInfo() { static RISCV Target; return &Target; Index: ELF/InputSection.cpp =================================================================== --- ELF/InputSection.cpp +++ ELF/InputSection.cpp @@ -587,7 +587,8 @@ }); for (auto It = Range.first; It != Range.second; ++It) - if (It->Expr == R_PC) + if (It->Type == R_RISCV_PCREL_HI20 || It->Type == R_RISCV_GOT_HI20 || + It->Type == R_RISCV_TLS_GD_HI20) return &*It; error("R_RISCV_PCREL_LO12 relocation points to " + IS->getObjMsg(D->Value) + @@ -620,6 +621,8 @@ // offset to reach 0x1000 of TCB/thread-library data and 0xf000 of the // program's TLS segment. return S.getVA(0) - 0x7000; + case EM_RISCV: + return S.getVA(0); default: llvm_unreachable("unhandled Config->EMachine"); } Index: ELF/Relocations.cpp =================================================================== --- ELF/Relocations.cpp +++ ELF/Relocations.cpp @@ -217,6 +217,9 @@ if (Config->EMachine == EM_MIPS) return handleMipsTlsRelocation(Type, Sym, C, Offset, Addend, Expr); + // RISC-V psABI doesn't specify TLS relaxation. + bool NoRelax = Config->EMachine == EM_RISCV; + if (oneof( Expr) && Config->Shared) { @@ -271,10 +274,14 @@ if (oneof(Expr)) { - if (Config->Shared) { + if (NoRelax || Config->Shared) { if (In.Got->addDynTlsEntry(Sym)) { uint64_t Off = In.Got->getGlobalDynOffset(Sym); - Main->RelaDyn->addReloc(Target->TlsModuleIndexRel, In.Got, Off, &Sym); + if (Config->Shared) + Main->RelaDyn->addReloc(Target->TlsModuleIndexRel, In.Got, Off, &Sym); + else + // DTPMOD is constant 1 when producing an executable for RISC-V. + In.Got->Relocations.push_back({R_ADDEND, Target->SymbolicRel, Off, 1, &Sym}); // If the symbol is preemptible we need the dynamic linker to write // the offset too. Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -416,9 +416,10 @@ Add(Part.Dynamic); Add(Part.DynStrTab); - Add(Part.RelaDyn); } + Add(Part.RelaDyn); + if (Config->RelrPackDynRelocs) { Part.RelrDyn = make>(); Add(Part.RelrDyn); Index: test/ELF/riscv-plt.s =================================================================== --- /dev/null +++ test/ELF/riscv-plt.s @@ -0,0 +1,103 @@ +# REQUIRES: riscv +# RUN: echo '.globl bar, weak; .type bar,@function; .type weak,@function; bar: weak:' > %t1.s + +# RUN: llvm-mc -filetype=obj -triple=riscv32 %t1.s -o %t1.32.o +# RUN: ld.lld -shared %t1.32.o -o %t1.32.so +# RUN: llvm-mc -filetype=obj -triple=riscv32 %s -o %t.32.o +# RUN: ld.lld %t.32.o %t1.32.so -o %t.32 +# RUN: llvm-readelf -S %t.32 | FileCheck --check-prefix=SEC %s +# RUN: llvm-readobj -r %t.32 | FileCheck --check-prefix=RELOC32 %s +# RUN: llvm-readelf -x .got.plt %t.32 | FileCheck --check-prefix=GOTPLT32 %s +# RUN: llvm-objdump -d --no-show-raw-insn %t.32 | FileCheck --check-prefixes=DIS,DIS32 %s + +# RUN: llvm-mc -filetype=obj -triple=riscv64 %t1.s -o %t1.64.o +# RUN: ld.lld -shared %t1.64.o -o %t1.64.so +# RUN: llvm-mc -filetype=obj -triple=riscv64 %s -o %t.64.o +# RUN: ld.lld %t.64.o %t1.64.so -o %t.64 +# RUN: llvm-readelf -S %t.64 | FileCheck --check-prefix=SEC %s +# RUN: llvm-readobj -r %t.64 | FileCheck --check-prefix=RELOC64 %s +# RUN: llvm-readelf -x .got.plt %t.64 | FileCheck --check-prefix=GOTPLT64 %s +# RUN: llvm-objdump -d --no-show-raw-insn %t.64 | FileCheck --check-prefixes=DIS,DIS64 %s + +# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+e %t1.s -o %t1.32e.o +# RUN: ld.lld -shared %t1.32e.o -o %t1.32e.so +# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+e %s -o %t.32e.o +# RUN: not ld.lld %t.32e.o %t1.32e.so -o %t.32e 2>&1 | FileCheck --check-prefix=ERR %s +# ERR: PLT is not supported for RVE + +# SEC: .plt PROGBITS {{0*}}00011030 + +## The .got.plt slots relocated by .rela.plt point to .plt +## This is required by glibc. +# RELOC32: .rela.plt { +# RELOC32-NEXT: 0x13008 R_RISCV_JUMP_SLOT bar 0x0 +# RELOC32-NEXT: 0x1300C R_RISCV_JUMP_SLOT weak 0x0 +# RELOC32-NEXT: } +# GOTPLT32: section '.got.plt' +# GOTPLT32-NEXT: 0x00013000 00000000 00000000 30100100 30100100 + +# RELOC64: .rela.plt { +# RELOC64-NEXT: 0x13010 R_RISCV_JUMP_SLOT bar 0x0 +# RELOC64-NEXT: 0x13018 R_RISCV_JUMP_SLOT weak 0x0 +# RELOC64-NEXT: } +# GOTPLT64: section '.got.plt' +# GOTPLT64-NEXT: 0x00013000 00000000 00000000 00000000 00000000 +# GOTPLT64-NEXT: 0x00013010 30100100 00000000 30100100 00000000 + +# DIS: _start: +## Direct call +# DIS-NEXT: auipc ra, 0 +# DIS-NEXT: 11004: jalr ra, ra, 32 +## foo@plt - . = 0x11050-0x1100c = 72 +# DIS-NEXT: auipc ra, 0 +# DIS-NEXT: 1100c: jalr ra, ra, 72 +## foo@plt - . = 0x11050-0x1100c = 72 +# DIS-NEXT: auipc ra, 0 +# DIS-NEXT: 11014: jalr ra, ra, 64 +## bar@plt - . = 0x11060-0x1101c = 76 +# DIS-NEXT: auipc ra, 0 +# DIS-NEXT: 1101c: jalr ra, ra, 72 +# DIS: foo: +# DIS-NEXT: 11020: + +# DIS: Disassembly of section .plt: +# DIS: .plt: +# DIS-NEXT: auipc t2, 2 +# DIS-NEXT: sub t1, t1, t3 +## .got.plt - .plt = 0x13000 - 0x11030 = 4096*2-48 +# DIS32-NEXT: lw t3, -48(t2) +# DIS64-NEXT: ld t3, -48(t2) +# DIS-NEXT: addi t1, t1, -44 +# DIS-NEXT: addi t0, t2, -48 +# DIS32-NEXT: srli t1, t1, 2 +# DIS64-NEXT: srli t1, t1, 1 +# DIS32-NEXT: lw t0, 4(t0) +# DIS64-NEXT: ld t0, 8(t0) +# DIS-NEXT: jr t3 + +## 32-bit: &.got.plt[bar]-. = 0x13008-0x11050 = 4096*2-72 +# DIS: 11050: auipc t3, 2 +# DIS32-NEXT: lw t3, -72(t3) +# DIS64-NEXT: ld t3, -64(t3) +# DIS-NEXT: jalr t1, t3, 0 +# DIS-NEXT: nop + +## 32-bit: &.got.plt[weak]-. = 0x1300c-0x11060 = 4096*2-84 +# DIS: 11060: auipc t3, 2 +# DIS32-NEXT: lw t3, -84(t3) +# DIS64-NEXT: ld t3, -72(t3) +# DIS-NEXT: jalr t1, t3, 0 +# DIS-NEXT: nop + +.global _start, foo, bar +.weak weak + +_start: + call foo + call bar + call bar@plt + call weak + +## foo is local and non-preemptale, no PLT is generated. +foo: + ret Index: test/ELF/riscv-reloc-64-pic.s =================================================================== --- /dev/null +++ test/ELF/riscv-reloc-64-pic.s @@ -0,0 +1,10 @@ +# REQUIRES: riscv +# RUN: llvm-mc -filetype=obj -triple=riscv64 %s -o %t.o +# RUN: not ld.lld -shared %t.o -o %t.so 2>&1 | FileCheck %s + +# CHECK: error: relocation R_RISCV_32 cannot be used against symbol a + +.globl a + +.data +.long a Index: test/ELF/riscv-reloc-copy.s =================================================================== --- /dev/null +++ test/ELF/riscv-reloc-copy.s @@ -0,0 +1,23 @@ +# REQUIRES: riscv +# RUN: llvm-mc -filetype=obj -triple=riscv32 %p/Inputs/relocation-copy.s -o %t1.o +# RUN: ld.lld -shared %t1.o -o %t1.so +# RUN: llvm-mc -filetype=obj -triple=riscv32 %s -o %t.o +# RUN: ld.lld %t.o %t1.so -o %t +# RUN: llvm-readobj -r %t | FileCheck --check-prefix=RELOC %s +# RUN: llvm-nm -S %t | FileCheck --check-prefix=NM32 %s + +# RUN: llvm-mc -filetype=obj -triple=riscv64 %p/Inputs/relocation-copy.s -o %t1.o +# RUN: ld.lld -shared %t1.o -o %t1.so +# RUN: llvm-mc -filetype=obj -triple=riscv64 %s -o %t.o +# RUN: ld.lld %t.o %t1.so -o %t +# RUN: llvm-readobj -r %t | FileCheck --check-prefix=RELOC %s +# RUN: llvm-nm -S %t | FileCheck --check-prefix=NM64 %s + +# RELOC: .rela.dyn { +# RELOC-NEXT: 0x13000 R_RISCV_COPY x 0x0 +# RELOC-NEXT: } + +# NM32: 00013000 00000004 B x +# NM64: 0000000000013000 0000000000000004 B x + +la a0, x Index: test/ELF/riscv-reloc-got.s =================================================================== --- /dev/null +++ test/ELF/riscv-reloc-got.s @@ -0,0 +1,65 @@ +# REQUIRES: riscv +# RUN: echo '.globl b; b:' | llvm-mc -filetype=obj -triple=riscv32 - -o %t1.o +# RUN: ld.lld -shared %t1.o -o %t1.so + +# RUN: llvm-mc -filetype=obj -triple=riscv32 -position-independent %s -o %t.o +# RUN: ld.lld %t.o %t1.so -o %t +# RUN: llvm-readobj -r %t | FileCheck --check-prefix=RELOC32 %s +# RUN: llvm-nm %t | FileCheck --check-prefix=NM %s +# RUN: llvm-readobj -x .got %t | FileCheck --check-prefix=HEX32 %s +# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=DIS32 %s + +# RUN: echo '.globl b; b:' | llvm-mc -filetype=obj -triple=riscv64 - -o %t1.o +# RUN: ld.lld -shared %t1.o -o %t1.so + +# RUN: llvm-mc -filetype=obj -triple=riscv64 -position-independent %s -o %t.o +# RUN: ld.lld %t.o %t1.so -o %t +# RUN: llvm-readobj -r %t | FileCheck --check-prefix=RELOC64 %s +# RUN: llvm-nm %t | FileCheck --check-prefix=NM %s +# RUN: llvm-readobj -x .got %t | FileCheck --check-prefix=HEX64 %s +# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=DIS64 %s + +# SEC: .got PROGBITS 00012060 020060 00000c + +# RELOC32: .rela.dyn { +# RELOC32-NEXT: 0x12068 R_RISCV_32 b 0x0 +# RELOC32-NEXT: } + +# RELOC64: .rela.dyn { +# RELOC64-NEXT: 0x120D0 R_RISCV_64 b 0x0 +# RELOC64-NEXT: } + +# NM: 00013000 d a + +## .got[0] = _DYNAMIC +## .got[1] = a (filled at link time) +## .got[2] = 0 (relocated by R_RISCV_64 at runtime) +# HEX32: section '.got': +# HEX32: 0x00012060 00200100 00300100 00000000 + +# HEX64: section '.got': +# HEX64: 0x000120c0 00200100 00000000 00300100 00000000 +# HEX64: 0x000120d0 00000000 00000000 + +## &.got[1]-. = 0x12060-0x11000 = 4096*1+100 +# DIS32: 11000: auipc a0, 1 +# DIS32-NEXT: lw a0, 100(a0) +## &.got[2]-. = 0x12064-0x11008 = 4096*1+96 +# DIS32: 11008: auipc a0, 1 +# DIS32-NEXT: lw a0, 96(a0) + +## &.got[1]-. = 0x120c8-0x11000 = 4096*1+100 +# DIS64: 11000: auipc a0, 1 +# DIS64-NEXT: ld a0, 200(a0) +## &.got[2]-. = 0x120d0-0x11008 = 4096*1+200 +# DIS64: 11008: auipc a0, 1 +# DIS64-NEXT: ld a0, 200(a0) + +la a0,a +la a0,b + +.data +a: +## An undefined reference of _GLOBAL_OFFSET_TABLE_ causes .got[0] to be +## allocated to store _DYNAMIC. +.long _GLOBAL_OFFSET_TABLE_ - . Index: test/ELF/riscv-tls-gd.s =================================================================== --- /dev/null +++ test/ELF/riscv-tls-gd.s @@ -0,0 +1,119 @@ +# REQUIRES: riscv +# RUN: echo '.tbss; .globl b, c; b: .zero 4; c:' > %t.s +# RUN: echo '.globl __tls_get_addr; __tls_get_addr:' > %tga.s + +## RISC-V psABI doesn't specify TLS relaxation. The instructions are not relaxed. +## We should verify that dynamic relocations and the contents of .got are correct. + +# RUN: llvm-mc -filetype=obj -triple=riscv32 %s -o %t.o +# RUN: llvm-mc -filetype=obj -triple=riscv32 %t.s -o %t1.o +# RUN: ld.lld -shared -soname=t1.so %t1.o -o %t1.so +# RUN: llvm-mc -filetype=obj -triple=riscv32 %tga.s -o %tga.o +## 32-bit GD +# RUN: ld.lld -shared %t.o %t1.o -o %t.so +# RUN: llvm-readobj -r %t.so | FileCheck --check-prefix=GD32-REL %s +# RUN: llvm-objdump -d --no-show-raw-insn %t.so | FileCheck --check-prefix=GD32 %s +## 32-bit GD->LE +# RUN: ld.lld %t.o %t1.o %tga.o -o %t +# RUN: llvm-readelf -r %t | FileCheck --check-prefix=NOREL %s +# RUN: llvm-readelf -x .got %t | FileCheck --check-prefix=LE32-GOT %s +# RUN: ld.lld -pie %t.o %t1.o %tga.o -o %t +# RUN: llvm-readelf -r %t | FileCheck --check-prefix=NOREL %s +# RUN: llvm-readelf -x .got %t | FileCheck --check-prefix=LE32-GOT %s +## 32-bit GD->IE +# RUN: ld.lld %t.o %t1.so %tga.o -o %t +# RUN: llvm-readobj -r %t | FileCheck --check-prefix=IE32-REL %s +# RUN: llvm-readelf -x .got %t | FileCheck --check-prefix=IE32-GOT %s + +# RUN: llvm-mc -filetype=obj -triple=riscv64 %s -o %t.o +# RUN: llvm-mc -filetype=obj -triple=riscv64 %t.s -o %t1.o +# RUN: ld.lld -shared -soname=t1.so %t1.o -o %t1.so +# RUN: llvm-mc -filetype=obj -triple=riscv64 %tga.s -o %tga.o +## 64-bit GD +# RUN: ld.lld -shared %t.o %t1.o -o %t.so +# RUN: llvm-readobj -r %t.so | FileCheck --check-prefix=GD64-REL %s +# RUN: llvm-objdump -d --no-show-raw-insn %t.so | FileCheck --check-prefix=GD64 %s +## 64-bit GD->LE +# RUN: ld.lld %t.o %t1.o %tga.o -o %t +# RUN: llvm-readelf -r %t | FileCheck --check-prefix=NOREL %s +# RUN: llvm-readelf -x .got %t | FileCheck --check-prefix=LE64-GOT %s +# RUN: ld.lld -pie %t.o %t1.o %tga.o -o %t +# RUN: llvm-readelf -r %t | FileCheck --check-prefix=NOREL %s +# RUN: llvm-readelf -x .got %t | FileCheck --check-prefix=LE64-GOT %s +## 64-bit GD->IE +# RUN: ld.lld %t.o %t1.so %tga.o -o %t +# RUN: llvm-readobj -r %t | FileCheck --check-prefix=IE64-REL %s +# RUN: llvm-readelf -x .got %t | FileCheck --check-prefix=IE64-GOT %s + +# GD32-REL: .rela.dyn { +# GD32-REL-NEXT: 0x2070 R_RISCV_TLS_DTPMOD32 a 0x0 +# GD32-REL-NEXT: 0x2074 R_RISCV_TLS_DTPREL32 a 0x0 +# GD32-REL-NEXT: 0x2078 R_RISCV_TLS_DTPMOD32 b 0x0 +# GD32-REL-NEXT: 0x207C R_RISCV_TLS_DTPREL32 b 0x0 +# GD32-REL-NEXT: } + +## &DTPMOD(a) - . = 0x2070 - 0x1000 = 4096*1+112 +# GD32: 1000: auipc a0, 1 +# GD32-NEXT: addi a0, a0, 112 +# GD32-NEXT: auipc ra, 0 +# GD32-NEXT: jalr ra, ra, 56 + +## &DTPMOD(b) - . = 0x2078 - 0x1010 = 4096*1+104 +# GD32: 1010: auipc a0, 1 +# GD32-NEXT: addi a0, a0, 104 +# GD32-NEXT: auipc ra, 0 +# GD32-NEXT: jalr ra, ra, 40 + +# GD64-REL: .rela.dyn { +# GD64-REL-NEXT: 0x20E0 R_RISCV_TLS_DTPMOD64 a 0x0 +# GD64-REL-NEXT: 0x20E8 R_RISCV_TLS_DTPREL64 a 0x0 +# GD64-REL-NEXT: 0x20F0 R_RISCV_TLS_DTPMOD64 b 0x0 +# GD64-REL-NEXT: 0x20F8 R_RISCV_TLS_DTPREL64 b 0x0 +# GD64-REL-NEXT: } + +## &DTPMOD(a) - . = 0x20e0 - 0x1010 = 4096*1+224 +# GD64: 1000: auipc a0, 1 +# GD64-NEXT: addi a0, a0, 224 +# GD64-NEXT: auipc ra, 0 +# GD64-NEXT: jalr ra, ra, 56 + +## &DTPMOD(b) - . = 0x20f0 - 0x1010 = 4096*1+224 +# GD64: 1010: auipc a0, 1 +# GD64-NEXT: addi a0, a0, 224 +# GD64-NEXT: auipc ra, 0 +# GD64-NEXT: jalr ra, ra, 40 + +# NOREL: no relocations + +## .got contains pre-populated values: [a@dtpmod, a@dtprel, b@dtpmod, b@dtprel] +# LE32-GOT: section '.got': +# LE32-GOT-NEXT: 0x{{[0-9a-f]+}} 01000000 08f8ffff 01000000 0cf8ffff +# LE64-GOT: section '.got': +# LE64-GOT-NEXT: 0x{{[0-9a-f]+}} 01000000 00000000 08f8ffff ffffffff +# LE64-GOT-NEXT: 0x{{[0-9a-f]+}} 01000000 00000000 0cf8ffff ffffffff + +## b is external +# IE32-REL: .rela.dyn { +# IE32-REL-NEXT: 0x1206C R_RISCV_TLS_DTPREL32 b 0x0 +# IE32-REL-NEXT: } +# IE32-GOT: section '.got': +# IE32-GOT-NEXT: 0x00012060 01000000 08f8ffff 01000000 00000000 + +# IE64-REL: .rela.dyn { +# IE64-REL-NEXT: 0x120D8 R_RISCV_TLS_DTPREL64 b 0x0 +# IE64-REL-NEXT: } +# IE64-GOT: section '.got': +# IE64-GOT-NEXT: 0x000120c0 01000000 00000000 08f8ffff ffffffff +# IE64-GOT-NEXT: 0x000120d0 01000000 00000000 00000000 00000000 + +la.tls.gd a0,a +call __tls_get_addr@plt + +la.tls.gd a0,b +call __tls_get_addr@plt + +.section .tbss +.globl a +.zero 8 +a: +.zero 4 Index: test/ELF/riscv32-reloc-32-pic.s =================================================================== --- /dev/null +++ test/ELF/riscv32-reloc-32-pic.s @@ -0,0 +1,23 @@ +# REQUIRES: riscv +# RUN: llvm-mc -filetype=obj -triple=riscv32 %s -o %t.o +# RUN: ld.lld -shared %t.o -o %t.so +# RUN: llvm-nm %t.so | FileCheck --check-prefix=NM %s +# RUN: llvm-readobj -r %t.so | FileCheck --check-prefix=RELOC %s + +## R_RISCV_32 is an absolute relocation type. +## In PIC mode, it creates a relative relocation if the symbol is non-preemptable. + +# NM: 00002004 d b + +# RELOC: .rela.dyn { +# RELOC-NEXT: 0x2004 R_RISCV_RELATIVE - 0x2004 +# RELOC-NEXT: 0x2000 R_RISCV_32 a 0 +# RELOC-NEXT: } + +.globl a, b +.hidden b + +.data +.long a +b: +.long b Index: test/ELF/riscv64-reloc-64-pic.s =================================================================== --- /dev/null +++ test/ELF/riscv64-reloc-64-pic.s @@ -0,0 +1,23 @@ +# REQUIRES: riscv +# RUN: llvm-mc -filetype=obj -triple=riscv64 %s -o %t.o +# RUN: ld.lld -shared %t.o -o %t.so +# RUN: llvm-nm %t.so | FileCheck --check-prefix=NM %s +# RUN: llvm-readobj -r %t.so | FileCheck --check-prefix=RELOC %s + +## R_RISCV_64 is an absolute relocation type. +## In PIC mode, it creates a relative relocation if the symbol is non-preemptable. + +# NM: 0000000000002008 d b + +# RELOC: .rela.dyn { +# RELOC-NEXT: 0x2008 R_RISCV_RELATIVE - 0x2008 +# RELOC-NEXT: 0x2000 R_RISCV_64 a 0 +# RELOC-NEXT: } + +.globl a, b +.hidden b + +.data +.quad a +b: +.quad b