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 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>> 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 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 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 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 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 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 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 { 174 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 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 std::stable_sort(DataInCode.begin(), DataInCode.end(), 195 [](DataInCodeRegion LHS, DataInCodeRegion RHS) { 196 return LHS.Offset < RHS.Offset; 197 }); 198 return DataInCode; 199 } 200 201 Optional<uint64_t> readStartAddress(const MachOObjectFile &O) { 202 Optional<uint64_t> StartOffset; 203 Optional<uint64_t> TextVMAddr; 204 for (const object::MachOObjectFile::LoadCommandInfo &LC : O.load_commands()) { 205 switch (LC.C.cmd) { 206 case MachO::LC_MAIN: { 207 MachO::entry_point_command LCMain = O.getEntryPointCommand(LC); 208 StartOffset = LCMain.entryoff; 209 break; 210 } 211 case MachO::LC_SEGMENT: { 212 MachO::segment_command LCSeg = O.getSegmentLoadCommand(LC); 213 StringRef SegmentName(LCSeg.segname, 214 strnlen(LCSeg.segname, sizeof(LCSeg.segname))); 215 if (SegmentName == "__TEXT") 216 TextVMAddr = LCSeg.vmaddr; 217 break; 218 } 219 case MachO::LC_SEGMENT_64: { 220 MachO::segment_command_64 LCSeg = O.getSegment64LoadCommand(LC); 221 StringRef SegmentName(LCSeg.segname, 222 strnlen(LCSeg.segname, sizeof(LCSeg.segname))); 223 if (SegmentName == "__TEXT") 224 TextVMAddr = LCSeg.vmaddr; 225 break; 226 } 227 default: 228 continue; 229 } 230 } 231 return (TextVMAddr && StartOffset) 232 ? Optional<uint64_t>(*TextVMAddr + *StartOffset) 233 : llvm::None; 234 } 235 236 } // anonymous namespace 237 238 void MachORewriteInstance::discoverFileObjects() { 239 std::vector<SymbolRef> FunctionSymbols; 240 for (const SymbolRef &S : InputFile->symbols()) { 241 SymbolRef::Type Type = cantFail(S.getType(), "cannot get symbol type"); 242 if (Type == SymbolRef::ST_Function) 243 FunctionSymbols.push_back(S); 244 } 245 if (FunctionSymbols.empty()) 246 return; 247 std::stable_sort(FunctionSymbols.begin(), FunctionSymbols.end(), 248 [](const SymbolRef &LHS, const SymbolRef &RHS) { 249 return cantFail(LHS.getValue()) < cantFail(RHS.getValue()); 250 }); 251 for (size_t Index = 0; Index < FunctionSymbols.size(); ++Index) { 252 const uint64_t Address = cantFail(FunctionSymbols[Index].getValue()); 253 ErrorOr<BinarySection &> Section = BC->getSectionForAddress(Address); 254 // TODO: It happens for some symbols (e.g. __mh_execute_header). 255 // Add proper logic to handle them correctly. 256 if (!Section) { 257 errs() << "BOLT-WARNING: no section found for address " << Address 258 << "\n"; 259 continue; 260 } 261 262 std::string SymbolName = 263 cantFail(FunctionSymbols[Index].getName(), "cannot get symbol name") 264 .str(); 265 // Uniquify names of local symbols. 266 if (!(cantFail(FunctionSymbols[Index].getFlags()) & SymbolRef::SF_Global)) 267 SymbolName = NR.uniquify(SymbolName); 268 269 section_iterator S = cantFail(FunctionSymbols[Index].getSection()); 270 uint64_t EndAddress = S->getAddress() + S->getSize(); 271 272 size_t NFIndex = Index + 1; 273 // Skip aliases. 274 while (NFIndex < FunctionSymbols.size() && 275 cantFail(FunctionSymbols[NFIndex].getValue()) == Address) 276 ++NFIndex; 277 if (NFIndex < FunctionSymbols.size() && 278 S == cantFail(FunctionSymbols[NFIndex].getSection())) 279 EndAddress = cantFail(FunctionSymbols[NFIndex].getValue()); 280 281 const uint64_t SymbolSize = EndAddress - Address; 282 const auto It = BC->getBinaryFunctions().find(Address); 283 if (It == BC->getBinaryFunctions().end()) { 284 BinaryFunction *Function = BC->createBinaryFunction( 285 std::move(SymbolName), *Section, Address, SymbolSize); 286 if (!opts::Instrument) 287 Function->setOutputAddress(Function->getAddress()); 288 289 } else { 290 It->second.addAlternativeName(std::move(SymbolName)); 291 } 292 } 293 294 const std::vector<DataInCodeRegion> DataInCode = readDataInCode(*InputFile); 295 296 for (auto &BFI : BC->getBinaryFunctions()) { 297 BinaryFunction &Function = BFI.second; 298 Function.setMaxSize(Function.getSize()); 299 300 ErrorOr<ArrayRef<uint8_t>> FunctionData = Function.getData(); 301 if (!FunctionData) { 302 errs() << "BOLT-ERROR: corresponding section is non-executable or " 303 << "empty for function " << Function << '\n'; 304 continue; 305 } 306 307 // Treat zero-sized functions as non-simple ones. 308 if (Function.getSize() == 0) { 309 Function.setSimple(false); 310 continue; 311 } 312 313 // Offset of the function in the file. 314 const auto *FileBegin = 315 reinterpret_cast<const uint8_t *>(InputFile->getData().data()); 316 Function.setFileOffset(FunctionData->begin() - FileBegin); 317 318 // Treat functions which contain data in code as non-simple ones. 319 const auto It = std::lower_bound( 320 DataInCode.cbegin(), DataInCode.cend(), Function.getFileOffset(), 321 [](DataInCodeRegion D, uint64_t Offset) { return D.Offset < Offset; }); 322 if (It != DataInCode.cend() && 323 It->Offset + It->Length <= 324 Function.getFileOffset() + Function.getMaxSize()) 325 Function.setSimple(false); 326 } 327 328 BC->StartFunctionAddress = readStartAddress(*InputFile); 329 } 330 331 void MachORewriteInstance::disassembleFunctions() { 332 for (auto &BFI : BC->getBinaryFunctions()) { 333 BinaryFunction &Function = BFI.second; 334 if (!Function.isSimple()) 335 continue; 336 Function.disassemble(); 337 if (opts::PrintDisasm) 338 Function.print(outs(), "after disassembly", true); 339 } 340 } 341 342 void MachORewriteInstance::buildFunctionsCFG() { 343 for (auto &BFI : BC->getBinaryFunctions()) { 344 BinaryFunction &Function = BFI.second; 345 if (!Function.isSimple()) 346 continue; 347 if (!Function.buildCFG(/*AllocId*/ 0)) { 348 errs() << "BOLT-WARNING: failed to build CFG for the function " 349 << Function << "\n"; 350 } 351 } 352 } 353 354 void MachORewriteInstance::postProcessFunctions() { 355 for (auto &BFI : BC->getBinaryFunctions()) { 356 BinaryFunction &Function = BFI.second; 357 if (Function.empty()) 358 continue; 359 Function.postProcessCFG(); 360 if (opts::PrintCFG) 361 Function.print(outs(), "after building cfg", true); 362 } 363 } 364 365 void MachORewriteInstance::runOptimizationPasses() { 366 BinaryFunctionPassManager Manager(*BC); 367 if (opts::Instrument) { 368 Manager.registerPass(std::make_unique<PatchEntries>()); 369 Manager.registerPass(std::make_unique<Instrumentation>(opts::NeverPrint)); 370 } 371 372 Manager.registerPass(std::make_unique<ShortenInstructions>(opts::NeverPrint)); 373 374 Manager.registerPass(std::make_unique<RemoveNops>(opts::NeverPrint)); 375 376 Manager.registerPass(std::make_unique<NormalizeCFG>(opts::PrintNormalized)); 377 378 Manager.registerPass( 379 std::make_unique<ReorderBasicBlocks>(opts::PrintReordered)); 380 Manager.registerPass( 381 std::make_unique<FixupBranches>(opts::PrintAfterBranchFixup)); 382 // This pass should always run last.* 383 Manager.registerPass( 384 std::make_unique<FinalizeFunctions>(opts::PrintFinalized)); 385 386 Manager.runPasses(); 387 } 388 389 void MachORewriteInstance::mapInstrumentationSection(StringRef SectionName) { 390 if (!opts::Instrument) 391 return; 392 ErrorOr<BinarySection &> Section = BC->getUniqueSectionByName(SectionName); 393 if (!Section) { 394 llvm::errs() << "Cannot find " + SectionName + " section\n"; 395 exit(1); 396 } 397 if (!Section->hasValidSectionID()) 398 return; 399 RTDyld->reassignSectionAddress(Section->getSectionID(), 400 Section->getAddress()); 401 } 402 403 void MachORewriteInstance::mapCodeSections() { 404 for (BinaryFunction *Function : BC->getAllBinaryFunctions()) { 405 if (!Function->isEmitted()) 406 continue; 407 if (Function->getOutputAddress() == 0) 408 continue; 409 ErrorOr<BinarySection &> FuncSection = Function->getCodeSection(); 410 if (!FuncSection) 411 report_error( 412 (Twine("Cannot find section for function ") + Function->getOneName()) 413 .str(), 414 FuncSection.getError()); 415 416 FuncSection->setOutputAddress(Function->getOutputAddress()); 417 LLVM_DEBUG(dbgs() << "BOLT: mapping 0x" 418 << Twine::utohexstr(FuncSection->getAllocAddress()) << " to 0x" 419 << Twine::utohexstr(Function->getOutputAddress()) << '\n'); 420 RTDyld->reassignSectionAddress(FuncSection->getSectionID(), 421 Function->getOutputAddress()); 422 Function->setImageAddress(FuncSection->getAllocAddress()); 423 Function->setImageSize(FuncSection->getOutputSize()); 424 } 425 426 if (opts::Instrument) { 427 ErrorOr<BinarySection &> BOLT = BC->getUniqueSectionByName("__bolt"); 428 if (!BOLT) { 429 llvm::errs() << "Cannot find __bolt section\n"; 430 exit(1); 431 } 432 uint64_t Addr = BOLT->getAddress(); 433 for (BinaryFunction *Function : BC->getAllBinaryFunctions()) { 434 if (!Function->isEmitted()) 435 continue; 436 if (Function->getOutputAddress() != 0) 437 continue; 438 ErrorOr<BinarySection &> FuncSection = Function->getCodeSection(); 439 assert(FuncSection && "cannot find section for function"); 440 Addr = llvm::alignTo(Addr, 4); 441 FuncSection->setOutputAddress(Addr); 442 RTDyld->reassignSectionAddress(FuncSection->getSectionID(), Addr); 443 Function->setFileOffset(Addr - BOLT->getAddress() + 444 BOLT->getInputFileOffset()); 445 Function->setImageAddress(FuncSection->getAllocAddress()); 446 Function->setImageSize(FuncSection->getOutputSize()); 447 BC->registerNameAtAddress(Function->getOneName(), Addr, 0, 0); 448 Addr += FuncSection->getOutputSize(); 449 } 450 } 451 } 452 453 namespace { 454 455 class BOLTSymbolResolver : public LegacyJITSymbolResolver { 456 BinaryContext &BC; 457 public: 458 BOLTSymbolResolver(BinaryContext &BC) : BC(BC) {} 459 460 JITSymbol findSymbolInLogicalDylib(const std::string &Name) override { 461 return JITSymbol(nullptr); 462 } 463 464 JITSymbol findSymbol(const std::string &Name) override { 465 LLVM_DEBUG(dbgs() << "BOLT: looking for " << Name << "\n"); 466 if (BinaryData *I = BC.getBinaryDataByName(Name)) { 467 const uint64_t Address = I->isMoved() && !I->isJumpTable() 468 ? I->getOutputAddress() 469 : I->getAddress(); 470 LLVM_DEBUG(dbgs() << "Resolved to address 0x" << Twine::utohexstr(Address) 471 << "\n"); 472 return JITSymbol(Address, JITSymbolFlags()); 473 } 474 LLVM_DEBUG(dbgs() << "Resolved to address 0x0\n"); 475 return JITSymbol(nullptr); 476 } 477 }; 478 479 } // end anonymous namespace 480 481 void MachORewriteInstance::emitAndLink() { 482 std::error_code EC; 483 std::unique_ptr<::llvm::ToolOutputFile> TempOut = 484 std::make_unique<::llvm::ToolOutputFile>( 485 opts::OutputFilename + ".bolt.o", EC, sys::fs::OF_None); 486 check_error(EC, "cannot create output object file"); 487 488 if (opts::KeepTmp) 489 TempOut->keep(); 490 491 std::unique_ptr<buffer_ostream> BOS = 492 std::make_unique<buffer_ostream>(TempOut->os()); 493 raw_pwrite_stream *OS = BOS.get(); 494 auto Streamer = BC->createStreamer(*OS); 495 496 emitBinaryContext(*Streamer, *BC, getOrgSecPrefix()); 497 Streamer->finish(); 498 499 std::unique_ptr<MemoryBuffer> ObjectMemBuffer = 500 MemoryBuffer::getMemBuffer(BOS->str(), "in-memory object file", false); 501 std::unique_ptr<object::ObjectFile> Obj = cantFail( 502 object::ObjectFile::createObjectFile(ObjectMemBuffer->getMemBufferRef()), 503 "error creating in-memory object"); 504 assert(Obj && "createObjectFile cannot return nullptr"); 505 506 BOLTSymbolResolver Resolver = BOLTSymbolResolver(*BC); 507 508 MCAsmLayout FinalLayout( 509 static_cast<MCObjectStreamer *>(Streamer.get())->getAssembler()); 510 511 BC->EFMM.reset(new ExecutableFileMemoryManager(*BC, /*AllowStubs*/ false)); 512 513 RTDyld.reset(new decltype(RTDyld)::element_type(*BC->EFMM, Resolver)); 514 RTDyld->setProcessAllSections(true); 515 RTDyld->loadObject(*Obj); 516 if (RTDyld->hasError()) { 517 outs() << "BOLT-ERROR: RTDyld failed.\n"; 518 exit(1); 519 } 520 521 // Assign addresses to all sections. If key corresponds to the object 522 // created by ourselves, call our regular mapping function. If we are 523 // loading additional objects as part of runtime libraries for 524 // instrumentation, treat them as extra sections. 525 mapCodeSections(); 526 mapInstrumentationSection("__counters"); 527 mapInstrumentationSection("__tables"); 528 529 // TODO: Refactor addRuntimeLibSections to work properly on Mach-O 530 // and use it here. 531 //FIXME! Put this in RtLibrary->link 532 // mapInstrumentationSection("I__setup"); 533 // mapInstrumentationSection("I__fini"); 534 // mapInstrumentationSection("I__data"); 535 // mapInstrumentationSection("I__text"); 536 // mapInstrumentationSection("I__cstring"); 537 // mapInstrumentationSection("I__literal16"); 538 539 // if (auto *RtLibrary = BC->getRuntimeLibrary()) { 540 // RtLibrary->link(*BC, ToolPath, *ES, *OLT); 541 // } 542 } 543 544 void MachORewriteInstance::writeInstrumentationSection(StringRef SectionName, 545 raw_pwrite_stream &OS) { 546 if (!opts::Instrument) 547 return; 548 ErrorOr<BinarySection &> Section = BC->getUniqueSectionByName(SectionName); 549 if (!Section) { 550 llvm::errs() << "Cannot find " + SectionName + " section\n"; 551 exit(1); 552 } 553 if (!Section->hasValidSectionID()) 554 return; 555 assert(Section->getInputFileOffset() && 556 "Section input offset cannot be zero"); 557 assert(Section->getAllocAddress() && "Section alloc address cannot be zero"); 558 assert(Section->getOutputSize() && "Section output size cannot be zero"); 559 OS.pwrite(reinterpret_cast<char *>(Section->getAllocAddress()), 560 Section->getOutputSize(), Section->getInputFileOffset()); 561 } 562 563 void MachORewriteInstance::rewriteFile() { 564 std::error_code EC; 565 Out = std::make_unique<ToolOutputFile>(opts::OutputFilename, EC, 566 sys::fs::OF_None); 567 check_error(EC, "cannot create output executable file"); 568 raw_fd_ostream &OS = Out->os(); 569 OS << InputFile->getData(); 570 571 for (auto &BFI : BC->getBinaryFunctions()) { 572 BinaryFunction &Function = BFI.second; 573 if (!Function.isSimple()) 574 continue; 575 assert(Function.isEmitted() && "Simple function has not been emitted"); 576 if (!opts::Instrument && (Function.getImageSize() > Function.getMaxSize())) 577 continue; 578 if (opts::Verbosity >= 2) 579 outs() << "BOLT: rewriting function \"" << Function << "\"\n"; 580 OS.pwrite(reinterpret_cast<char *>(Function.getImageAddress()), 581 Function.getImageSize(), Function.getFileOffset()); 582 } 583 584 for (const BinaryFunction *Function : BC->getInjectedBinaryFunctions()) { 585 OS.pwrite(reinterpret_cast<char *>(Function->getImageAddress()), 586 Function->getImageSize(), Function->getFileOffset()); 587 } 588 589 writeInstrumentationSection("__counters", OS); 590 writeInstrumentationSection("__tables", OS); 591 592 // TODO: Refactor addRuntimeLibSections to work properly on Mach-O and 593 // use it here. 594 writeInstrumentationSection("I__setup", OS); 595 writeInstrumentationSection("I__fini", OS); 596 writeInstrumentationSection("I__data", OS); 597 writeInstrumentationSection("I__text", OS); 598 writeInstrumentationSection("I__cstring", OS); 599 writeInstrumentationSection("I__literal16", OS); 600 601 Out->keep(); 602 EC = sys::fs::setPermissions(opts::OutputFilename, 603 sys::fs::perms::all_all); 604 check_error(EC, "cannot set permissions of output file"); 605 } 606 607 void MachORewriteInstance::adjustCommandLineOptions() { 608 //FIXME! Upstream change 609 // opts::CheckOverlappingElements = false; 610 if (!opts::AlignText.getNumOccurrences()) 611 opts::AlignText = BC->PageAlign; 612 if (opts::Instrument.getNumOccurrences()) 613 opts::ForcePatch = true; 614 opts::JumpTables = JTS_MOVE; 615 opts::InstrumentCalls = false; 616 opts::RuntimeInstrumentationLib = "libbolt_rt_instr_osx.a"; 617 } 618 619 void MachORewriteInstance::run() { 620 adjustCommandLineOptions(); 621 622 readSpecialSections(); 623 624 discoverFileObjects(); 625 626 preprocessProfileData(); 627 628 disassembleFunctions(); 629 630 processProfileDataPreCFG(); 631 632 buildFunctionsCFG(); 633 634 processProfileData(); 635 636 postProcessFunctions(); 637 638 runOptimizationPasses(); 639 640 emitAndLink(); 641 642 rewriteFile(); 643 } 644 645 MachORewriteInstance::~MachORewriteInstance() {} 646 647 } // namespace bolt 648 } // namespace llvm 649