Skip to content

Commit dbfc1b5

Browse files
[BOLT] Add --pad-funcs-before=func:n
This complements --pad-funcs, and by using both simultaneously, enables moving a specific function through a binary without modifying any code other than the targeted function (and references to it) by doing (before+after=constant). See also: proposed functionality to enable inserting random padding in https://discourse.llvm.org/t/rfc-lld-feature-for-controlling-for-code-size-dependent-measurement-bias
1 parent 0ccc389 commit dbfc1b5

File tree

2 files changed

+88
-0
lines changed

2 files changed

+88
-0
lines changed

bolt/lib/Core/BinaryEmitter.cpp

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,12 @@ FunctionPadSpec("pad-funcs",
5454
cl::Hidden,
5555
cl::cat(BoltCategory));
5656

57+
static cl::list<std::string> FunctionPadBeforeSpec(
58+
"pad-funcs-before", cl::CommaSeparated,
59+
cl::desc("list of functions to pad with amount of bytes"),
60+
cl::value_desc("func1:pad1,func2:pad2,func3:pad3,..."), cl::Hidden,
61+
cl::cat(BoltCategory));
62+
5763
static cl::opt<bool> MarkFuncs(
5864
"mark-funcs",
5965
cl::desc("mark function boundaries with break instruction to make "
@@ -94,6 +100,30 @@ size_t padFunction(const BinaryFunction &Function) {
94100
return 0;
95101
}
96102

103+
size_t padFunctionBefore(const BinaryFunction &Function) {
104+
static std::map<std::string, size_t> FunctionPadding;
105+
106+
if (FunctionPadding.empty() && !FunctionPadBeforeSpec.empty()) {
107+
for (std::string &Spec : FunctionPadBeforeSpec) {
108+
size_t N = Spec.find(':');
109+
if (N == std::string::npos)
110+
continue;
111+
std::string Name = Spec.substr(0, N);
112+
size_t Padding = std::stoull(Spec.substr(N + 1));
113+
FunctionPadding[Name] = Padding;
114+
}
115+
}
116+
117+
for (auto &FPI : FunctionPadding) {
118+
std::string Name = FPI.first;
119+
size_t Padding = FPI.second;
120+
if (Function.hasNameRegex(Name))
121+
return Padding;
122+
}
123+
124+
return 0;
125+
}
126+
97127
} // namespace opts
98128

99129
namespace {
@@ -319,6 +349,36 @@ bool BinaryEmitter::emitFunction(BinaryFunction &Function,
319349
Streamer.emitCodeAlignment(Function.getAlign(), &*BC.STI);
320350
}
321351

352+
if (size_t Padding = opts::padFunctionBefore(Function)) {
353+
// Handle padFuncsBefore after the above alignment logic but before
354+
// symbol addresses are decided; with the intent that the nops are
355+
// not executed and the original alignment logic is preserved.
356+
if (!BC.HasRelocations) {
357+
errs() << "BOLT-ERROR: -pad-before-funcs is not supported in "
358+
<< "non-relocation mode\n";
359+
exit(1);
360+
}
361+
362+
// Preserve Function.getMinAlign().
363+
if (!isAligned(Function.getMinAlign(), Padding)) {
364+
errs() << "BOLT-ERROR: User-requested " << Padding
365+
<< " padding bytes before function " << Function
366+
<< " is not a multiple of the minimum function alignment ("
367+
<< Function.getMinAlign().value() << ").\n";
368+
exit(1);
369+
}
370+
371+
LLVM_DEBUG(dbgs() << "BOLT-DEBUG: padding function " << Function << " with "
372+
<< Padding << " bytes\n");
373+
374+
// Since the padding is not executed, it can be null bytes.
375+
Streamer.emitFill(Padding, 0);
376+
377+
Function.setMaxSize(Function.getMaxSize() + Padding);
378+
Function.setSize(Function.getSize() + Padding);
379+
Function.setImageSize(Function.getImageSize() + Padding);
380+
}
381+
322382
MCContext &Context = Streamer.getContext();
323383
const MCAsmInfo *MAI = Context.getAsmInfo();
324384

bolt/test/AArch64/pad-before-funcs.s

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown %s -o %t.o
2+
# RUN: %clang %cflags %t.o -o %t.exe -Wl,-q -Wl,--section-start=.text=0x4000
3+
# RUN: llvm-bolt %t.exe -o %t.bolt.0 --pad-funcs-before=_start:0
4+
# RUN: llvm-bolt %t.exe -o %t.bolt.4 --pad-funcs-before=_start:4
5+
# RUN: llvm-bolt %t.exe -o %t.bolt.8 --pad-funcs-before=_start:8
6+
7+
# RUN: not llvm-bolt %t.exe -o %t.bolt.8 --pad-funcs-before=_start:1 2>&1 | FileCheck --check-prefix=CHECK-BAD-ALIGN %s
8+
9+
# CHECK-BAD-ALIGN: User-requested 1 padding bytes before function _start(*2) is not a multiple of the minimum function alignment (4).
10+
11+
# RUN: llvm-objdump --section=.text --disassemble %t.bolt.0 | FileCheck --check-prefix=CHECK-0 %s
12+
# RUN: llvm-objdump --section=.text --disassemble %t.bolt.4 | FileCheck --check-prefix=CHECK-4 %s
13+
# RUN: llvm-objdump --section=.text --disassemble %t.bolt.8 | FileCheck --check-prefix=CHECK-8 %s
14+
15+
# Need a symbol reference so that relocations are emitted.
16+
.section .data
17+
test:
18+
.word 0x0
19+
20+
.section .text
21+
.globl _start
22+
23+
# CHECK-0: 0000000000400000 <_start>
24+
# CHECK-4: 0000000000400004 <_start>
25+
# CHECK-8: 0000000000400008 <_start>
26+
_start:
27+
adr x0, test
28+
ret

0 commit comments

Comments
 (0)