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