Skip to content

Commit f42b43e

Browse files
committed
[lld][RISCV] Implement GP relaxation for R_RISCV_HI20/R_RISCV_LO12_I/R_RISCV_LO12_S.
https://reviews.llvm.org/D143673
1 parent b177f06 commit f42b43e

File tree

10 files changed

+177
-4
lines changed

10 files changed

+177
-4
lines changed

lld/ELF/Arch/RISCV.cpp

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ class RISCV final : public TargetInfo {
4848

4949
} // end anonymous namespace
5050

51+
// These are internal relocation numbers for GP relaxation. They aren't part
52+
// of the psABI spec.
53+
#define INTERNAL_R_RISCV_GPREL_I 256
54+
#define INTERNAL_R_RISCV_GPREL_S 257
55+
5156
const uint64_t dtpOffset = 0x800;
5257

5358
enum Op {
@@ -62,6 +67,7 @@ enum Op {
6267

6368
enum Reg {
6469
X_RA = 1,
70+
X_GP = 3,
6571
X_TP = 4,
6672
X_T0 = 5,
6773
X_T1 = 6,
@@ -435,6 +441,20 @@ void RISCV::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
435441
return;
436442
}
437443

444+
case INTERNAL_R_RISCV_GPREL_I:
445+
case INTERNAL_R_RISCV_GPREL_S: {
446+
Defined *gp = ElfSym::riscvGlobalPointer;
447+
int64_t displace = SignExtend64(val - gp->getVA(), bits);
448+
checkInt(loc, displace, 12, rel);
449+
uint32_t insn = (read32le(loc) & ~(31 << 15)) | (X_GP << 15);
450+
if (rel.type == INTERNAL_R_RISCV_GPREL_I)
451+
insn = setLO12_I(insn, displace);
452+
else
453+
insn = setLO12_S(insn, displace);
454+
write32le(loc, insn);
455+
return;
456+
}
457+
438458
case R_RISCV_ADD8:
439459
*loc += val;
440460
return;
@@ -612,6 +632,30 @@ static void relaxTlsLe(const InputSection &sec, size_t i, uint64_t loc,
612632
}
613633
}
614634

635+
static void relaxHi20Lo12(const InputSection &sec, size_t i, uint64_t loc,
636+
Relocation &r, uint32_t &remove) {
637+
const Defined *gp = ElfSym::riscvGlobalPointer;
638+
if (!gp)
639+
return;
640+
641+
if (!isInt<12>(r.sym->getVA(r.addend) - gp->getVA()))
642+
return;
643+
644+
switch (r.type) {
645+
case R_RISCV_HI20:
646+
// Remove lui rd, %hi20(x).
647+
sec.relaxAux->relocTypes[i] = R_RISCV_RELAX;
648+
remove = 4;
649+
break;
650+
case R_RISCV_LO12_I:
651+
sec.relaxAux->relocTypes[i] = INTERNAL_R_RISCV_GPREL_I;
652+
break;
653+
case R_RISCV_LO12_S:
654+
sec.relaxAux->relocTypes[i] = INTERNAL_R_RISCV_GPREL_S;
655+
break;
656+
}
657+
}
658+
615659
static bool relax(InputSection &sec) {
616660
const uint64_t secAddr = sec.getVA();
617661
auto &aux = *sec.relaxAux;
@@ -663,6 +707,13 @@ static bool relax(InputSection &sec) {
663707
sec.relocs()[i + 1].type == R_RISCV_RELAX)
664708
relaxTlsLe(sec, i, loc, r, remove);
665709
break;
710+
case R_RISCV_HI20:
711+
case R_RISCV_LO12_I:
712+
case R_RISCV_LO12_S:
713+
if (i + 1 != sec.relocs().size() &&
714+
sec.relocs()[i + 1].type == R_RISCV_RELAX)
715+
relaxHi20Lo12(sec, i, loc, r, remove);
716+
break;
666717
}
667718

668719
// For all anchors whose offsets are <= r.offset, they are preceded by
@@ -776,6 +827,9 @@ void elf::riscvFinalizeRelax(int passes) {
776827
}
777828
} else if (RelType newType = aux.relocTypes[i]) {
778829
switch (newType) {
830+
case INTERNAL_R_RISCV_GPREL_I:
831+
case INTERNAL_R_RISCV_GPREL_S:
832+
break;
779833
case R_RISCV_RELAX:
780834
// Used by relaxTlsLe to indicate the relocation is ignored.
781835
break;

lld/ELF/Config.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ struct Config {
245245
bool printGcSections;
246246
bool printIcfSections;
247247
bool relax;
248+
bool relaxGP;
248249
bool relocatable;
249250
bool relrGlibc = false;
250251
bool relrPackDynRelocs = false;

lld/ELF/Driver.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,9 @@ static void checkOptions() {
352352
if (config->pcRelOptimize && config->emachine != EM_PPC64)
353353
error("--pcrel-optimize is only supported on PowerPC64 targets");
354354

355+
if (config->relaxGP && config->emachine != EM_RISCV)
356+
error("--relax-gp is only supported on RISC-V targets");
357+
355358
if (config->pie && config->shared)
356359
error("-shared and -pie may not be used together");
357360

@@ -1189,6 +1192,7 @@ static void readConfigs(opt::InputArgList &args) {
11891192
config->printSymbolOrder =
11901193
args.getLastArgValue(OPT_print_symbol_order);
11911194
config->relax = args.hasFlag(OPT_relax, OPT_no_relax, true);
1195+
config->relaxGP = args.hasFlag(OPT_relax_gp, OPT_no_relax_gp, false);
11921196
config->rpath = getRpath(args);
11931197
config->relocatable = args.hasArg(OPT_relocatable);
11941198

lld/ELF/Options.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,10 @@ defm relax: BB<"relax",
355355
"Enable target-specific relaxations if supported (default)",
356356
"Disable target-specific relaxations">;
357357

358+
defm relax_gp: BB<"relax-gp",
359+
"Enable global pointer relaxation",
360+
"Disable global pointer relaxation (default)">;
361+
358362
defm reproduce:
359363
EEq<"reproduce",
360364
"Write tar file containing inputs and command to reproduce link">;

lld/ELF/Symbols.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ Defined *ElfSym::globalOffsetTable;
7171
Defined *ElfSym::mipsGp;
7272
Defined *ElfSym::mipsGpDisp;
7373
Defined *ElfSym::mipsLocalGp;
74+
Defined *ElfSym::riscvGlobalPointer;
7475
Defined *ElfSym::relaIpltStart;
7576
Defined *ElfSym::relaIpltEnd;
7677
Defined *ElfSym::tlsModuleBase;

lld/ELF/Symbols.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,9 @@ struct ElfSym {
512512
static Defined *mipsGpDisp;
513513
static Defined *mipsLocalGp;
514514

515+
// __global_pointer$ for RISC-V.
516+
static Defined *riscvGlobalPointer;
517+
515518
// __rel{,a}_iplt_{start,end} symbols.
516519
static Defined *relaIpltStart;
517520
static Defined *relaIpltEnd;

lld/ELF/Writer.cpp

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1856,10 +1856,20 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
18561856
// should only be defined in an executable. If .sdata does not exist, its
18571857
// value/section does not matter but it has to be relative, so set its
18581858
// st_shndx arbitrarily to 1 (Out::elfHeader).
1859-
if (config->emachine == EM_RISCV && !config->shared) {
1860-
OutputSection *sec = findSection(".sdata");
1861-
addOptionalRegular("__global_pointer$", sec ? sec : Out::elfHeader, 0x800,
1862-
STV_DEFAULT);
1859+
if (config->emachine == EM_RISCV) {
1860+
ElfSym::riscvGlobalPointer = nullptr;
1861+
if (!config->shared) {
1862+
OutputSection *sec = findSection(".sdata");
1863+
addOptionalRegular(
1864+
"__global_pointer$", sec ? sec : Out::elfHeader, 0x800, STV_DEFAULT);
1865+
// Set riscvGlobalPointer to be used by the optional global pointer
1866+
// relaxation.
1867+
if (config->relaxGP) {
1868+
Symbol *s = symtab.find("__global_pointer$");
1869+
if (s && s->isDefined())
1870+
ElfSym::riscvGlobalPointer = cast<Defined>(s);
1871+
}
1872+
}
18631873
}
18641874

18651875
if (config->emachine == EM_386 || config->emachine == EM_X86_64) {

lld/docs/ld.lld.1

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,8 @@ and
493493
.It Fl -pop-state
494494
Restore the states saved by
495495
.Fl -push-state.
496+
.It Fl --relax-gp
497+
Enable global pointer relaxation for RISC-V.
496498
.It Fl -relocatable , Fl r
497499
Create relocatable object file.
498500
.It Fl -reproduce Ns = Ns Ar path
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# REQUIRES: riscv
2+
# RUN: rm -rf %t && split-file %s %t && cd %t
3+
4+
# RUN: llvm-mc -filetype=obj -triple=riscv32-unknown-elf -mattr=+relax a.s -o rv32.o
5+
# RUN: llvm-mc -filetype=obj -triple=riscv64-unknown-elf -mattr=+relax a.s -o rv64.o
6+
# RUN: llvm-mc -filetype=obj -triple=riscv64-unknown-elf -mattr=+relax a.s -o rv64-pie.o
7+
8+
# RUN: ld.lld --relax-gp --undefined=__global_pointer$ rv32.o lds -pie -o rv32
9+
# RUN: ld.lld --relax-gp --undefined=__global_pointer$ rv64.o lds -shared -o rv64
10+
# RUN: llvm-objdump -td -M no-aliases --no-show-raw-insn rv32 | FileCheck %s
11+
# RUN: llvm-objdump -td -M no-aliases --no-show-raw-insn rv64 | FileCheck %s
12+
13+
# CHECK: lui a0, 512
14+
# CHECK-NEXT: addi a0, a0, 1
15+
# CHECK-NEXT: lw a0, 1(a0)
16+
# CHECK-NEXT: sw a0, 1(a0)
17+
18+
#--- a.s
19+
.globl abs
20+
abs = 0x200001
21+
22+
.global _start
23+
_start:
24+
lui a0, %hi(abs)
25+
addi a0, a0, %lo(abs)
26+
lw a0, %lo(abs)(a0)
27+
sw a0, %lo(abs)(a0)
28+
29+
#--- lds
30+
SECTIONS {
31+
.text : {*(.text) }
32+
.sdata 0x200000 : {}
33+
}

lld/test/ELF/riscv-relax-hi20-lo12.s

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# REQUIRES: riscv
2+
# RUN: rm -rf %t && split-file %s %t && cd %t
3+
4+
# RUN: llvm-mc -filetype=obj -triple=riscv32-unknown-elf -mattr=+relax a.s -o rv32.o
5+
# RUN: llvm-mc -filetype=obj -triple=riscv64-unknown-elf -mattr=+relax a.s -o rv64.o
6+
7+
# RUN: ld.lld --relax-gp --undefined=__global_pointer$ rv32.o lds -o rv32
8+
# RUN: ld.lld --relax-gp --undefined=__global_pointer$ rv64.o lds -o rv64
9+
# RUN: llvm-objdump -td -M no-aliases --no-show-raw-insn rv32 | FileCheck %s
10+
# RUN: llvm-objdump -td -M no-aliases --no-show-raw-insn rv64 | FileCheck %s
11+
12+
# CHECK: 00000028 l .text {{0*}}0 a
13+
14+
# CHECK-NOT: lui
15+
# CHECK: addi a0, gp, -2048
16+
# CHECK-NEXT: lw a0, -2048(gp)
17+
# CHECK-NEXT: sw a0, -2048(gp)
18+
# CHECK-NOT: lui
19+
# CHECK-NEXT: addi a0, gp, 2047
20+
# CHECK-NEXT: lb a0, 2047(gp)
21+
# CHECK-NEXT: sb a0, 2047(gp)
22+
# CHECK-NEXT: lui a0, 513
23+
# CHECK-NEXT: addi a0, a0, 0
24+
# CHECK-NEXT: lw a0, 0(a0)
25+
# CHECK-NEXT: sw a0, 0(a0)
26+
# CHECK-EMPTY:
27+
# CHECK-NEXT: <a>:
28+
# CHECK-NEXT: addi a0, a0, 1
29+
30+
#--- a.s
31+
.global _start
32+
_start:
33+
lui a0, %hi(foo)
34+
addi a0, a0, %lo(foo)
35+
lw a0, %lo(foo)(a0)
36+
sw a0, %lo(foo)(a0)
37+
lui a0, %hi(bar)
38+
addi a0, a0, %lo(bar)
39+
lb a0, %lo(bar)(a0)
40+
sb a0, %lo(bar)(a0)
41+
lui a0, %hi(norelax)
42+
addi a0, a0, %lo(norelax)
43+
lw a0, %lo(norelax)(a0)
44+
sw a0, %lo(norelax)(a0)
45+
a:
46+
addi a0, a0, 1
47+
48+
.section .sdata,"aw"
49+
foo:
50+
.word 0
51+
.space 4091
52+
bar:
53+
.byte 0
54+
norelax:
55+
.word 0
56+
57+
#--- lds
58+
SECTIONS {
59+
.text : {*(.text) }
60+
.sdata 0x200000 : { }
61+
}

0 commit comments

Comments
 (0)