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