@@ -47,12 +47,16 @@ BreakFunctionNames("break-funcs",
4747 cl::cat(BoltCategory));
4848
4949static 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));
5660
5761static cl::opt<bool > MarkFuncs (
5862 " mark-funcs" ,
@@ -70,11 +74,11 @@ X86AlignBranchBoundaryHotOnly("x86-align-branch-boundary-hot-only",
7074 cl::init(true ),
7175 cl::cat(BoltOptCategory));
7276
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 ) {
7882 size_t N = Spec.find (' :' );
7983 if (N == std::string::npos)
8084 continue ;
@@ -94,6 +98,15 @@ size_t padFunction(const BinaryFunction &Function) {
9498 return 0 ;
9599}
96100
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+
97110} // namespace opts
98111
99112namespace {
@@ -319,6 +332,31 @@ bool BinaryEmitter::emitFunction(BinaryFunction &Function,
319332 Streamer.emitCodeAlignment (Function.getAlign (), &*BC.STI );
320333 }
321334
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+
322360 MCContext &Context = Streamer.getContext ();
323361 const MCAsmInfo *MAI = Context.getAsmInfo ();
324362
@@ -373,7 +411,7 @@ bool BinaryEmitter::emitFunction(BinaryFunction &Function,
373411 emitFunctionBody (Function, FF, /* EmitCodeOnly=*/ false );
374412
375413 // Emit padding if requested.
376- if (size_t Padding = opts::padFunction (Function)) {
414+ if (size_t Padding = opts::padFunctionAfter (Function)) {
377415 LLVM_DEBUG (dbgs () << " BOLT-DEBUG: padding function " << Function << " with "
378416 << Padding << " bytes\n " );
379417 Streamer.emitFill (Padding, MAI->getTextAlignFillValue ());
0 commit comments