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