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