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