} // end anonymous namespace
+// These are internal relocation numbers for GP relaxation. They aren't part
+// of the psABI spec.
+#define INTERNAL_R_RISCV_GPREL_I 256
+#define INTERNAL_R_RISCV_GPREL_S 257
+
const uint64_t dtpOffset = 0x800;
enum Op {
enum Reg {
X_RA = 1,
+ X_GP = 3,
X_TP = 4,
X_T0 = 5,
X_T1 = 6,
return;
}
+ case INTERNAL_R_RISCV_GPREL_I:
+ case INTERNAL_R_RISCV_GPREL_S: {
+ Defined *gp = ElfSym::riscvGlobalPointer;
+ int64_t displace = SignExtend64(val - gp->getVA(), bits);
+ checkInt(loc, displace, 12, rel);
+ uint32_t insn = (read32le(loc) & ~(31 << 15)) | (X_GP << 15);
+ if (rel.type == INTERNAL_R_RISCV_GPREL_I)
+ insn = setLO12_I(insn, displace);
+ else
+ insn = setLO12_S(insn, displace);
+ write32le(loc, insn);
+ return;
+ }
+
case R_RISCV_ADD8:
*loc += val;
return;
}
}
+static void relaxHi20Lo12(const InputSection &sec, size_t i, uint64_t loc,
+ Relocation &r, uint32_t &remove) {
+ const Defined *gp = ElfSym::riscvGlobalPointer;
+ if (!gp)
+ return;
+
+ if (!isInt<12>(r.sym->getVA(r.addend) - gp->getVA()))
+ return;
+
+ switch (r.type) {
+ case R_RISCV_HI20:
+ // Remove lui rd, %hi20(x).
+ sec.relaxAux->relocTypes[i] = R_RISCV_RELAX;
+ remove = 4;
+ break;
+ case R_RISCV_LO12_I:
+ sec.relaxAux->relocTypes[i] = INTERNAL_R_RISCV_GPREL_I;
+ break;
+ case R_RISCV_LO12_S:
+ sec.relaxAux->relocTypes[i] = INTERNAL_R_RISCV_GPREL_S;
+ break;
+ }
+}
+
static bool relax(InputSection &sec) {
const uint64_t secAddr = sec.getVA();
auto &aux = *sec.relaxAux;
sec.relocs()[i + 1].type == R_RISCV_RELAX)
relaxTlsLe(sec, i, loc, r, remove);
break;
+ case R_RISCV_HI20:
+ case R_RISCV_LO12_I:
+ case R_RISCV_LO12_S:
+ if (i + 1 != sec.relocs().size() &&
+ sec.relocs()[i + 1].type == R_RISCV_RELAX)
+ relaxHi20Lo12(sec, i, loc, r, remove);
+ break;
}
// For all anchors whose offsets are <= r.offset, they are preceded by
}
} else if (RelType newType = aux.relocTypes[i]) {
switch (newType) {
+ case INTERNAL_R_RISCV_GPREL_I:
+ case INTERNAL_R_RISCV_GPREL_S:
+ break;
case R_RISCV_RELAX:
// Used by relaxTlsLe to indicate the relocation is ignored.
break;
bool printGcSections;
bool printIcfSections;
bool relax;
+ bool relaxGP;
bool relocatable;
bool relrGlibc = false;
bool relrPackDynRelocs = false;
if (config->pcRelOptimize && config->emachine != EM_PPC64)
error("--pcrel-optimize is only supported on PowerPC64 targets");
+ if (config->relaxGP && config->emachine != EM_RISCV)
+ error("--relax-gp is only supported on RISC-V targets");
+
if (config->pie && config->shared)
error("-shared and -pie may not be used together");
config->printSymbolOrder =
args.getLastArgValue(OPT_print_symbol_order);
config->relax = args.hasFlag(OPT_relax, OPT_no_relax, true);
+ config->relaxGP = args.hasFlag(OPT_relax_gp, OPT_no_relax_gp, false);
config->rpath = getRpath(args);
config->relocatable = args.hasArg(OPT_relocatable);
"Enable target-specific relaxations if supported (default)",
"Disable target-specific relaxations">;
+defm relax_gp: BB<"relax-gp",
+ "Enable global pointer relaxation",
+ "Disable global pointer relaxation (default)">;
+
defm reproduce:
EEq<"reproduce",
"Write tar file containing inputs and command to reproduce link">;
Defined *ElfSym::mipsGp;
Defined *ElfSym::mipsGpDisp;
Defined *ElfSym::mipsLocalGp;
+Defined *ElfSym::riscvGlobalPointer;
Defined *ElfSym::relaIpltStart;
Defined *ElfSym::relaIpltEnd;
Defined *ElfSym::tlsModuleBase;
static Defined *mipsGpDisp;
static Defined *mipsLocalGp;
+ // __global_pointer$ for RISC-V.
+ static Defined *riscvGlobalPointer;
+
// __rel{,a}_iplt_{start,end} symbols.
static Defined *relaIpltStart;
static Defined *relaIpltEnd;
// should only be defined in an executable. If .sdata does not exist, its
// value/section does not matter but it has to be relative, so set its
// st_shndx arbitrarily to 1 (Out::elfHeader).
- if (config->emachine == EM_RISCV && !config->shared) {
- OutputSection *sec = findSection(".sdata");
- addOptionalRegular("__global_pointer$", sec ? sec : Out::elfHeader, 0x800,
- STV_DEFAULT);
+ if (config->emachine == EM_RISCV) {
+ ElfSym::riscvGlobalPointer = nullptr;
+ if (!config->shared) {
+ OutputSection *sec = findSection(".sdata");
+ addOptionalRegular(
+ "__global_pointer$", sec ? sec : Out::elfHeader, 0x800, STV_DEFAULT);
+ // Set riscvGlobalPointer to be used by the optional global pointer
+ // relaxation.
+ if (config->relaxGP) {
+ Symbol *s = symtab.find("__global_pointer$");
+ if (s && s->isDefined())
+ ElfSym::riscvGlobalPointer = cast<Defined>(s);
+ }
+ }
}
if (config->emachine == EM_386 || config->emachine == EM_X86_64) {
.It Fl -pop-state
Restore the states saved by
.Fl -push-state.
+.It Fl --relax-gp
+Enable global pointer relaxation for RISC-V.
.It Fl -relocatable , Fl r
Create relocatable object file.
.It Fl -reproduce Ns = Ns Ar path
--- /dev/null
+# REQUIRES: riscv
+# RUN: rm -rf %t && split-file %s %t && cd %t
+
+# RUN: llvm-mc -filetype=obj -triple=riscv32-unknown-elf -mattr=+relax a.s -o rv32.o
+# RUN: llvm-mc -filetype=obj -triple=riscv64-unknown-elf -mattr=+relax a.s -o rv64.o
+# RUN: llvm-mc -filetype=obj -triple=riscv64-unknown-elf -mattr=+relax a.s -o rv64-pie.o
+
+# RUN: ld.lld --relax-gp --undefined=__global_pointer$ rv32.o lds -pie -o rv32
+# RUN: ld.lld --relax-gp --undefined=__global_pointer$ rv64.o lds -shared -o rv64
+# RUN: llvm-objdump -td -M no-aliases --no-show-raw-insn rv32 | FileCheck %s
+# RUN: llvm-objdump -td -M no-aliases --no-show-raw-insn rv64 | FileCheck %s
+
+# CHECK: lui a0, 512
+# CHECK-NEXT: addi a0, a0, 1
+# CHECK-NEXT: lw a0, 1(a0)
+# CHECK-NEXT: sw a0, 1(a0)
+
+#--- a.s
+.globl abs
+abs = 0x200001
+
+.global _start
+_start:
+ lui a0, %hi(abs)
+ addi a0, a0, %lo(abs)
+ lw a0, %lo(abs)(a0)
+ sw a0, %lo(abs)(a0)
+
+#--- lds
+SECTIONS {
+ .text : {*(.text) }
+ .sdata 0x200000 : {}
+}
--- /dev/null
+# REQUIRES: riscv
+# RUN: rm -rf %t && split-file %s %t && cd %t
+
+# RUN: llvm-mc -filetype=obj -triple=riscv32-unknown-elf -mattr=+relax a.s -o rv32.o
+# RUN: llvm-mc -filetype=obj -triple=riscv64-unknown-elf -mattr=+relax a.s -o rv64.o
+
+# RUN: ld.lld --relax-gp --undefined=__global_pointer$ rv32.o lds -o rv32
+# RUN: ld.lld --relax-gp --undefined=__global_pointer$ rv64.o lds -o rv64
+# RUN: llvm-objdump -td -M no-aliases --no-show-raw-insn rv32 | FileCheck %s
+# RUN: llvm-objdump -td -M no-aliases --no-show-raw-insn rv64 | FileCheck %s
+
+# CHECK: 00000028 l .text {{0*}}0 a
+
+# CHECK-NOT: lui
+# CHECK: addi a0, gp, -2048
+# CHECK-NEXT: lw a0, -2048(gp)
+# CHECK-NEXT: sw a0, -2048(gp)
+# CHECK-NOT: lui
+# CHECK-NEXT: addi a0, gp, 2047
+# CHECK-NEXT: lb a0, 2047(gp)
+# CHECK-NEXT: sb a0, 2047(gp)
+# CHECK-NEXT: lui a0, 513
+# CHECK-NEXT: addi a0, a0, 0
+# CHECK-NEXT: lw a0, 0(a0)
+# CHECK-NEXT: sw a0, 0(a0)
+# CHECK-EMPTY:
+# CHECK-NEXT: <a>:
+# CHECK-NEXT: addi a0, a0, 1
+
+#--- a.s
+.global _start
+_start:
+ lui a0, %hi(foo)
+ addi a0, a0, %lo(foo)
+ lw a0, %lo(foo)(a0)
+ sw a0, %lo(foo)(a0)
+ lui a0, %hi(bar)
+ addi a0, a0, %lo(bar)
+ lb a0, %lo(bar)(a0)
+ sb a0, %lo(bar)(a0)
+ lui a0, %hi(norelax)
+ addi a0, a0, %lo(norelax)
+ lw a0, %lo(norelax)(a0)
+ sw a0, %lo(norelax)(a0)
+a:
+ addi a0, a0, 1
+
+.section .sdata,"aw"
+foo:
+ .word 0
+ .space 4091
+bar:
+ .byte 0
+norelax:
+ .word 0
+
+#--- lds
+SECTIONS {
+ .text : {*(.text) }
+ .sdata 0x200000 : { }
+}