Skip to content

Commit fb6c10d

Browse files
authored
[MC] Emit a jump table size section (#101962)
This patch will make LLVM emit a new section .llvm_jump_table_sizes containing tuples of (jump table address, entry count) in object files. This section is useful for tools that need to statically reconstruct the control flow of executables. At the moment this is only enabled by default for the PS5 target.
1 parent 9d12d93 commit fb6c10d

File tree

10 files changed

+298
-0
lines changed

10 files changed

+298
-0
lines changed

clang/lib/Driver/ToolChains/PS4CPU.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,8 @@ void tools::PS5cpu::Linker::ConstructJob(Compilation &C, const JobAction &JA,
272272
CmdArgs.push_back(D.getLTOMode() == LTOK_Thin ? "--lto=thin"
273273
: "--lto=full");
274274

275+
AddLTOFlag("-emit-jump-table-sizes-section");
276+
275277
if (UseJMC)
276278
AddLTOFlag("-enable-jmc-instrument");
277279

@@ -484,6 +486,12 @@ void toolchains::PS4PS5Base::addClangTargetOptions(
484486
else
485487
CC1Args.push_back("-fvisibility-externs-nodllstorageclass=keep");
486488
}
489+
490+
// Enable jump table sizes section for PS5.
491+
if (getTriple().isPS5()) {
492+
CC1Args.push_back("-mllvm");
493+
CC1Args.push_back("-emit-jump-table-sizes-section");
494+
}
487495
}
488496

489497
// PS4 toolchain.

clang/test/Driver/ps4-ps5-toolchain.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,8 @@
1111
// RUN: %clang %s -### -target x86_64-sie-ps5 -flto 2>&1 | FileCheck %s --check-prefix=LTO
1212
// LTO-NOT: error:
1313
// LTO-NOT: unable to pass LLVM bit-code
14+
15+
// Verify that the jump table sizes section is enabled.
16+
// RUN: %clang %s -target x86_64-sie-ps5 -### 2>&1 | FileCheck -check-prefix=JUMPTABLESIZES %s
17+
// JUMPTABLESIZES: "-mllvm" "-emit-jump-table-sizes-section"
18+
// JUMPTABLESIZES: "-plugin-opt=-emit-jump-table-sizes-section"

llvm/docs/Extensions.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,12 @@ time. This section is generated when the compiler enables fat LTO. This section
554554
has the ``SHF_EXCLUDE`` flag so that it is stripped from the final executable
555555
or shared library.
556556

557+
``SHT_LLVM_JT_SIZES`` Section (Jump table addresses and sizes)
558+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
559+
This section stores pairs of (jump table address, number of entries).
560+
This information is useful for tools that need to statically reconstruct
561+
the control flow of executables.
562+
557563
CodeView-Dependent
558564
------------------
559565

llvm/include/llvm/BinaryFormat/ELF.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1129,6 +1129,7 @@ enum : unsigned {
11291129
SHT_LLVM_BB_ADDR_MAP = 0x6fff4c0a, // LLVM Basic Block Address Map.
11301130
SHT_LLVM_OFFLOADING = 0x6fff4c0b, // LLVM device offloading data.
11311131
SHT_LLVM_LTO = 0x6fff4c0c, // .llvm.lto for fat LTO.
1132+
SHT_LLVM_JT_SIZES = 0x6fff4c0d, // LLVM jump tables sizes.
11321133
// Android's experimental support for SHT_RELR sections.
11331134
// https://android.googlesource.com/platform/bionic/+/b7feec74547f84559a1467aca02708ff61346d2a/libc/include/elf.h#512
11341135
SHT_ANDROID_RELR = 0x6fffff00, // Relocation entries; only offsets.

llvm/include/llvm/CodeGen/AsmPrinter.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -894,6 +894,10 @@ class AsmPrinter : public MachineFunctionPass {
894894

895895
void emitJumpTableEntry(const MachineJumpTableInfo *MJTI,
896896
const MachineBasicBlock *MBB, unsigned uid) const;
897+
898+
void emitJumpTableSizesSection(const MachineJumpTableInfo *MJTI,
899+
const Function &F) const;
900+
897901
void emitLLVMUsedList(const ConstantArray *InitList);
898902
/// Emit llvm.ident metadata in an '.ident' directive.
899903
void emitModuleIdents(Module &M);

llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@
9999
#include "llvm/MC/MCStreamer.h"
100100
#include "llvm/MC/MCSubtargetInfo.h"
101101
#include "llvm/MC/MCSymbol.h"
102+
#include "llvm/MC/MCSymbolCOFF.h"
102103
#include "llvm/MC/MCSymbolELF.h"
103104
#include "llvm/MC/MCTargetOptions.h"
104105
#include "llvm/MC/MCValue.h"
@@ -107,6 +108,7 @@
107108
#include "llvm/Pass.h"
108109
#include "llvm/Remarks/RemarkStreamer.h"
109110
#include "llvm/Support/Casting.h"
111+
#include "llvm/Support/CommandLine.h"
110112
#include "llvm/Support/Compiler.h"
111113
#include "llvm/Support/ErrorHandling.h"
112114
#include "llvm/Support/FileSystem.h"
@@ -155,6 +157,11 @@ static cl::bits<PGOMapFeaturesEnum> PgoAnalysisMapFeatures(
155157
"Enable extended information within the SHT_LLVM_BB_ADDR_MAP that is "
156158
"extracted from PGO related analysis."));
157159

160+
static cl::opt<bool> EmitJumpTableSizesSection(
161+
"emit-jump-table-sizes-section",
162+
cl::desc("Emit a section containing jump table addresses and sizes"),
163+
cl::Hidden, cl::init(false));
164+
158165
STATISTIC(EmittedInsts, "Number of machine instrs printed");
159166

160167
char AsmPrinter::ID = 0;
@@ -2786,10 +2793,62 @@ void AsmPrinter::emitJumpTableInfo() {
27862793
for (const MachineBasicBlock *MBB : JTBBs)
27872794
emitJumpTableEntry(MJTI, MBB, JTI);
27882795
}
2796+
2797+
if (EmitJumpTableSizesSection)
2798+
emitJumpTableSizesSection(MJTI, F);
2799+
27892800
if (!JTInDiffSection)
27902801
OutStreamer->emitDataRegion(MCDR_DataRegionEnd);
27912802
}
27922803

2804+
void AsmPrinter::emitJumpTableSizesSection(const MachineJumpTableInfo *MJTI,
2805+
const Function &F) const {
2806+
const std::vector<MachineJumpTableEntry> &JT = MJTI->getJumpTables();
2807+
2808+
if (JT.empty())
2809+
return;
2810+
2811+
StringRef GroupName = F.hasComdat() ? F.getComdat()->getName() : "";
2812+
MCSection *JumpTableSizesSection = nullptr;
2813+
StringRef sectionName = ".llvm_jump_table_sizes";
2814+
2815+
bool isElf = TM.getTargetTriple().isOSBinFormatELF();
2816+
bool isCoff = TM.getTargetTriple().isOSBinFormatCOFF();
2817+
2818+
if (!isCoff && !isElf)
2819+
return;
2820+
2821+
if (isElf) {
2822+
MCSymbolELF *LinkedToSym = dyn_cast<MCSymbolELF>(CurrentFnSym);
2823+
int Flags = F.hasComdat() ? ELF::SHF_GROUP : 0;
2824+
2825+
JumpTableSizesSection = OutContext.getELFSection(
2826+
sectionName, ELF::SHT_LLVM_JT_SIZES, Flags, 0, GroupName, F.hasComdat(),
2827+
MCSection::NonUniqueID, LinkedToSym);
2828+
} else if (isCoff) {
2829+
if (F.hasComdat()) {
2830+
JumpTableSizesSection = OutContext.getCOFFSection(
2831+
sectionName,
2832+
COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | COFF::IMAGE_SCN_MEM_READ |
2833+
COFF::IMAGE_SCN_LNK_COMDAT | COFF::IMAGE_SCN_MEM_DISCARDABLE,
2834+
F.getComdat()->getName(), COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE);
2835+
} else {
2836+
JumpTableSizesSection = OutContext.getCOFFSection(
2837+
sectionName, COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
2838+
COFF::IMAGE_SCN_MEM_READ |
2839+
COFF::IMAGE_SCN_MEM_DISCARDABLE);
2840+
}
2841+
}
2842+
2843+
OutStreamer->switchSection(JumpTableSizesSection);
2844+
2845+
for (unsigned JTI = 0, E = JT.size(); JTI != E; ++JTI) {
2846+
const std::vector<MachineBasicBlock *> &JTBBs = JT[JTI].MBBs;
2847+
OutStreamer->emitSymbolValue(GetJTISymbol(JTI), TM.getProgramPointerSize());
2848+
OutStreamer->emitIntValue(JTBBs.size(), TM.getProgramPointerSize());
2849+
}
2850+
}
2851+
27932852
/// EmitJumpTableEntry - Emit a jump table entry for the specified MBB to the
27942853
/// current stream.
27952854
void AsmPrinter::emitJumpTableEntry(const MachineJumpTableInfo *MJTI,

llvm/lib/MC/MCParser/ELFAsmParser.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -677,6 +677,8 @@ bool ELFAsmParser::ParseSectionArguments(bool IsPush, SMLoc loc) {
677677
Type = ELF::SHT_LLVM_OFFLOADING;
678678
else if (TypeName == "llvm_lto")
679679
Type = ELF::SHT_LLVM_LTO;
680+
else if (TypeName == "llvm_jt_sizes")
681+
Type = ELF::SHT_LLVM_JT_SIZES;
680682
else if (TypeName.getAsInteger(0, Type))
681683
return TokError("unknown section type");
682684
}

llvm/lib/MC/MCSectionELF.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,8 @@ void MCSectionELF::printSwitchToSection(const MCAsmInfo &MAI, const Triple &T,
172172
OS << "llvm_offloading";
173173
else if (Type == ELF::SHT_LLVM_LTO)
174174
OS << "llvm_lto";
175+
else if (Type == ELF::SHT_LLVM_JT_SIZES)
176+
OS << "llvm_jt_sizes";
175177
else
176178
OS << "0x" << Twine::utohexstr(Type);
177179

llvm/lib/Object/ELF.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,7 @@ StringRef llvm::object::getELFSectionTypeName(uint32_t Machine, unsigned Type) {
319319
STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_BB_ADDR_MAP);
320320
STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_OFFLOADING);
321321
STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_LTO);
322+
STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_JT_SIZES)
322323
STRINGIFY_ENUM_CASE(ELF, SHT_GNU_ATTRIBUTES);
323324
STRINGIFY_ENUM_CASE(ELF, SHT_GNU_HASH);
324325
STRINGIFY_ENUM_CASE(ELF, SHT_GNU_verdef);
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
; RUN: llc %s -o - -mtriple x86_64-sie-ps5 -emit-jump-table-sizes-section -verify-machineinstrs --relocation-model=pic | FileCheck --check-prefix=PS5-CHECK %s
2+
; RUN: llc %s -o - -mtriple x86_64-sie-ps5 -verify-machineinstrs --relocation-model=pic | FileCheck --check-prefix=NOFLAG %s
3+
; RUN: llc %s -o - -mtriple x86_64-sie-ps5 -verify-machineinstrs --relocation-model=pic | FileCheck --check-prefix=NOTABLE %s
4+
5+
; RUN: llc %s -o - -mtriple x86_64-unknown-linux-gnu -emit-jump-table-sizes-section -verify-machineinstrs --relocation-model=pic | FileCheck --check-prefix=ELF-CHECK %s
6+
; RUN: llc %s -o - -mtriple x86_64-unknown-linux-gnu -verify-machineinstrs --relocation-model=pic | FileCheck --check-prefix=NOFLAG %s
7+
; RUN: llc %s -o - -mtriple x86_64-unknown-linux-gnu -verify-machineinstrs --relocation-model=pic | FileCheck --check-prefix=NOTABLE %s
8+
9+
; RUN: llc %s -o - -mtriple x86_64-pc-windows-msvc -emit-jump-table-sizes-section -verify-machineinstrs --relocation-model=pic | FileCheck --check-prefix=COFF-CHECK %s
10+
; RUN: llc %s -o - -mtriple x86_64-pc-windows-msvc -verify-machineinstrs --relocation-model=pic | FileCheck --check-prefix=NOFLAG %s
11+
; RUN: llc %s -o - -mtriple x86_64-pc-windows-msvc -verify-machineinstrs --relocation-model=pic | FileCheck --check-prefix=NOTABLE %s
12+
13+
; This test verifies the jump table size section. Currently only enabled by default on the PS5 target.
14+
15+
$foo1 = comdat any
16+
17+
; Ensure proper comdat handling.
18+
define void @foo1(i32 %x, ptr %to) comdat {
19+
20+
; PS5-CHECK-LABEL: foo1
21+
; PS5-CHECK: .section .llvm_jump_table_sizes,"G",@llvm_jt_sizes,foo1,comdat
22+
; PS5-CHECK-NEXT: .quad .LJTI0_0
23+
; PS5-CHECK-NEXT: .quad 6
24+
25+
; ELF-CHECK-LABEL: foo1
26+
; ELF-CHECK: .section .llvm_jump_table_sizes,"G",@llvm_jt_sizes,foo1,comdat
27+
; ELF-CHECK-NEXT: .quad .LJTI0_0
28+
; ELF-CHECK-NEXT: .quad 6
29+
30+
; COFF-CHECK-LABEL: foo1
31+
; COFF-CHECK: .section .llvm_jump_table_sizes,"drD",associative,foo1
32+
; COFF-CHECK-NEXT: .quad .LJTI0_0
33+
; COFF-CHECK-NEXT: .quad 6
34+
35+
; NOFLAG-LABEL: foo1
36+
; NOFLAG-NOT: .section .llvm_jump_table_sizes
37+
38+
entry:
39+
switch i32 %x, label %default [
40+
i32 0, label %bb0
41+
i32 1, label %bb1
42+
i32 2, label %bb2
43+
i32 3, label %bb3
44+
i32 4, label %bb4
45+
i32 5, label %bb4
46+
]
47+
bb0:
48+
store i32 0, ptr %to
49+
br label %exit
50+
bb1:
51+
store i32 1, ptr %to
52+
br label %exit
53+
bb2:
54+
store i32 2, ptr %to
55+
br label %exit
56+
bb3:
57+
store i32 3, ptr %to
58+
br label %exit
59+
bb4:
60+
store i32 4, ptr %to
61+
br label %exit
62+
exit:
63+
ret void
64+
default:
65+
unreachable
66+
}
67+
68+
define void @foo2(i32 %x, ptr %to) {
69+
70+
; PS5-CHECK-LABEL: foo2
71+
; PS5-CHECK: .section .llvm_jump_table_sizes,"",@llvm_jt_sizes
72+
; PS5-CHECK-NEXT: .quad .LJTI1_0
73+
; PS5-CHECK-NEXT: .quad 5
74+
75+
; ELF-CHECK-LABEL: foo2
76+
; ELF-CHECK: .section .llvm_jump_table_sizes,"",@llvm_jt_sizes
77+
; ELF-CHECK-NEXT: .quad .LJTI1_0
78+
; ELF-CHECK-NEXT: .quad 5
79+
80+
; COFF-CHECK-LABEL: foo2
81+
; COFF-CHECK: .section .llvm_jump_table_sizes,"drD"
82+
; COFF-CHECK-NEXT: .quad .LJTI1_0
83+
; COFF-CHECK-NEXT: .quad 5
84+
85+
; NOFLAG-LABEL: foo1
86+
; NOFLAG-NOT: .section .llvm_jump_table_sizes
87+
88+
entry:
89+
switch i32 %x, label %default [
90+
i32 0, label %bb0
91+
i32 1, label %bb1
92+
i32 2, label %bb2
93+
i32 3, label %bb3
94+
i32 4, label %bb4
95+
]
96+
bb0:
97+
store i32 0, ptr %to
98+
br label %exit
99+
bb1:
100+
store i32 1, ptr %to
101+
br label %exit
102+
bb2:
103+
store i32 2, ptr %to
104+
br label %exit
105+
bb3:
106+
store i32 3, ptr %to
107+
br label %exit
108+
bb4:
109+
store i32 4, ptr %to
110+
br label %exit
111+
exit:
112+
ret void
113+
default:
114+
unreachable
115+
}
116+
117+
; Ensure that the section isn't produced if there is no jump table.
118+
119+
define void @foo3(i32 %x, ptr %to) {
120+
121+
; NOTABLE-LABEL: foo3
122+
; NOTABLE-NOT: .section .llvm_jump_table_sizes
123+
124+
exit:
125+
ret void
126+
}
127+
128+
; Ensure we can deal with nested jump tables.
129+
130+
define void @nested(i32 %x, i32 %y, ptr %to) {
131+
132+
; PS5-CHECK-LABEL: nested
133+
; PS5-CHECK: .section .llvm_jump_table_sizes,"",@llvm_jt_sizes
134+
; PS5-CHECK-NEXT: .quad .LJTI3_0
135+
; PS5-CHECK-NEXT: .quad 5
136+
; PS5-CHECK-NEXT: .quad .LJTI3_1
137+
; PS5-CHECK-NEXT: .quad 6
138+
139+
; ELF-CHECK-LABEL: nested
140+
; ELF-CHECK: .section .llvm_jump_table_sizes,"",@llvm_jt_sizes
141+
; ELF-CHECK-NEXT: .quad .LJTI3_0
142+
; ELF-CHECK-NEXT: .quad 5
143+
; ELF-CHECK-NEXT: .quad .LJTI3_1
144+
; ELF-CHECK-NEXT: .quad 6
145+
146+
; COFF-CHECK-LABEL: nested
147+
; COFF-CHECK: .section .llvm_jump_table_sizes,"drD"
148+
; COFF-CHECK-NEXT: .quad .LJTI3_0
149+
; COFF-CHECK-NEXT: .quad 5
150+
; COFF-CHECK-NEXT: .quad .LJTI3_1
151+
; COFF-CHECK-NEXT: .quad 6
152+
153+
; NOFLAG-LABEL: nested
154+
; NOFLAG-NOT: .section .llvm_jump_table_sizes
155+
156+
entry:
157+
switch i32 %x, label %default [
158+
i32 0, label %bb0
159+
i32 1, label %bb1
160+
i32 2, label %bb2
161+
i32 3, label %bb3
162+
i32 4, label %bb4
163+
]
164+
bb0:
165+
store i32 0, ptr %to
166+
br label %exit
167+
bb1:
168+
store i32 1, ptr %to
169+
br label %exit
170+
bb2:
171+
store i32 2, ptr %to
172+
br label %exit
173+
bb3:
174+
store i32 3, ptr %to
175+
br label %exit
176+
bb4:
177+
switch i32 %y, label %default [
178+
i32 1, label %bb5
179+
i32 2, label %bb6
180+
i32 3, label %bb7
181+
i32 4, label %bb8
182+
i32 5, label %bb9
183+
i32 6, label %bb10
184+
]
185+
br label %exit2
186+
bb5:
187+
store i32 4, ptr %to
188+
br label %exit
189+
bb6:
190+
store i32 4, ptr %to
191+
br label %exit
192+
bb7:
193+
store i32 4, ptr %to
194+
br label %exit
195+
bb8:
196+
store i32 4, ptr %to
197+
br label %exit
198+
bb9:
199+
store i32 4, ptr %to
200+
br label %exit
201+
bb10:
202+
store i32 4, ptr %to
203+
br label %exit
204+
exit:
205+
ret void
206+
exit2:
207+
ret void
208+
default:
209+
unreachable
210+
}

0 commit comments

Comments
 (0)