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