Skip to content

Commit 2e46e90

Browse files
committed
Add RISC-V ePIC implementation
1 parent f42b43e commit 2e46e90

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+698
-74
lines changed

clang/include/clang/Basic/DiagnosticDriverKinds.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -503,7 +503,7 @@ def warn_slash_u_filename : Warning<"'/U%0' treated as the '/U' option">,
503503
def note_use_dashdash : Note<
504504
"use '--' to treat subsequent arguments as filenames">;
505505

506-
def err_drv_ropi_rwpi_incompatible_with_pic : Error<
506+
def err_drv_epic_ropi_rwpi_incompatible_with_pic : Error<
507507
"embedded and GOT-based position independence are incompatible">;
508508
def err_drv_ropi_incompatible_with_cxx : Error<
509509
"ROPI is not compatible with c++">;

clang/include/clang/Basic/LangOptions.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ LANGOPT(EnableAIXExtendedAltivecABI , 1, 0, "__EXTABI__ predefined macro")
201201
LANGOPT(EnableAIXQuadwordAtomicsABI , 1, 0, "Use 16-byte atomic lock free semantics")
202202
COMPATIBLE_VALUE_LANGOPT(PICLevel , 2, 0, "__PIC__ level")
203203
COMPATIBLE_VALUE_LANGOPT(PIE , 1, 0, "is pie")
204+
LANGOPT(EPIC , 1, 0, "Position independence for embedded systems")
204205
LANGOPT(ROPI , 1, 0, "Read-only position independence")
205206
LANGOPT(RWPI , 1, 0, "Read-write position independence")
206207
COMPATIBLE_LANGOPT(GNUInline , 1, 0, "GNU inline semantics")

clang/include/clang/Driver/Options.td

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2746,6 +2746,10 @@ defm plt : BoolFOption<"plt",
27462746
CodeGenOpts<"NoPLT">, DefaultFalse,
27472747
NegFlag<SetTrue, [CC1Option], "Use GOT indirection instead of PLT to make external function calls (x86 only)">,
27482748
PosFlag<SetFalse>>;
2749+
defm epic : BoolFOption<"epic",
2750+
LangOpts<"EPIC">, DefaultFalse,
2751+
PosFlag<SetTrue, [CC1Option], "Generate position independent code for embedded systems (RISC-V only)">,
2752+
NegFlag<SetFalse>>;
27492753
defm ropi : BoolFOption<"ropi",
27502754
LangOpts<"ROPI">, DefaultFalse,
27512755
PosFlag<SetTrue, [CC1Option], "Generate read-only position independent code (ARM only)">,
@@ -5376,9 +5380,9 @@ def migrator_no_finalize_removal : Flag<["-"], "no-finalize-removal">,
53765380
let Flags = [CC1Option, CC1AsOption, FC1Option, NoDriverOption] in {
53775381

53785382
def mrelocation_model : Separate<["-"], "mrelocation-model">,
5379-
HelpText<"The relocation model to use">, Values<"static,pic,ropi,rwpi,ropi-rwpi,dynamic-no-pic">,
5383+
HelpText<"The relocation model to use">, Values<"static,pic,epic,ropi,rwpi,ropi-rwpi,dynamic-no-pic">,
53805384
NormalizedValuesScope<"llvm::Reloc">,
5381-
NormalizedValues<["Static", "PIC_", "ROPI", "RWPI", "ROPI_RWPI", "DynamicNoPIC"]>,
5385+
NormalizedValues<["Static", "PIC_", "EPIC", "ROPI", "RWPI", "ROPI_RWPI", "DynamicNoPIC"]>,
53825386
MarshallingInfoEnum<CodeGenOpts<"RelocationModel">, "PIC_">;
53835387

53845388
} // let Flags = [CC1Option, CC1AsOption, FC1Option, NoDriverOption]

clang/lib/Driver/ToolChains/CommonArgs.cpp

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1341,6 +1341,8 @@ const char *tools::RelocationModelName(llvm::Reloc::Model Model) {
13411341
return "pic";
13421342
case llvm::Reloc::DynamicNoPIC:
13431343
return "dynamic-no-pic";
1344+
case llvm::Reloc::EPIC:
1345+
return "epic";
13441346
case llvm::Reloc::ROPI:
13451347
return "ropi";
13461348
case llvm::Reloc::RWPI:
@@ -1498,38 +1500,48 @@ tools::ParsePICArgs(const ToolChain &ToolChain, const ArgList &Args) {
14981500
return std::make_tuple(llvm::Reloc::DynamicNoPIC, PIC ? 2U : 0U, false);
14991501
}
15001502

1501-
bool EmbeddedPISupported;
1503+
bool EPIC = false;
1504+
Arg* LastEPICArg = Args.getLastArg(options::OPT_fepic, options::OPT_fno_epic);
1505+
if (LastEPICArg && LastEPICArg->getOption().matches(options::OPT_fepic)) {
1506+
auto Arch = Triple.getArch();
1507+
if (Arch != llvm::Triple::riscv32 && Arch != llvm::Triple::riscv64)
1508+
ToolChain.getDriver().Diag(diag::err_drv_unsupported_opt_for_target)
1509+
<< LastEPICArg->getSpelling() << Triple.str();
1510+
EPIC = true;
1511+
}
1512+
1513+
bool RORWPISupported;
15021514
switch (Triple.getArch()) {
15031515
case llvm::Triple::arm:
15041516
case llvm::Triple::armeb:
15051517
case llvm::Triple::thumb:
15061518
case llvm::Triple::thumbeb:
1507-
EmbeddedPISupported = true;
1519+
RORWPISupported = true;
15081520
break;
15091521
default:
1510-
EmbeddedPISupported = false;
1522+
RORWPISupported = false;
15111523
break;
15121524
}
15131525

15141526
bool ROPI = false, RWPI = false;
15151527
Arg* LastROPIArg = Args.getLastArg(options::OPT_fropi, options::OPT_fno_ropi);
15161528
if (LastROPIArg && LastROPIArg->getOption().matches(options::OPT_fropi)) {
1517-
if (!EmbeddedPISupported)
1529+
if (!RORWPISupported)
15181530
ToolChain.getDriver().Diag(diag::err_drv_unsupported_opt_for_target)
15191531
<< LastROPIArg->getSpelling() << Triple.str();
15201532
ROPI = true;
15211533
}
15221534
Arg *LastRWPIArg = Args.getLastArg(options::OPT_frwpi, options::OPT_fno_rwpi);
15231535
if (LastRWPIArg && LastRWPIArg->getOption().matches(options::OPT_frwpi)) {
1524-
if (!EmbeddedPISupported)
1536+
if (!RORWPISupported)
15251537
ToolChain.getDriver().Diag(diag::err_drv_unsupported_opt_for_target)
15261538
<< LastRWPIArg->getSpelling() << Triple.str();
15271539
RWPI = true;
15281540
}
15291541

15301542
// ROPI and RWPI are not compatible with PIC or PIE.
15311543
if ((ROPI || RWPI) && (PIC || PIE))
1532-
ToolChain.getDriver().Diag(diag::err_drv_ropi_rwpi_incompatible_with_pic);
1544+
ToolChain.getDriver().Diag(diag::err_drv_epic_ropi_rwpi_incompatible_with_pic);
15331545

15341546
if (Triple.isMIPS()) {
15351547
StringRef CPUName;
@@ -1552,7 +1564,9 @@ tools::ParsePICArgs(const ToolChain &ToolChain, const ArgList &Args) {
15521564
return std::make_tuple(llvm::Reloc::PIC_, IsPICLevelTwo ? 2U : 1U, PIE);
15531565

15541566
llvm::Reloc::Model RelocM = llvm::Reloc::Static;
1555-
if (ROPI && RWPI)
1567+
if (EPIC)
1568+
RelocM = llvm::Reloc::EPIC;
1569+
else if (ROPI && RWPI)
15561570
RelocM = llvm::Reloc::ROPI_RWPI;
15571571
else if (ROPI)
15581572
RelocM = llvm::Reloc::ROPI;

clang/tools/driver/cc1as_main.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -436,20 +436,27 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
436436
&MCOptions);
437437

438438
bool PIC = false;
439+
bool EPIC = false;
439440
if (Opts.RelocationModel == "static") {
440441
PIC = false;
441442
} else if (Opts.RelocationModel == "pic") {
442443
PIC = true;
444+
} else if (Opts.RelocationModel == "epic") {
445+
EPIC = true;
443446
} else {
444-
assert(Opts.RelocationModel == "dynamic-no-pic" &&
447+
assert((Opts.RelocationModel == "epic" ||
448+
Opts.RelocationModel == "ropi" ||
449+
Opts.RelocationModel == "rwpi" ||
450+
Opts.RelocationModel == "ropi-rwpi" ||
451+
Opts.RelocationModel == "dynamic-no-pic") &&
445452
"Invalid PIC model!");
446453
PIC = false;
447454
}
448455

449456
// FIXME: This is not pretty. MCContext has a ptr to MCObjectFileInfo and
450457
// MCObjectFileInfo needs a MCContext reference in order to initialize itself.
451458
std::unique_ptr<MCObjectFileInfo> MOFI(
452-
TheTarget->createMCObjectFileInfo(Ctx, PIC));
459+
TheTarget->createMCObjectFileInfo(Ctx, PIC, false, EPIC));
453460
if (Opts.DarwinTargetVariantTriple)
454461
MOFI->setDarwinTargetVariantTriple(*Opts.DarwinTargetVariantTriple);
455462
if (!Opts.DarwinTargetVariantSDKVersion.empty())

lld/ELF/Arch/RISCV.cpp

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,9 @@ class RISCV final : public TargetInfo {
4343
const uint8_t *loc) const override;
4444
void relocate(uint8_t *loc, const Relocation &rel,
4545
uint64_t val) const override;
46+
void relocateAlloc(InputSectionBase &sec, uint8_t *buf) const override;
4647
bool relaxOnce(int pass) const override;
48+
void transformEPICRel(uint8_t *loc, Relocation &rel) const;
4749
};
4850

4951
} // end anonymous namespace
@@ -251,6 +253,13 @@ RelType RISCV::getDynRel(RelType type) const {
251253
: static_cast<RelType>(R_RISCV_NONE);
252254
}
253255

256+
static bool shouldMakePCRel(const Symbol &sym) {
257+
OutputSection *section = sym.getOutputSection();
258+
if (!section)
259+
return false;
260+
return (section->flags & SHF_WRITE) == 0;
261+
}
262+
254263
RelExpr RISCV::getRelExpr(const RelType type, const Symbol &s,
255264
const uint8_t *loc) const {
256265
switch (type) {
@@ -262,6 +271,9 @@ RelExpr RISCV::getRelExpr(const RelType type, const Symbol &s,
262271
case R_RISCV_LO12_I:
263272
case R_RISCV_LO12_S:
264273
case R_RISCV_RVC_LUI:
274+
case R_RISCV_GPREL_HI20:
275+
case R_RISCV_GPREL_LO12_I:
276+
case R_RISCV_GPREL_LO12_S:
265277
return R_ABS;
266278
case R_RISCV_ADD8:
267279
case R_RISCV_ADD16:
@@ -305,6 +317,13 @@ RelExpr RISCV::getRelExpr(const RelType type, const Symbol &s,
305317
case R_RISCV_TPREL_ADD:
306318
case R_RISCV_RELAX:
307319
return config->relax ? R_RELAX_HINT : R_NONE;
320+
case R_RISCV_GPREL_ADD:
321+
return R_NONE;
322+
case R_RISCV_EPIC_HI20:
323+
case R_RISCV_EPIC_LO12_I:
324+
case R_RISCV_EPIC_LO12_S:
325+
case R_RISCV_EPIC_BASE_ADD:
326+
return R_EPIC;
308327
default:
309328
error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) +
310329
") against symbol " + toString(s));
@@ -416,13 +435,15 @@ void RISCV::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
416435
case R_RISCV_TLS_GD_HI20:
417436
case R_RISCV_TLS_GOT_HI20:
418437
case R_RISCV_TPREL_HI20:
438+
case R_RISCV_GPREL_HI20:
419439
case R_RISCV_HI20: {
420440
uint64_t hi = val + 0x800;
421441
checkInt(loc, SignExtend64(hi, bits) >> 12, 20, rel);
422442
write32le(loc, (read32le(loc) & 0xFFF) | (hi & 0xFFFFF000));
423443
return;
424444
}
425445

446+
case R_RISCV_GPREL_LO12_I:
426447
case R_RISCV_PCREL_LO12_I:
427448
case R_RISCV_TPREL_LO12_I:
428449
case R_RISCV_LO12_I: {
@@ -432,6 +453,7 @@ void RISCV::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
432453
return;
433454
}
434455

456+
case R_RISCV_GPREL_LO12_S:
435457
case R_RISCV_PCREL_LO12_S:
436458
case R_RISCV_TPREL_LO12_S:
437459
case R_RISCV_LO12_S: {
@@ -511,6 +533,32 @@ void RISCV::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
511533
}
512534
}
513535

536+
void RISCV::relocateAlloc(InputSectionBase &sec, uint8_t *buf) const {
537+
const unsigned bits = config->is64 ? 64 : 32;
538+
uint64_t secAddr = sec.getOutputSection()->addr;
539+
if (auto *s = dyn_cast<InputSection>(&sec))
540+
secAddr += s->outSecOff;
541+
for (Relocation &rel : sec.relocs()) {
542+
if (rel.expr == R_EPIC) {
543+
uint64_t offset = rel.offset;
544+
uint8_t *bufLoc = buf + offset;
545+
transformEPICRel(bufLoc, rel);
546+
assert(rel.expr != R_EPIC);
547+
}
548+
}
549+
for (const Relocation &rel : sec.relocs()) {
550+
if (rel.expr == R_NONE)
551+
continue;
552+
uint8_t *loc = buf + rel.offset;
553+
const uint64_t val = SignExtend64(
554+
sec.getRelocTargetVA(sec.file, rel.type, rel.addend,
555+
secAddr + rel.offset, *rel.sym, rel.expr),
556+
bits);
557+
if (rel.expr != R_RELAX_HINT)
558+
relocate(loc, rel, val);
559+
}
560+
}
561+
514562
namespace {
515563
struct SymbolAnchor {
516564
uint64_t offset;
@@ -1070,6 +1118,92 @@ void elf::mergeRISCVAttributesSections() {
10701118
mergeAttributesSection(sections));
10711119
}
10721120

1121+
// For R_RISCV_EPIC_LO12_{I,S}, the symbol actually points the corresponding
1122+
// R_RISCV_EPIC_HI20 relocation, and the target VA is calculated using the
1123+
// R_RISCV_EPIC_HI20's symbol.
1124+
//
1125+
// This function returns the R_RISCV_EPIC_HI20 relocation from
1126+
// R_RISCV_EPIC_LO12's symbol and addend.
1127+
static Relocation *getRISCVEPICHi20(const Symbol *sym, uint64_t addend) {
1128+
const Defined *d = cast<Defined>(sym);
1129+
if (!d->section) {
1130+
errorOrWarn("R_RISCV_EPIC_LO12_* relocation points to an absolute symbol: " +
1131+
sym->getName());
1132+
return nullptr;
1133+
}
1134+
InputSection *isec = cast<InputSection>(d->section);
1135+
1136+
if (addend != 0)
1137+
warn("non-zero addend in R_RISCV_EPIC_LO12_* relocation to " +
1138+
isec->getObjMsg(d->value) + " is ignored");
1139+
1140+
// Relocations are sorted by offset, so we can use std::equal_range to do
1141+
// binary search.
1142+
Relocation r;
1143+
r.offset = d->value;
1144+
auto range =
1145+
std::equal_range(isec->relocations.begin(), isec->relocations.end(), r,
1146+
[](const Relocation &lhs, const Relocation &rhs) {
1147+
return lhs.offset < rhs.offset;
1148+
});
1149+
1150+
for (auto it = range.first; it != range.second; ++it)
1151+
// The R_RISCV_EPIC_HI20 relocation may have already been transformed into
1152+
// a R_RISCV_PCREL_HI20 or a R_RISCV_GPREL_HI20 relocation, so we also
1153+
// accept those.
1154+
if (it->type == R_RISCV_PCREL_HI20 || it->type == R_RISCV_GPREL_HI20 ||
1155+
it->type == R_RISCV_EPIC_HI20)
1156+
return &*it;
1157+
1158+
errorOrWarn("R_RISCV_EPIC_LO12_* relocation points to " +
1159+
isec->getObjMsg(d->value) +
1160+
" without an associated R_RISCV_EPIC_HI20_* relocation");
1161+
return nullptr;
1162+
}
1163+
1164+
void RISCV::transformEPICRel(uint8_t *loc, Relocation &rel) const {
1165+
switch (rel.type) {
1166+
case R_RISCV_EPIC_HI20:
1167+
if (shouldMakePCRel(*rel.sym)) {
1168+
*loc = *loc & 0xdf; // Rewrite LUI to AUIPC.
1169+
rel.type = R_RISCV_PCREL_HI20;
1170+
} else {
1171+
rel.type = R_RISCV_GPREL_HI20;
1172+
}
1173+
break;
1174+
case R_RISCV_EPIC_LO12_I: {
1175+
Relocation *hiRel = getRISCVEPICHi20(rel.sym, rel.addend);
1176+
if (shouldMakePCRel(*hiRel->sym))
1177+
rel.type = R_RISCV_PCREL_LO12_I;
1178+
else {
1179+
rel.type = R_RISCV_GPREL_LO12_I;
1180+
rel.sym = hiRel->sym;
1181+
}
1182+
break;
1183+
}
1184+
case R_RISCV_EPIC_LO12_S: {
1185+
Relocation *hiRel = getRISCVEPICHi20(rel.sym, rel.addend);
1186+
if (shouldMakePCRel(*hiRel->sym))
1187+
rel.type = R_RISCV_PCREL_LO12_S;
1188+
else {
1189+
rel.type = R_RISCV_GPREL_LO12_S;
1190+
rel.sym = hiRel->sym;
1191+
}
1192+
break;
1193+
}
1194+
case R_RISCV_EPIC_BASE_ADD:
1195+
if (shouldMakePCRel(*rel.sym)) {
1196+
if ((*loc & 0x7f) != 0b0110011) // not an uncompressed ADD.
1197+
error(getErrorLocation(loc) +
1198+
"R_RISCV_EPIC_BASE_ADD relocation against wrong instruction");
1199+
write32le(loc, itype(ADDI, 0, 0, 0)); // Rewrite ADD to NOP.
1200+
}
1201+
rel.type = R_RISCV_NONE;
1202+
break;
1203+
}
1204+
rel.expr = getRelExpr(rel.type, *rel.sym, loc);
1205+
}
1206+
10731207
TargetInfo *elf::getRISCVTargetInfo() {
10741208
static RISCV target;
10751209
return &target;

lld/ELF/Config.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@ struct Config {
226226
bool ltoEmitAsm;
227227
bool ltoUniqueBasicBlockSectionNames;
228228
bool ltoWholeProgramVisibility;
229+
bool ltoEpic;
229230
bool mergeArmExidx;
230231
bool mipsN32Abi = false;
231232
bool mmapOutputFile;

lld/ELF/Driver.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1150,6 +1150,7 @@ static void readConfigs(opt::InputArgList &args) {
11501150
config->ltoUniqueBasicBlockSectionNames =
11511151
args.hasFlag(OPT_lto_unique_basic_block_section_names,
11521152
OPT_no_lto_unique_basic_block_section_names, false);
1153+
config->ltoEpic = args.hasArg(OPT_lto_epic);
11531154
config->mapFile = args.getLastArgValue(OPT_Map);
11541155
config->mipsGotSize = args::getInteger(args, OPT_mips_got_size, 0xfff0);
11551156
config->mergeArmExidx =

lld/ELF/LTO.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ static lto::Config createConfig() {
118118
c.RelocModel = std::nullopt;
119119
else if (config->isPic)
120120
c.RelocModel = Reloc::PIC_;
121+
else if (config->ltoEpic)
122+
c.RelocModel = Reloc::EPIC;
121123
else
122124
c.RelocModel = Reloc::Static;
123125

lld/ELF/Options.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,10 @@ def lto_sample_profile: JJ<"lto-sample-profile=">,
579579
defm lto_whole_program_visibility: BB<"lto-whole-program-visibility",
580580
"Asserts that the LTO link has whole program visibility",
581581
"Asserts that the LTO link does not have whole program visibility">;
582+
def lto_pseudo_probe_for_profiling: F<"lto-pseudo-probe-for-profiling">,
583+
HelpText<"Emit pseudo probes for sample profiling">;
584+
def lto_epic: FF<"lto-epic">,
585+
HelpText<"Emit code suitable for the ePIC ABI during LTO">;
582586
def disable_verify: F<"disable-verify">;
583587
defm mllvm: Eq<"mllvm", "Additional arguments to forward to LLVM's option processing">;
584588
def opt_remarks_filename: Separate<["--"], "opt-remarks-filename">,

lld/ELF/Relocations.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,6 @@ static bool isRelExpr(RelExpr expr) {
211211
R_RISCV_PC_INDIRECT, R_PPC64_RELAX_GOT_PC>(expr);
212212
}
213213

214-
215214
static RelExpr toPlt(RelExpr expr) {
216215
switch (expr) {
217216
case R_PPC64_CALL:
@@ -946,7 +945,7 @@ bool RelocationScanner::isStaticLinkTimeConstant(RelExpr e, RelType type,
946945
R_MIPS_GOTREL, R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_MIPS_GOT_GP_PC,
947946
R_AARCH64_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC, R_GOTPLTONLY_PC,
948947
R_PLT_PC, R_PLT_GOTPLT, R_PPC32_PLTREL, R_PPC64_CALL_PLT,
949-
R_PPC64_RELAX_TOC, R_RISCV_ADD, R_AARCH64_GOT_PAGE>(e))
948+
R_PPC64_RELAX_TOC, R_RISCV_ADD, R_AARCH64_GOT_PAGE, R_EPIC>(e))
950949
return true;
951950

952951
// These never do, except if the entire file is position dependent or if

0 commit comments

Comments
 (0)