@@ -47,12 +47,16 @@ BreakFunctionNames("break-funcs",
47
47
cl::cat(BoltCategory));
48
48
49
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));
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
+ static 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));
56
60
57
61
static cl::opt<bool > MarkFuncs (
58
62
" mark-funcs" ,
@@ -70,11 +74,11 @@ X86AlignBranchBoundaryHotOnly("x86-align-branch-boundary-hot-only",
70
74
cl::init(true ),
71
75
cl::cat(BoltOptCategory));
72
76
73
- size_t padFunction (const BinaryFunction &Function) {
74
- static std::map <std::string, size_t > FunctionPadding;
75
-
76
- if (FunctionPadding.empty () && !FunctionPadSpec .empty ()) {
77
- for (std::string &Spec : FunctionPadSpec ) {
77
+ size_t padFunction (std::map<std::string, size_t > &FunctionPadding,
78
+ const cl::list <std::string> &Spec,
79
+ const BinaryFunction &Function) {
80
+ if (FunctionPadding.empty () && !Spec .empty ()) {
81
+ for (const std::string &Spec : Spec ) {
78
82
size_t N = Spec.find (' :' );
79
83
if (N == std::string::npos)
80
84
continue ;
@@ -94,6 +98,15 @@ size_t padFunction(const BinaryFunction &Function) {
94
98
return 0 ;
95
99
}
96
100
101
+ size_t padFunctionBefore (const BinaryFunction &Function) {
102
+ static std::map<std::string, size_t > CacheFunctionPadding;
103
+ return padFunction (CacheFunctionPadding, FunctionPadBeforeSpec, Function);
104
+ }
105
+ size_t padFunctionAfter (const BinaryFunction &Function) {
106
+ static std::map<std::string, size_t > CacheFunctionPadding;
107
+ return padFunction (CacheFunctionPadding, FunctionPadSpec, Function);
108
+ }
109
+
97
110
} // namespace opts
98
111
99
112
namespace {
@@ -319,6 +332,31 @@ bool BinaryEmitter::emitFunction(BinaryFunction &Function,
319
332
Streamer.emitCodeAlignment (Function.getAlign (), &*BC.STI );
320
333
}
321
334
335
+ if (size_t Padding = opts::padFunctionBefore (Function)) {
336
+ // Handle padFuncsBefore after the above alignment logic but before
337
+ // symbol addresses are decided.
338
+ if (!BC.HasRelocations ) {
339
+ BC.errs () << " BOLT-ERROR: -pad-before-funcs is not supported in "
340
+ << " non-relocation mode\n " ;
341
+ exit (1 );
342
+ }
343
+
344
+ // Preserve Function.getMinAlign().
345
+ if (!isAligned (Function.getMinAlign (), Padding)) {
346
+ BC.errs () << " BOLT-ERROR: user-requested " << Padding
347
+ << " padding bytes before function " << Function
348
+ << " is not a multiple of the minimum function alignment ("
349
+ << Function.getMinAlign ().value () << " ).\n " ;
350
+ exit (1 );
351
+ }
352
+
353
+ LLVM_DEBUG (dbgs () << " BOLT-DEBUG: padding before function " << Function
354
+ << " with " << Padding << " bytes\n " );
355
+
356
+ // Since the padding is not executed, it can be null bytes.
357
+ Streamer.emitFill (Padding, 0 );
358
+ }
359
+
322
360
MCContext &Context = Streamer.getContext ();
323
361
const MCAsmInfo *MAI = Context.getAsmInfo ();
324
362
@@ -373,7 +411,7 @@ bool BinaryEmitter::emitFunction(BinaryFunction &Function,
373
411
emitFunctionBody (Function, FF, /* EmitCodeOnly=*/ false );
374
412
375
413
// Emit padding if requested.
376
- if (size_t Padding = opts::padFunction (Function)) {
414
+ if (size_t Padding = opts::padFunctionAfter (Function)) {
377
415
LLVM_DEBUG (dbgs () << " BOLT-DEBUG: padding function " << Function << " with "
378
416
<< Padding << " bytes\n " );
379
417
Streamer.emitFill (Padding, MAI->getTextAlignFillValue ());
0 commit comments