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