Skip to content

Commit 0ebcd5d

Browse files
committed
[ELF] Emit .reloc annotations and local STT_OBJECT symbols for jump tables
The Linux kernel build system performs static analysis on the ELF objects to infer whether indirect jumps are truly function pointer dereferences, or calls via jump tables where the set of possible destinations is limited and decided at compile-time. When generating position dependent x86 code for the small code model, this is usually straight-forward, as the address of the jump table is encoded as an immediate in the instruction, e.g., jmpq *jump_table(, %reg, 8) and each entry in the table represents the absolute address of a jump destination. However, when switching to PIC codegen, or building for load-store architectures, this usually becomes something like leaq jump_table(%rip), %reg0 movlsq (%reg0, %reg1, 4), %reg1 addq %reg0, %reg1 jmpq *%reg1 or on arm64 adrp xM, jump_table add xM, :lo12:jump_table ldrsw wN, [xM, xN, lsl #2] add xN, xN, xM br xN where there is no obvious correlation between the location of the jump table and the indirect branch instruction, and where the start of each jump table has to be known to dereference the 32-bit relative references correctly, as they are relative to the start of the table rather than relative to each individual entry. Make the tooling's job easier by: - emitting an ELF symbol that covers the jump table, so that its size can be discovered; - emitting a BFD_RELOC_NONE allocation that links the symbol to the indirect branch instruction where the effective jump destination is consumed. Signed-off-by: Ard Biesheuvel <[email protected]>
1 parent 5000c68 commit 0ebcd5d

File tree

3 files changed

+51
-4
lines changed

3 files changed

+51
-4
lines changed

llvm/include/llvm/CodeGen/AsmPrinter.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,10 @@ class AsmPrinter : public MachineFunctionPass {
453453
/// function to the current output stream.
454454
virtual void emitJumpTableInfo();
455455

456+
/// Emit jump table annotations correlating each table with its associated
457+
/// indirect branch instruction.
458+
virtual void emitJumpTableAnnotation(const MachineFunction &MF, const MachineInstr &MI);
459+
456460
/// Emit the specified global variable to the .s file.
457461
virtual void emitGlobalVariable(const GlobalVariable *GV);
458462

llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,10 @@ static cl::opt<bool> EmitJumpTableSizesSection(
162162
cl::desc("Emit a section containing jump table addresses and sizes"),
163163
cl::Hidden, cl::init(false));
164164

165+
static cl::opt<bool> AnnotateJumpTables("annotate-jump-tables",
166+
cl::desc("Annotate jump tables"),
167+
cl::Hidden, cl::init(false));
168+
165169
STATISTIC(EmittedInsts, "Number of machine instrs printed");
166170

167171
char AsmPrinter::ID = 0;
@@ -1528,6 +1532,25 @@ void AsmPrinter::emitPseudoProbe(const MachineInstr &MI) {
15281532
}
15291533
}
15301534

1535+
void AsmPrinter::emitJumpTableAnnotation(const MachineFunction &MF,
1536+
const MachineInstr &MI) {
1537+
if (!AnnotateJumpTables || !TM.getTargetTriple().isOSBinFormatELF())
1538+
return;
1539+
1540+
MCSymbol *JTISymbol = GetJTISymbol(MI.getOperand(0).getImm());
1541+
MCSymbol *ProvenanceLabel = OutContext.createTempSymbol("jtp");
1542+
1543+
const MCExpr *OffsetExpr =
1544+
MCSymbolRefExpr::create(ProvenanceLabel, OutContext);
1545+
const MCExpr *JTISymbolExpr =
1546+
MCSymbolRefExpr::create(JTISymbol, OutContext);
1547+
1548+
OutStreamer->emitRelocDirective(*OffsetExpr, "BFD_RELOC_NONE",
1549+
JTISymbolExpr, SMLoc(),
1550+
*OutContext.getSubtargetInfo());
1551+
OutStreamer->emitLabel(ProvenanceLabel);
1552+
}
1553+
15311554
void AsmPrinter::emitStackSizeSection(const MachineFunction &MF) {
15321555
if (!MF.getTarget().Options.EmitStackSizeSection)
15331556
return;
@@ -1849,8 +1872,7 @@ void AsmPrinter::emitFunctionBody() {
18491872
OutStreamer->emitRawComment("MEMBARRIER");
18501873
break;
18511874
case TargetOpcode::JUMP_TABLE_DEBUG_INFO:
1852-
// This instruction is only used to note jump table debug info, it's
1853-
// purely meta information.
1875+
emitJumpTableAnnotation(*MF, MI);
18541876
break;
18551877
case TargetOpcode::INIT_UNDEF:
18561878
// This is only used to influence register allocation behavior, no
@@ -2821,6 +2843,25 @@ void AsmPrinter::emitJumpTableInfo() {
28212843
// label differences will be evaluated at write time.
28222844
for (const MachineBasicBlock *MBB : JTBBs)
28232845
emitJumpTableEntry(MJTI, MBB, JTI);
2846+
2847+
if (AnnotateJumpTables && TM.getTargetTriple().isOSBinFormatELF()) {
2848+
// Create a temp symbol for the end of the jump table.
2849+
MCSymbol *JTIEndSymbol = createTempSymbol("jt_end");
2850+
OutStreamer->emitLabel(JTIEndSymbol);
2851+
2852+
const MCExpr *JTISymbolExpr =
2853+
MCSymbolRefExpr::create(JTISymbol, OutContext);
2854+
2855+
MCSymbol *JTISymbolForSize = OutContext.getOrCreateSymbol(
2856+
"$JTI" + Twine(MF->getFunctionNumber()) + "_" + Twine(JTI));
2857+
OutStreamer->emitAssignment(JTISymbolForSize, JTISymbolExpr);
2858+
OutStreamer->emitSymbolAttribute(JTISymbolForSize, MCSA_ELF_TypeObject);
2859+
2860+
const MCExpr *SizeExp = MCBinaryExpr::createSub(
2861+
MCSymbolRefExpr::create(JTIEndSymbol, OutContext), JTISymbolExpr,
2862+
OutContext);
2863+
OutStreamer->emitELFSize(JTISymbolForSize, SizeExp);
2864+
}
28242865
}
28252866

28262867
if (EmitJumpTableSizesSection)

llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -479,8 +479,10 @@ SDValue TargetLowering::expandIndirectJTBranch(const SDLoc &dl, SDValue Value,
479479
SDValue Addr, int JTI,
480480
SelectionDAG &DAG) const {
481481
SDValue Chain = Value;
482-
// Jump table debug info is only needed if CodeView is enabled.
483-
if (DAG.getTarget().getTargetTriple().isOSBinFormatCOFF()) {
482+
const auto &Triple = DAG.getTarget().getTargetTriple();
483+
// Jump table debug info is only needed if CodeView is enabled,
484+
// or when adding jump table annotations to ELF objects.
485+
if (Triple.isOSBinFormatCOFF() || Triple.isOSBinFormatELF()) {
484486
Chain = DAG.getJumpTableDebugInfo(JTI, Chain, dl);
485487
}
486488
return DAG.getNode(ISD::BRIND, dl, MVT::Other, Chain, Addr);

0 commit comments

Comments
 (0)