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