Skip to content

Commit 14dcf82

Browse files
[BOLT] Add --pad-funcs-before=func:n (#117924)
This complements --pad-funcs, and by using both simultaneously, enables moving a specific function through the address space 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 and #117653
1 parent 8d714db commit 14dcf82

File tree

3 files changed

+80
-14
lines changed

3 files changed

+80
-14
lines changed

bolt/lib/Core/BinaryEmitter.cpp

Lines changed: 42 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,17 @@ BreakFunctionNames("break-funcs",
4646
cl::Hidden,
4747
cl::cat(BoltCategory));
4848

49-
static cl::list<std::string>
50-
FunctionPadSpec("pad-funcs",
51-
cl::CommaSeparated,
52-
cl::desc("list of functions to pad with amount of bytes"),
53-
cl::value_desc("func1:pad1,func2:pad2,func3:pad3,..."),
54-
cl::Hidden,
55-
cl::cat(BoltCategory));
49+
cl::list<std::string>
50+
FunctionPadSpec("pad-funcs", cl::CommaSeparated,
51+
cl::desc("list of functions to pad with amount of bytes"),
52+
cl::value_desc("func1:pad1,func2:pad2,func3:pad3,..."),
53+
cl::Hidden, cl::cat(BoltCategory));
54+
55+
cl::list<std::string> FunctionPadBeforeSpec(
56+
"pad-funcs-before", cl::CommaSeparated,
57+
cl::desc("list of functions to pad with amount of bytes"),
58+
cl::value_desc("func1:pad1,func2:pad2,func3:pad3,..."), cl::Hidden,
59+
cl::cat(BoltCategory));
5660

5761
static cl::opt<bool> MarkFuncs(
5862
"mark-funcs",
@@ -70,11 +74,12 @@ X86AlignBranchBoundaryHotOnly("x86-align-branch-boundary-hot-only",
7074
cl::init(true),
7175
cl::cat(BoltOptCategory));
7276

73-
size_t padFunction(const BinaryFunction &Function) {
77+
size_t padFunction(const cl::list<std::string> &Spec,
78+
const BinaryFunction &Function) {
7479
static std::map<std::string, size_t> FunctionPadding;
7580

76-
if (FunctionPadding.empty() && !FunctionPadSpec.empty()) {
77-
for (std::string &Spec : FunctionPadSpec) {
81+
if (FunctionPadding.empty() && !Spec.empty()) {
82+
for (const std::string &Spec : Spec) {
7883
size_t N = Spec.find(':');
7984
if (N == std::string::npos)
8085
continue;
@@ -319,6 +324,32 @@ bool BinaryEmitter::emitFunction(BinaryFunction &Function,
319324
Streamer.emitCodeAlignment(Function.getAlign(), &*BC.STI);
320325
}
321326

327+
if (size_t Padding =
328+
opts::padFunction(opts::FunctionPadBeforeSpec, Function)) {
329+
// Handle padFuncsBefore after the above alignment logic but before
330+
// symbol addresses are decided.
331+
if (!BC.HasRelocations) {
332+
BC.errs() << "BOLT-ERROR: -pad-before-funcs is not supported in "
333+
<< "non-relocation mode\n";
334+
exit(1);
335+
}
336+
337+
// Preserve Function.getMinAlign().
338+
if (!isAligned(Function.getMinAlign(), Padding)) {
339+
BC.errs() << "BOLT-ERROR: user-requested " << Padding
340+
<< " padding bytes before function " << Function
341+
<< " is not a multiple of the minimum function alignment ("
342+
<< Function.getMinAlign().value() << ").\n";
343+
exit(1);
344+
}
345+
346+
LLVM_DEBUG(dbgs() << "BOLT-DEBUG: padding before function " << Function
347+
<< " with " << Padding << " bytes\n");
348+
349+
// Since the padding is not executed, it can be null bytes.
350+
Streamer.emitFill(Padding, 0);
351+
}
352+
322353
MCContext &Context = Streamer.getContext();
323354
const MCAsmInfo *MAI = Context.getAsmInfo();
324355

@@ -373,7 +404,7 @@ bool BinaryEmitter::emitFunction(BinaryFunction &Function,
373404
emitFunctionBody(Function, FF, /*EmitCodeOnly=*/false);
374405

375406
// Emit padding if requested.
376-
if (size_t Padding = opts::padFunction(Function)) {
407+
if (size_t Padding = opts::padFunction(opts::FunctionPadSpec, Function)) {
377408
LLVM_DEBUG(dbgs() << "BOLT-DEBUG: padding function " << Function << " with "
378409
<< Padding << " bytes\n");
379410
Streamer.emitFill(Padding, MAI->getTextAlignFillValue());

bolt/lib/Passes/ReorderFunctions.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ extern cl::OptionCategory BoltOptCategory;
2828
extern cl::opt<unsigned> Verbosity;
2929
extern cl::opt<uint32_t> RandomSeed;
3030

31-
extern size_t padFunction(const bolt::BinaryFunction &Function);
31+
extern size_t padFunction(const cl::list<std::string> &Spec,
32+
const bolt::BinaryFunction &Function);
33+
extern cl::list<std::string> FunctionPadSpec, FunctionPadBeforeSpec;
3234

3335
extern cl::opt<bolt::ReorderFunctions::ReorderType> ReorderFunctions;
3436
cl::opt<bolt::ReorderFunctions::ReorderType> ReorderFunctions(
@@ -304,8 +306,12 @@ Error ReorderFunctions::runOnFunctions(BinaryContext &BC) {
304306
return false;
305307
if (B->isIgnored())
306308
return true;
307-
const size_t PadA = opts::padFunction(*A);
308-
const size_t PadB = opts::padFunction(*B);
309+
const size_t PadA =
310+
opts::padFunction(opts::FunctionPadSpec, *A) +
311+
opts::padFunction(opts::FunctionPadBeforeSpec, *A);
312+
const size_t PadB =
313+
opts::padFunction(opts::FunctionPadSpec, *B) +
314+
opts::padFunction(opts::FunctionPadBeforeSpec, *B);
309315
if (!PadA || !PadB) {
310316
if (PadA)
311317
return true;

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

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Test checks that --pad-before-funcs is working as expected.
2+
# It should be able to introduce a configurable offset for the _start symbol.
3+
# It should reject requests which don't obey the code alignment requirement.
4+
5+
# RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown %s -o %t.o
6+
# RUN: %clang %cflags %t.o -o %t.exe -Wl,-q -Wl,--section-start=.text=0x4000
7+
# RUN: llvm-bolt %t.exe -o %t.bolt.0 --pad-funcs-before=_start:0
8+
# RUN: llvm-bolt %t.exe -o %t.bolt.4 --pad-funcs-before=_start:4
9+
# RUN: llvm-bolt %t.exe -o %t.bolt.8 --pad-funcs-before=_start:8
10+
11+
# RUN: not llvm-bolt %t.exe -o %t.bolt.8 --pad-funcs-before=_start:1 2>&1 | FileCheck --check-prefix=CHECK-BAD-ALIGN %s
12+
13+
# CHECK-BAD-ALIGN: user-requested 1 padding bytes before function _start(*2) is not a multiple of the minimum function alignment (4).
14+
15+
# RUN: llvm-objdump --section=.text --disassemble %t.bolt.0 | FileCheck --check-prefix=CHECK-0 %s
16+
# RUN: llvm-objdump --section=.text --disassemble %t.bolt.4 | FileCheck --check-prefix=CHECK-4 %s
17+
# RUN: llvm-objdump --section=.text --disassemble %t.bolt.8 | FileCheck --check-prefix=CHECK-8 %s
18+
19+
# Trigger relocation mode in bolt.
20+
.reloc 0, R_AARCH64_NONE
21+
22+
.section .text
23+
.globl _start
24+
25+
# CHECK-0: 0000000000400000 <_start>
26+
# CHECK-4: 0000000000400004 <_start>
27+
# CHECK-8: 0000000000400008 <_start>
28+
_start:
29+
ret

0 commit comments

Comments
 (0)