@@ -318,6 +318,9 @@ bool X86_64::deleteFallThruJmpInsn(InputSection &is, InputFile *file,
318318}
319319
320320bool 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).
0 commit comments