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
createMCPlusBuilder(const Triple::ArchType Arch,const MCInstrAnalysis * Analysis,const MCInstrInfo * Info,const MCRegisterInfo * RegInfo)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>>
createMachORewriteInstance(object::MachOObjectFile * InputFile,StringRef ToolPath)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
MachORewriteInstance(object::MachOObjectFile * InputFile,StringRef ToolPath,Error & Err)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
setProfile(StringRef Filename)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
preprocessProfileData()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
processProfileDataPreCFG()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
processProfileData()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
readSpecialSections()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 {
DataInCodeRegionllvm::bolt::__anonf2314c260211::DataInCodeRegion174 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
readDataInCode(const MachOObjectFile & O)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
readStartAddress(const MachOObjectFile & O)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 : llvm::None;
233 }
234
235 } // anonymous namespace
236
discoverFileObjects()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
disassembleFunctions()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", true);
338 }
339 }
340
buildFunctionsCFG()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
postProcessFunctions()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", true);
361 }
362 }
363
runOptimizationPasses()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
mapInstrumentationSection(StringRef SectionName)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
mapCodeSections()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:
BOLTSymbolResolver(BinaryContext & BC)457 BOLTSymbolResolver(BinaryContext &BC) : BC(BC) {}
458
findSymbolInLogicalDylib(const std::string & Name)459 JITSymbol findSymbolInLogicalDylib(const std::string &Name) override {
460 return JITSymbol(nullptr);
461 }
462
findSymbol(const std::string & Name)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
emitAndLink()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
512 RTDyld.reset(new decltype(RTDyld)::element_type(*BC->EFMM, Resolver));
513 RTDyld->setProcessAllSections(true);
514 RTDyld->loadObject(*Obj);
515 if (RTDyld->hasError()) {
516 outs() << "BOLT-ERROR: RTDyld failed.\n";
517 exit(1);
518 }
519
520 // Assign addresses to all sections. If key corresponds to the object
521 // created by ourselves, call our regular mapping function. If we are
522 // loading additional objects as part of runtime libraries for
523 // instrumentation, treat them as extra sections.
524 mapCodeSections();
525 mapInstrumentationSection("__counters");
526 mapInstrumentationSection("__tables");
527
528 // TODO: Refactor addRuntimeLibSections to work properly on Mach-O
529 // and use it here.
530 //FIXME! Put this in RtLibrary->link
531 // mapInstrumentationSection("I__setup");
532 // mapInstrumentationSection("I__fini");
533 // mapInstrumentationSection("I__data");
534 // mapInstrumentationSection("I__text");
535 // mapInstrumentationSection("I__cstring");
536 // mapInstrumentationSection("I__literal16");
537
538 // if (auto *RtLibrary = BC->getRuntimeLibrary()) {
539 // RtLibrary->link(*BC, ToolPath, *ES, *OLT);
540 // }
541 }
542
writeInstrumentationSection(StringRef SectionName,raw_pwrite_stream & OS)543 void MachORewriteInstance::writeInstrumentationSection(StringRef SectionName,
544 raw_pwrite_stream &OS) {
545 if (!opts::Instrument)
546 return;
547 ErrorOr<BinarySection &> Section = BC->getUniqueSectionByName(SectionName);
548 if (!Section) {
549 llvm::errs() << "Cannot find " + SectionName + " section\n";
550 exit(1);
551 }
552 if (!Section->hasValidSectionID())
553 return;
554 assert(Section->getInputFileOffset() &&
555 "Section input offset cannot be zero");
556 assert(Section->getAllocAddress() && "Section alloc address cannot be zero");
557 assert(Section->getOutputSize() && "Section output size cannot be zero");
558 OS.pwrite(reinterpret_cast<char *>(Section->getAllocAddress()),
559 Section->getOutputSize(), Section->getInputFileOffset());
560 }
561
rewriteFile()562 void MachORewriteInstance::rewriteFile() {
563 std::error_code EC;
564 Out = std::make_unique<ToolOutputFile>(opts::OutputFilename, EC,
565 sys::fs::OF_None);
566 check_error(EC, "cannot create output executable file");
567 raw_fd_ostream &OS = Out->os();
568 OS << InputFile->getData();
569
570 for (auto &BFI : BC->getBinaryFunctions()) {
571 BinaryFunction &Function = BFI.second;
572 if (!Function.isSimple())
573 continue;
574 assert(Function.isEmitted() && "Simple function has not been emitted");
575 if (!opts::Instrument && (Function.getImageSize() > Function.getMaxSize()))
576 continue;
577 if (opts::Verbosity >= 2)
578 outs() << "BOLT: rewriting function \"" << Function << "\"\n";
579 OS.pwrite(reinterpret_cast<char *>(Function.getImageAddress()),
580 Function.getImageSize(), Function.getFileOffset());
581 }
582
583 for (const BinaryFunction *Function : BC->getInjectedBinaryFunctions()) {
584 OS.pwrite(reinterpret_cast<char *>(Function->getImageAddress()),
585 Function->getImageSize(), Function->getFileOffset());
586 }
587
588 writeInstrumentationSection("__counters", OS);
589 writeInstrumentationSection("__tables", OS);
590
591 // TODO: Refactor addRuntimeLibSections to work properly on Mach-O and
592 // use it here.
593 writeInstrumentationSection("I__setup", OS);
594 writeInstrumentationSection("I__fini", OS);
595 writeInstrumentationSection("I__data", OS);
596 writeInstrumentationSection("I__text", OS);
597 writeInstrumentationSection("I__cstring", OS);
598 writeInstrumentationSection("I__literal16", OS);
599
600 Out->keep();
601 EC = sys::fs::setPermissions(opts::OutputFilename,
602 sys::fs::perms::all_all);
603 check_error(EC, "cannot set permissions of output file");
604 }
605
adjustCommandLineOptions()606 void MachORewriteInstance::adjustCommandLineOptions() {
607 //FIXME! Upstream change
608 // opts::CheckOverlappingElements = false;
609 if (!opts::AlignText.getNumOccurrences())
610 opts::AlignText = BC->PageAlign;
611 if (opts::Instrument.getNumOccurrences())
612 opts::ForcePatch = true;
613 opts::JumpTables = JTS_MOVE;
614 opts::InstrumentCalls = false;
615 opts::RuntimeInstrumentationLib = "libbolt_rt_instr_osx.a";
616 }
617
run()618 void MachORewriteInstance::run() {
619 adjustCommandLineOptions();
620
621 readSpecialSections();
622
623 discoverFileObjects();
624
625 preprocessProfileData();
626
627 disassembleFunctions();
628
629 processProfileDataPreCFG();
630
631 buildFunctionsCFG();
632
633 processProfileData();
634
635 postProcessFunctions();
636
637 runOptimizationPasses();
638
639 emitAndLink();
640
641 rewriteFile();
642 }
643
~MachORewriteInstance()644 MachORewriteInstance::~MachORewriteInstance() {}
645
646 } // namespace bolt
647 } // namespace llvm
648