Skip to content

Commit 5bce06b

Browse files
committed
[𝘀𝗽𝗿] initial version
Created using spr 1.3.6-beta.1
1 parent 4946db1 commit 5bce06b

File tree

3 files changed

+97
-1
lines changed

3 files changed

+97
-1
lines changed

lld/ELF/Arch/X86_64.cpp

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,9 @@ bool X86_64::deleteFallThruJmpInsn(InputSection &is, InputFile *file,
318318
}
319319

320320
bool X86_64::relaxOnce(int pass) const {
321+
if (pass == 0)
322+
relaxJumpTables(ctx);
323+
321324
uint64_t minVA = UINT64_MAX, maxVA = 0;
322325
for (OutputSection *osec : ctx.outputSections) {
323326
if (!(osec->flags & SHF_ALLOC))
@@ -1231,6 +1234,98 @@ void X86_64::applyBranchToBranchOpt() const {
12311234
redirectControlTransferRelocations);
12321235
}
12331236

1237+
void elf::relaxJumpTables(Ctx &ctx) {
1238+
// Relax CFI jump tables.
1239+
// - Split jump table into pieces and place target functions inside the jump
1240+
// table if small enough.
1241+
// - Move jump table before last called function and delete last branch
1242+
// instruction.
1243+
std::map<InputSection *, std::vector<InputSection *>> sectionReplacements;
1244+
SmallVector<InputSection *, 0> storage;
1245+
for (OutputSection *osec : ctx.outputSections) {
1246+
if (!(osec->flags & SHF_EXECINSTR))
1247+
continue;
1248+
for (InputSection *sec : getInputSections(*osec, storage)) {
1249+
if (!sec->name.starts_with(".text..L.cfi.jumptable"))
1250+
continue;
1251+
std::vector<InputSection *> replacements;
1252+
replacements.push_back(sec);
1253+
auto addSectionSlice = [&](size_t begin, size_t end, Relocation *rbegin,
1254+
Relocation *rend) {
1255+
if (begin == end)
1256+
return;
1257+
auto *slice = make<InputSection>(
1258+
sec->file, sec->name, sec->type, sec->flags, 1, sec->entsize,
1259+
sec->contentMaybeDecompress().slice(begin, end - begin));
1260+
for (const Relocation &r : ArrayRef<Relocation>(rbegin, rend)) {
1261+
slice->relocations.push_back(
1262+
Relocation{r.expr, r.type, r.offset - begin, r.addend, r.sym});
1263+
}
1264+
replacements.push_back(slice);
1265+
};
1266+
auto getMovableSection = [&](Relocation &r) -> InputSection * {
1267+
auto *sym = dyn_cast_or_null<Defined>(r.sym);
1268+
if (!sym || sym->isPreemptible || sym->isGnuIFunc() || sym->value != 0)
1269+
return nullptr;
1270+
auto *sec = dyn_cast_or_null<InputSection>(sym->section);
1271+
if (!sec || sectionReplacements.count(sec))
1272+
return nullptr;
1273+
return sec;
1274+
};
1275+
size_t begin = 0;
1276+
Relocation *rbegin = sec->relocs().begin();
1277+
for (auto &r : sec->relocs().slice(0, sec->relocs().size() - 1)) {
1278+
auto entrySize = (&r + 1)->offset - r.offset;
1279+
InputSection *target = getMovableSection(r);
1280+
if (!target || target->size > entrySize)
1281+
continue;
1282+
target->addralign = 1;
1283+
addSectionSlice(begin, r.offset - 1, rbegin, &r);
1284+
replacements.push_back(target);
1285+
sectionReplacements[target] = {};
1286+
begin = r.offset - 1 + target->size;
1287+
rbegin = &r + 1;
1288+
}
1289+
InputSection *lastSec = getMovableSection(sec->relocs().back());
1290+
if (lastSec) {
1291+
lastSec->addralign = 1;
1292+
addSectionSlice(begin, sec->relocs().back().offset - 1, rbegin,
1293+
&sec->relocs().back());
1294+
replacements.push_back(lastSec);
1295+
sectionReplacements[sec] = {};
1296+
sectionReplacements[lastSec] = replacements;
1297+
for (auto *s : replacements)
1298+
s->parent = lastSec->parent;
1299+
} else {
1300+
addSectionSlice(begin, sec->size, rbegin, sec->relocs().end());
1301+
sectionReplacements[sec] = replacements;
1302+
for (auto *s : replacements)
1303+
s->parent = sec->parent;
1304+
}
1305+
sec->relocations.clear();
1306+
sec->size = 0;
1307+
}
1308+
}
1309+
for (OutputSection *osec : ctx.outputSections) {
1310+
if (!(osec->flags & SHF_EXECINSTR))
1311+
continue;
1312+
for (SectionCommand *cmd : osec->commands) {
1313+
auto *isd = dyn_cast<InputSectionDescription>(cmd);
1314+
if (!isd)
1315+
continue;
1316+
SmallVector<InputSection *> newSections;
1317+
for (auto *sec : isd->sections) {
1318+
auto i = sectionReplacements.find(sec);
1319+
if (i == sectionReplacements.end())
1320+
newSections.push_back(sec);
1321+
else
1322+
newSections.append(i->second.begin(), i->second.end());
1323+
}
1324+
isd->sections = std::move(newSections);
1325+
}
1326+
}
1327+
}
1328+
12341329
// If Intel Indirect Branch Tracking is enabled, we have to emit special PLT
12351330
// entries containing endbr64 instructions. A PLT entry will be split into two
12361331
// parts, one in .plt.sec (writePlt), and the other in .plt (writeIBTPlt).

lld/ELF/Relocations.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1674,7 +1674,7 @@ void RelocationScanner::scan(Relocs<RelTy> rels) {
16741674
// R_RISCV_PCREL_HI20, R_PPC64_ADDR64 and the branch-to-branch optimization.
16751675
if (ctx.arg.emachine == EM_RISCV ||
16761676
(ctx.arg.emachine == EM_PPC64 && sec->name == ".toc") ||
1677-
ctx.arg.branchToBranch)
1677+
ctx.arg.branchToBranch || sec->name.starts_with(".text..L.cfi.jumptable"))
16781678
llvm::stable_sort(sec->relocs(),
16791679
[](const Relocation &lhs, const Relocation &rhs) {
16801680
return lhs.offset < rhs.offset;

lld/ELF/Target.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ void setSPARCV9TargetInfo(Ctx &);
195195
void setSystemZTargetInfo(Ctx &);
196196
void setX86TargetInfo(Ctx &);
197197
void setX86_64TargetInfo(Ctx &);
198+
void relaxJumpTables(Ctx &);
198199

199200
struct ErrorPlace {
200201
InputSectionBase *isec;

0 commit comments

Comments
 (0)