xref: /llvm-project/bolt/lib/Rewrite/MachORewriteInstance.cpp (revision c0febca3a64530c1cc3f117aec6a28c37114e572)
1 //===- bolt/Rewrite/MachORewriteInstance.cpp - MachO rewriter -------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "bolt/Rewrite/MachORewriteInstance.h"
10 #include "bolt/Core/BinaryContext.h"
11 #include "bolt/Core/BinaryEmitter.h"
12 #include "bolt/Core/BinaryFunction.h"
13 #include "bolt/Core/JumpTable.h"
14 #include "bolt/Core/MCPlusBuilder.h"
15 #include "bolt/Passes/Instrumentation.h"
16 #include "bolt/Passes/PatchEntries.h"
17 #include "bolt/Profile/DataReader.h"
18 #include "bolt/Rewrite/BinaryPassManager.h"
19 #include "bolt/Rewrite/ExecutableFileMemoryManager.h"
20 #include "bolt/Rewrite/JITLinkLinker.h"
21 #include "bolt/Rewrite/RewriteInstance.h"
22 #include "bolt/RuntimeLibs/InstrumentationRuntimeLibrary.h"
23 #include "bolt/Utils/Utils.h"
24 #include "llvm/MC/MCObjectStreamer.h"
25 #include "llvm/Support/Errc.h"
26 #include "llvm/Support/FileSystem.h"
27 #include "llvm/Support/ToolOutputFile.h"
28 #include <memory>
29 #include <optional>
30 
31 namespace opts {
32 
33 using namespace llvm;
34 extern cl::opt<unsigned> AlignText;
35 //FIXME! Upstream change
36 //extern cl::opt<bool> CheckOverlappingElements;
37 extern cl::opt<bool> ForcePatch;
38 extern cl::opt<bool> Instrument;
39 extern cl::opt<bool> InstrumentCalls;
40 extern cl::opt<bolt::JumpTableSupportLevel> JumpTables;
41 extern cl::opt<bool> KeepTmp;
42 extern cl::opt<bool> NeverPrint;
43 extern cl::opt<std::string> OutputFilename;
44 extern cl::opt<bool> PrintAfterBranchFixup;
45 extern cl::opt<bool> PrintFinalized;
46 extern cl::opt<bool> PrintNormalized;
47 extern cl::opt<bool> PrintReordered;
48 extern cl::opt<bool> PrintSections;
49 extern cl::opt<bool> PrintDisasm;
50 extern cl::opt<bool> PrintCFG;
51 extern cl::opt<std::string> RuntimeInstrumentationLib;
52 extern cl::opt<unsigned> Verbosity;
53 } // namespace opts
54 
55 namespace llvm {
56 namespace bolt {
57 
58 #define DEBUG_TYPE "bolt"
59 
60 Expected<std::unique_ptr<MachORewriteInstance>>
61 MachORewriteInstance::create(object::MachOObjectFile *InputFile,
62                              StringRef ToolPath) {
63   Error Err = Error::success();
64   auto MachORI =
65       std::make_unique<MachORewriteInstance>(InputFile, ToolPath, Err);
66   if (Err)
67     return std::move(Err);
68   return std::move(MachORI);
69 }
70 
71 MachORewriteInstance::MachORewriteInstance(object::MachOObjectFile *InputFile,
72                                            StringRef ToolPath, Error &Err)
73     : InputFile(InputFile), ToolPath(ToolPath) {
74   ErrorAsOutParameter EAO(&Err);
75   auto BCOrErr = BinaryContext::createBinaryContext(
76       InputFile->makeTriple(), InputFile->getFileName(), nullptr,
77       /* IsPIC */ true, DWARFContext::create(*InputFile),
78       {llvm::outs(), llvm::errs()});
79   if (Error E = BCOrErr.takeError()) {
80     Err = std::move(E);
81     return;
82   }
83   BC = std::move(BCOrErr.get());
84   BC->initializeTarget(std::unique_ptr<MCPlusBuilder>(
85       createMCPlusBuilder(BC->TheTriple->getArch(), BC->MIA.get(),
86                           BC->MII.get(), BC->MRI.get(), BC->STI.get())));
87   if (opts::Instrument)
88     BC->setRuntimeLibrary(std::make_unique<InstrumentationRuntimeLibrary>());
89 }
90 
91 Error MachORewriteInstance::setProfile(StringRef Filename) {
92   if (!sys::fs::exists(Filename))
93     return errorCodeToError(make_error_code(errc::no_such_file_or_directory));
94 
95   if (ProfileReader) {
96     // Already exists
97     return make_error<StringError>(
98         Twine("multiple profiles specified: ") + ProfileReader->getFilename() +
99         " and " + Filename, inconvertibleErrorCode());
100   }
101 
102   ProfileReader = std::make_unique<DataReader>(Filename);
103   return Error::success();
104 }
105 
106 void MachORewriteInstance::preprocessProfileData() {
107   if (!ProfileReader)
108     return;
109   if (Error E = ProfileReader->preprocessProfile(*BC.get()))
110     report_error("cannot pre-process profile", std::move(E));
111 }
112 
113 void MachORewriteInstance::processProfileDataPreCFG() {
114   if (!ProfileReader)
115     return;
116   if (Error E = ProfileReader->readProfilePreCFG(*BC.get()))
117     report_error("cannot read profile pre-CFG", std::move(E));
118 }
119 
120 void MachORewriteInstance::processProfileData() {
121   if (!ProfileReader)
122     return;
123   if (Error E = ProfileReader->readProfile(*BC.get()))
124     report_error("cannot read profile", std::move(E));
125 }
126 
127 void MachORewriteInstance::readSpecialSections() {
128   for (const object::SectionRef &Section : InputFile->sections()) {
129     Expected<StringRef> SectionName = Section.getName();;
130     check_error(SectionName.takeError(), "cannot get section name");
131     // Only register sections with names.
132     if (!SectionName->empty()) {
133       BC->registerSection(Section);
134       LLVM_DEBUG(
135           dbgs() << "BOLT-DEBUG: registering section " << *SectionName
136                  << " @ 0x" << Twine::utohexstr(Section.getAddress()) << ":0x"
137                  << Twine::utohexstr(Section.getAddress() + Section.getSize())
138                  << "\n");
139     }
140   }
141 
142   if (opts::PrintSections) {
143     outs() << "BOLT-INFO: Sections from original binary:\n";
144     BC->printSections(outs());
145   }
146 }
147 
148 namespace {
149 
150 struct DataInCodeRegion {
151   explicit DataInCodeRegion(DiceRef D) {
152     D.getOffset(Offset);
153     D.getLength(Length);
154     D.getKind(Kind);
155   }
156 
157   uint32_t Offset;
158   uint16_t Length;
159   uint16_t Kind;
160 };
161 
162 std::vector<DataInCodeRegion> readDataInCode(const MachOObjectFile &O) {
163   const MachO::linkedit_data_command DataInCodeLC =
164       O.getDataInCodeLoadCommand();
165   const uint32_t NumberOfEntries =
166       DataInCodeLC.datasize / sizeof(MachO::data_in_code_entry);
167   std::vector<DataInCodeRegion> DataInCode;
168   DataInCode.reserve(NumberOfEntries);
169   for (auto I = O.begin_dices(), E = O.end_dices(); I != E; ++I)
170     DataInCode.emplace_back(*I);
171   llvm::stable_sort(DataInCode, [](DataInCodeRegion LHS, DataInCodeRegion RHS) {
172     return LHS.Offset < RHS.Offset;
173   });
174   return DataInCode;
175 }
176 
177 std::optional<uint64_t> readStartAddress(const MachOObjectFile &O) {
178   std::optional<uint64_t> StartOffset;
179   std::optional<uint64_t> TextVMAddr;
180   for (const object::MachOObjectFile::LoadCommandInfo &LC : O.load_commands()) {
181     switch (LC.C.cmd) {
182     case MachO::LC_MAIN: {
183       MachO::entry_point_command LCMain = O.getEntryPointCommand(LC);
184       StartOffset = LCMain.entryoff;
185       break;
186     }
187     case MachO::LC_SEGMENT: {
188       MachO::segment_command LCSeg = O.getSegmentLoadCommand(LC);
189       StringRef SegmentName(LCSeg.segname,
190                             strnlen(LCSeg.segname, sizeof(LCSeg.segname)));
191       if (SegmentName == "__TEXT")
192         TextVMAddr = LCSeg.vmaddr;
193       break;
194     }
195     case MachO::LC_SEGMENT_64: {
196       MachO::segment_command_64 LCSeg = O.getSegment64LoadCommand(LC);
197       StringRef SegmentName(LCSeg.segname,
198                             strnlen(LCSeg.segname, sizeof(LCSeg.segname)));
199       if (SegmentName == "__TEXT")
200         TextVMAddr = LCSeg.vmaddr;
201       break;
202     }
203     default:
204       continue;
205     }
206   }
207   return (TextVMAddr && StartOffset)
208              ? std::optional<uint64_t>(*TextVMAddr + *StartOffset)
209              : std::nullopt;
210 }
211 
212 } // anonymous namespace
213 
214 void MachORewriteInstance::discoverFileObjects() {
215   std::vector<SymbolRef> FunctionSymbols;
216   for (const SymbolRef &S : InputFile->symbols()) {
217     SymbolRef::Type Type = cantFail(S.getType(), "cannot get symbol type");
218     if (Type == SymbolRef::ST_Function)
219       FunctionSymbols.push_back(S);
220   }
221   if (FunctionSymbols.empty())
222     return;
223   llvm::stable_sort(
224       FunctionSymbols, [](const SymbolRef &LHS, const SymbolRef &RHS) {
225         return cantFail(LHS.getValue()) < cantFail(RHS.getValue());
226       });
227   for (size_t Index = 0; Index < FunctionSymbols.size(); ++Index) {
228     const uint64_t Address = cantFail(FunctionSymbols[Index].getValue());
229     ErrorOr<BinarySection &> Section = BC->getSectionForAddress(Address);
230     // TODO: It happens for some symbols (e.g. __mh_execute_header).
231     // Add proper logic to handle them correctly.
232     if (!Section) {
233       errs() << "BOLT-WARNING: no section found for address " << Address
234              << "\n";
235       continue;
236     }
237 
238     std::string SymbolName =
239         cantFail(FunctionSymbols[Index].getName(), "cannot get symbol name")
240             .str();
241     // Uniquify names of local symbols.
242     if (!(cantFail(FunctionSymbols[Index].getFlags()) & SymbolRef::SF_Global))
243       SymbolName = NR.uniquify(SymbolName);
244 
245     section_iterator S = cantFail(FunctionSymbols[Index].getSection());
246     uint64_t EndAddress = S->getAddress() + S->getSize();
247 
248     size_t NFIndex = Index + 1;
249     // Skip aliases.
250     while (NFIndex < FunctionSymbols.size() &&
251            cantFail(FunctionSymbols[NFIndex].getValue()) == Address)
252       ++NFIndex;
253     if (NFIndex < FunctionSymbols.size() &&
254         S == cantFail(FunctionSymbols[NFIndex].getSection()))
255       EndAddress = cantFail(FunctionSymbols[NFIndex].getValue());
256 
257     const uint64_t SymbolSize = EndAddress - Address;
258     const auto It = BC->getBinaryFunctions().find(Address);
259     if (It == BC->getBinaryFunctions().end()) {
260       BinaryFunction *Function = BC->createBinaryFunction(
261           std::move(SymbolName), *Section, Address, SymbolSize);
262       if (!opts::Instrument)
263         Function->setOutputAddress(Function->getAddress());
264 
265     } else {
266       It->second.addAlternativeName(std::move(SymbolName));
267     }
268   }
269 
270   const std::vector<DataInCodeRegion> DataInCode = readDataInCode(*InputFile);
271 
272   for (auto &BFI : BC->getBinaryFunctions()) {
273     BinaryFunction &Function = BFI.second;
274     Function.setMaxSize(Function.getSize());
275 
276     ErrorOr<ArrayRef<uint8_t>> FunctionData = Function.getData();
277     if (!FunctionData) {
278       errs() << "BOLT-ERROR: corresponding section is non-executable or "
279              << "empty for function " << Function << '\n';
280       continue;
281     }
282 
283     // Treat zero-sized functions as non-simple ones.
284     if (Function.getSize() == 0) {
285       Function.setSimple(false);
286       continue;
287     }
288 
289     // Offset of the function in the file.
290     const auto *FileBegin =
291         reinterpret_cast<const uint8_t *>(InputFile->getData().data());
292     Function.setFileOffset(FunctionData->begin() - FileBegin);
293 
294     // Treat functions which contain data in code as non-simple ones.
295     const auto It = std::lower_bound(
296         DataInCode.cbegin(), DataInCode.cend(), Function.getFileOffset(),
297         [](DataInCodeRegion D, uint64_t Offset) { return D.Offset < Offset; });
298     if (It != DataInCode.cend() &&
299         It->Offset + It->Length <=
300             Function.getFileOffset() + Function.getMaxSize())
301       Function.setSimple(false);
302   }
303 
304   BC->StartFunctionAddress = readStartAddress(*InputFile);
305 }
306 
307 void MachORewriteInstance::disassembleFunctions() {
308   for (auto &BFI : BC->getBinaryFunctions()) {
309     BinaryFunction &Function = BFI.second;
310     if (!Function.isSimple())
311       continue;
312     BC->logBOLTErrorsAndQuitOnFatal(Function.disassemble());
313     if (opts::PrintDisasm)
314       Function.print(outs(), "after disassembly");
315   }
316 }
317 
318 void MachORewriteInstance::buildFunctionsCFG() {
319   for (auto &BFI : BC->getBinaryFunctions()) {
320     BinaryFunction &Function = BFI.second;
321     if (!Function.isSimple())
322       continue;
323     BC->logBOLTErrorsAndQuitOnFatal(Function.buildCFG(/*AllocId*/ 0));
324   }
325 }
326 
327 void MachORewriteInstance::postProcessFunctions() {
328   for (auto &BFI : BC->getBinaryFunctions()) {
329     BinaryFunction &Function = BFI.second;
330     if (Function.empty())
331       continue;
332     Function.postProcessCFG();
333     if (opts::PrintCFG)
334       Function.print(outs(), "after building cfg");
335   }
336 }
337 
338 void MachORewriteInstance::runOptimizationPasses() {
339   BinaryFunctionPassManager Manager(*BC);
340   if (opts::Instrument) {
341     Manager.registerPass(std::make_unique<PatchEntries>());
342     Manager.registerPass(std::make_unique<Instrumentation>(opts::NeverPrint));
343   }
344 
345   Manager.registerPass(std::make_unique<ShortenInstructions>(opts::NeverPrint));
346 
347   Manager.registerPass(std::make_unique<RemoveNops>(opts::NeverPrint));
348 
349   Manager.registerPass(std::make_unique<NormalizeCFG>(opts::PrintNormalized));
350 
351   Manager.registerPass(
352       std::make_unique<ReorderBasicBlocks>(opts::PrintReordered));
353   Manager.registerPass(
354       std::make_unique<FixupBranches>(opts::PrintAfterBranchFixup));
355   // This pass should always run last.*
356   Manager.registerPass(
357       std::make_unique<FinalizeFunctions>(opts::PrintFinalized));
358 
359   BC->logBOLTErrorsAndQuitOnFatal(Manager.runPasses());
360 }
361 
362 void MachORewriteInstance::mapInstrumentationSection(
363     StringRef SectionName, BOLTLinker::SectionMapper MapSection) {
364   if (!opts::Instrument)
365     return;
366   ErrorOr<BinarySection &> Section = BC->getUniqueSectionByName(SectionName);
367   if (!Section) {
368     llvm::errs() << "Cannot find " + SectionName + " section\n";
369     exit(1);
370   }
371   if (!Section->hasValidSectionID())
372     return;
373   MapSection(*Section, Section->getAddress());
374 }
375 
376 void MachORewriteInstance::mapCodeSections(
377     BOLTLinker::SectionMapper MapSection) {
378   for (BinaryFunction *Function : BC->getAllBinaryFunctions()) {
379     if (!Function->isEmitted())
380       continue;
381     if (Function->getOutputAddress() == 0)
382       continue;
383     ErrorOr<BinarySection &> FuncSection = Function->getCodeSection();
384     if (!FuncSection)
385       report_error(
386           (Twine("Cannot find section for function ") + Function->getOneName())
387               .str(),
388           FuncSection.getError());
389 
390     FuncSection->setOutputAddress(Function->getOutputAddress());
391     LLVM_DEBUG(dbgs() << "BOLT: mapping 0x"
392                  << Twine::utohexstr(FuncSection->getAllocAddress()) << " to 0x"
393                  << Twine::utohexstr(Function->getOutputAddress()) << '\n');
394     MapSection(*FuncSection, Function->getOutputAddress());
395     Function->setImageAddress(FuncSection->getAllocAddress());
396     Function->setImageSize(FuncSection->getOutputSize());
397   }
398 
399   if (opts::Instrument) {
400     ErrorOr<BinarySection &> BOLT = BC->getUniqueSectionByName("__bolt");
401     if (!BOLT) {
402       llvm::errs() << "Cannot find __bolt section\n";
403       exit(1);
404     }
405     uint64_t Addr = BOLT->getAddress();
406     for (BinaryFunction *Function : BC->getAllBinaryFunctions()) {
407       if (!Function->isEmitted())
408         continue;
409       if (Function->getOutputAddress() != 0)
410         continue;
411       ErrorOr<BinarySection &> FuncSection = Function->getCodeSection();
412       assert(FuncSection && "cannot find section for function");
413       Addr = llvm::alignTo(Addr, 4);
414       FuncSection->setOutputAddress(Addr);
415       MapSection(*FuncSection, Addr);
416       Function->setFileOffset(Addr - BOLT->getAddress() +
417                               BOLT->getInputFileOffset());
418       Function->setImageAddress(FuncSection->getAllocAddress());
419       Function->setImageSize(FuncSection->getOutputSize());
420       BC->registerNameAtAddress(Function->getOneName(), Addr, 0, 0);
421       Addr += FuncSection->getOutputSize();
422     }
423   }
424 }
425 
426 void MachORewriteInstance::emitAndLink() {
427   std::error_code EC;
428   std::unique_ptr<::llvm::ToolOutputFile> TempOut =
429       std::make_unique<::llvm::ToolOutputFile>(
430           opts::OutputFilename + ".bolt.o", EC, sys::fs::OF_None);
431   check_error(EC, "cannot create output object file");
432 
433   if (opts::KeepTmp)
434     TempOut->keep();
435 
436   std::unique_ptr<buffer_ostream> BOS =
437       std::make_unique<buffer_ostream>(TempOut->os());
438   raw_pwrite_stream *OS = BOS.get();
439   auto Streamer = BC->createStreamer(*OS);
440 
441   emitBinaryContext(*Streamer, *BC, getOrgSecPrefix());
442   Streamer->finish();
443 
444   std::unique_ptr<MemoryBuffer> ObjectMemBuffer =
445       MemoryBuffer::getMemBuffer(BOS->str(), "in-memory object file", false);
446   std::unique_ptr<object::ObjectFile> Obj = cantFail(
447       object::ObjectFile::createObjectFile(ObjectMemBuffer->getMemBufferRef()),
448       "error creating in-memory object");
449   assert(Obj && "createObjectFile cannot return nullptr");
450 
451   auto EFMM = std::make_unique<ExecutableFileMemoryManager>(*BC);
452   EFMM->setNewSecPrefix(getNewSecPrefix());
453   EFMM->setOrgSecPrefix(getOrgSecPrefix());
454 
455   Linker = std::make_unique<JITLinkLinker>(*BC, std::move(EFMM));
456   Linker->loadObject(ObjectMemBuffer->getMemBufferRef(),
457                      [this](auto MapSection) {
458                        // Assign addresses to all sections. If key corresponds
459                        // to the object created by ourselves, call our regular
460                        // mapping function. If we are loading additional objects
461                        // as part of runtime libraries for instrumentation,
462                        // treat them as extra sections.
463                        mapCodeSections(MapSection);
464                        mapInstrumentationSection("__counters", MapSection);
465                        mapInstrumentationSection("__tables", MapSection);
466                      });
467 
468   // TODO: Refactor addRuntimeLibSections to work properly on Mach-O
469   // and use it here.
470   // if (auto *RtLibrary = BC->getRuntimeLibrary()) {
471   //   RtLibrary->link(*BC, ToolPath, *Linker, [this](auto MapSection) {
472   //     mapInstrumentationSection("I__setup", MapSection);
473   //     mapInstrumentationSection("I__fini", MapSection);
474   //     mapInstrumentationSection("I__data", MapSection);
475   //     mapInstrumentationSection("I__text", MapSection);
476   //     mapInstrumentationSection("I__cstring", MapSection);
477   //     mapInstrumentationSection("I__literal16", MapSection);
478   //   });
479   // }
480 }
481 
482 void MachORewriteInstance::writeInstrumentationSection(StringRef SectionName,
483                                                        raw_pwrite_stream &OS) {
484   if (!opts::Instrument)
485     return;
486   ErrorOr<BinarySection &> Section = BC->getUniqueSectionByName(SectionName);
487   if (!Section) {
488     llvm::errs() << "Cannot find " + SectionName + " section\n";
489     exit(1);
490   }
491   if (!Section->hasValidSectionID())
492     return;
493   assert(Section->getInputFileOffset() &&
494          "Section input offset cannot be zero");
495   assert(Section->getAllocAddress() && "Section alloc address cannot be zero");
496   assert(Section->getOutputSize() && "Section output size cannot be zero");
497   OS.pwrite(reinterpret_cast<char *>(Section->getAllocAddress()),
498             Section->getOutputSize(), Section->getInputFileOffset());
499 }
500 
501 void MachORewriteInstance::rewriteFile() {
502   std::error_code EC;
503   Out = std::make_unique<ToolOutputFile>(opts::OutputFilename, EC,
504                                          sys::fs::OF_None);
505   check_error(EC, "cannot create output executable file");
506   raw_fd_ostream &OS = Out->os();
507   OS << InputFile->getData();
508 
509   for (auto &BFI : BC->getBinaryFunctions()) {
510     BinaryFunction &Function = BFI.second;
511     if (!Function.isSimple())
512       continue;
513     assert(Function.isEmitted() && "Simple function has not been emitted");
514     if (!opts::Instrument && (Function.getImageSize() > Function.getMaxSize()))
515       continue;
516     if (opts::Verbosity >= 2)
517       outs() << "BOLT: rewriting function \"" << Function << "\"\n";
518     OS.pwrite(reinterpret_cast<char *>(Function.getImageAddress()),
519               Function.getImageSize(), Function.getFileOffset());
520   }
521 
522   for (const BinaryFunction *Function : BC->getInjectedBinaryFunctions()) {
523     OS.pwrite(reinterpret_cast<char *>(Function->getImageAddress()),
524               Function->getImageSize(), Function->getFileOffset());
525   }
526 
527   writeInstrumentationSection("__counters", OS);
528   writeInstrumentationSection("__tables", OS);
529 
530   // TODO: Refactor addRuntimeLibSections to work properly on Mach-O and
531   // use it here.
532   writeInstrumentationSection("I__setup", OS);
533   writeInstrumentationSection("I__fini", OS);
534   writeInstrumentationSection("I__data", OS);
535   writeInstrumentationSection("I__text", OS);
536   writeInstrumentationSection("I__cstring", OS);
537   writeInstrumentationSection("I__literal16", OS);
538 
539   Out->keep();
540   EC = sys::fs::setPermissions(
541       opts::OutputFilename,
542       static_cast<sys::fs::perms>(sys::fs::perms::all_all &
543                                   ~sys::fs::getUmask()));
544   check_error(EC, "cannot set permissions of output file");
545 }
546 
547 void MachORewriteInstance::adjustCommandLineOptions() {
548 //FIXME! Upstream change
549 //  opts::CheckOverlappingElements = false;
550   if (!opts::AlignText.getNumOccurrences())
551     opts::AlignText = BC->PageAlign;
552   if (opts::Instrument.getNumOccurrences())
553     opts::ForcePatch = true;
554   opts::JumpTables = JTS_MOVE;
555   opts::InstrumentCalls = false;
556   opts::RuntimeInstrumentationLib = "libbolt_rt_instr_osx.a";
557 }
558 
559 void MachORewriteInstance::run() {
560   adjustCommandLineOptions();
561 
562   readSpecialSections();
563 
564   discoverFileObjects();
565 
566   preprocessProfileData();
567 
568   disassembleFunctions();
569 
570   processProfileDataPreCFG();
571 
572   buildFunctionsCFG();
573 
574   processProfileData();
575 
576   postProcessFunctions();
577 
578   runOptimizationPasses();
579 
580   emitAndLink();
581 
582   rewriteFile();
583 }
584 
585 MachORewriteInstance::~MachORewriteInstance() {}
586 
587 } // namespace bolt
588 } // namespace llvm
589