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 #include <optional> 29 30 namespace opts { 31 32 using namespace llvm; 33 extern cl::opt<unsigned> AlignText; 34 //FIXME! Upstream change 35 //extern cl::opt<bool> CheckOverlappingElements; 36 extern cl::opt<bool> ForcePatch; 37 extern cl::opt<bool> Instrument; 38 extern cl::opt<bool> InstrumentCalls; 39 extern cl::opt<bolt::JumpTableSupportLevel> JumpTables; 40 extern cl::opt<bool> KeepTmp; 41 extern cl::opt<bool> NeverPrint; 42 extern cl::opt<std::string> OutputFilename; 43 extern cl::opt<bool> PrintAfterBranchFixup; 44 extern cl::opt<bool> PrintFinalized; 45 extern cl::opt<bool> PrintNormalized; 46 extern cl::opt<bool> PrintReordered; 47 extern cl::opt<bool> PrintSections; 48 extern cl::opt<bool> PrintDisasm; 49 extern cl::opt<bool> PrintCFG; 50 extern cl::opt<std::string> RuntimeInstrumentationLib; 51 extern cl::opt<unsigned> Verbosity; 52 } // namespace opts 53 54 namespace llvm { 55 namespace bolt { 56 57 extern MCPlusBuilder *createX86MCPlusBuilder(const MCInstrAnalysis *, 58 const MCInstrInfo *, 59 const MCRegisterInfo *); 60 extern MCPlusBuilder *createAArch64MCPlusBuilder(const MCInstrAnalysis *, 61 const MCInstrInfo *, 62 const MCRegisterInfo *); 63 64 namespace { 65 66 MCPlusBuilder *createMCPlusBuilder(const Triple::ArchType Arch, 67 const MCInstrAnalysis *Analysis, 68 const MCInstrInfo *Info, 69 const MCRegisterInfo *RegInfo) { 70 #ifdef X86_AVAILABLE 71 if (Arch == Triple::x86_64) 72 return createX86MCPlusBuilder(Analysis, Info, RegInfo); 73 #endif 74 75 #ifdef AARCH64_AVAILABLE 76 if (Arch == Triple::aarch64) 77 return createAArch64MCPlusBuilder(Analysis, Info, RegInfo); 78 #endif 79 80 llvm_unreachable("architecture unsupported by MCPlusBuilder"); 81 } 82 83 } // anonymous namespace 84 85 #define DEBUG_TYPE "bolt" 86 87 Expected<std::unique_ptr<MachORewriteInstance>> 88 MachORewriteInstance::createMachORewriteInstance( 89 object::MachOObjectFile *InputFile, StringRef ToolPath) { 90 Error Err = Error::success(); 91 auto MachORI = 92 std::make_unique<MachORewriteInstance>(InputFile, ToolPath, Err); 93 if (Err) 94 return std::move(Err); 95 return std::move(MachORI); 96 } 97 98 MachORewriteInstance::MachORewriteInstance(object::MachOObjectFile *InputFile, 99 StringRef ToolPath, Error &Err) 100 : InputFile(InputFile), ToolPath(ToolPath) { 101 ErrorAsOutParameter EAO(&Err); 102 auto BCOrErr = BinaryContext::createBinaryContext( 103 InputFile, /* IsPIC */ true, DWARFContext::create(*InputFile)); 104 if (Error E = BCOrErr.takeError()) { 105 Err = std::move(E); 106 return; 107 } 108 BC = std::move(BCOrErr.get()); 109 BC->initializeTarget(std::unique_ptr<MCPlusBuilder>(createMCPlusBuilder( 110 BC->TheTriple->getArch(), BC->MIA.get(), BC->MII.get(), BC->MRI.get()))); 111 if (opts::Instrument) 112 BC->setRuntimeLibrary(std::make_unique<InstrumentationRuntimeLibrary>()); 113 } 114 115 Error MachORewriteInstance::setProfile(StringRef Filename) { 116 if (!sys::fs::exists(Filename)) 117 return errorCodeToError(make_error_code(errc::no_such_file_or_directory)); 118 119 if (ProfileReader) { 120 // Already exists 121 return make_error<StringError>( 122 Twine("multiple profiles specified: ") + ProfileReader->getFilename() + 123 " and " + Filename, inconvertibleErrorCode()); 124 } 125 126 ProfileReader = std::make_unique<DataReader>(Filename); 127 return Error::success(); 128 } 129 130 void MachORewriteInstance::preprocessProfileData() { 131 if (!ProfileReader) 132 return; 133 if (Error E = ProfileReader->preprocessProfile(*BC.get())) 134 report_error("cannot pre-process profile", std::move(E)); 135 } 136 137 void MachORewriteInstance::processProfileDataPreCFG() { 138 if (!ProfileReader) 139 return; 140 if (Error E = ProfileReader->readProfilePreCFG(*BC.get())) 141 report_error("cannot read profile pre-CFG", std::move(E)); 142 } 143 144 void MachORewriteInstance::processProfileData() { 145 if (!ProfileReader) 146 return; 147 if (Error E = ProfileReader->readProfile(*BC.get())) 148 report_error("cannot read profile", std::move(E)); 149 } 150 151 void MachORewriteInstance::readSpecialSections() { 152 for (const object::SectionRef &Section : InputFile->sections()) { 153 Expected<StringRef> SectionName = Section.getName();; 154 check_error(SectionName.takeError(), "cannot get section name"); 155 // Only register sections with names. 156 if (!SectionName->empty()) { 157 BC->registerSection(Section); 158 LLVM_DEBUG( 159 dbgs() << "BOLT-DEBUG: registering section " << *SectionName 160 << " @ 0x" << Twine::utohexstr(Section.getAddress()) << ":0x" 161 << Twine::utohexstr(Section.getAddress() + Section.getSize()) 162 << "\n"); 163 } 164 } 165 166 if (opts::PrintSections) { 167 outs() << "BOLT-INFO: Sections from original binary:\n"; 168 BC->printSections(outs()); 169 } 170 } 171 172 namespace { 173 174 struct DataInCodeRegion { 175 explicit DataInCodeRegion(DiceRef D) { 176 D.getOffset(Offset); 177 D.getLength(Length); 178 D.getKind(Kind); 179 } 180 181 uint32_t Offset; 182 uint16_t Length; 183 uint16_t Kind; 184 }; 185 186 std::vector<DataInCodeRegion> readDataInCode(const MachOObjectFile &O) { 187 const MachO::linkedit_data_command DataInCodeLC = 188 O.getDataInCodeLoadCommand(); 189 const uint32_t NumberOfEntries = 190 DataInCodeLC.datasize / sizeof(MachO::data_in_code_entry); 191 std::vector<DataInCodeRegion> DataInCode; 192 DataInCode.reserve(NumberOfEntries); 193 for (auto I = O.begin_dices(), E = O.end_dices(); I != E; ++I) 194 DataInCode.emplace_back(*I); 195 llvm::stable_sort(DataInCode, [](DataInCodeRegion LHS, DataInCodeRegion RHS) { 196 return LHS.Offset < RHS.Offset; 197 }); 198 return DataInCode; 199 } 200 201 std::optional<uint64_t> readStartAddress(const MachOObjectFile &O) { 202 std::optional<uint64_t> StartOffset; 203 std::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 ? std::optional<uint64_t>(*TextVMAddr + *StartOffset) 233 : std::nullopt; 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 llvm::stable_sort( 248 FunctionSymbols, [](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"); 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"); 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 BC->EFMM->setOrgSecPrefix(getOrgSecPrefix()); 513 BC->EFMM->setNewSecPrefix(getNewSecPrefix()); 514 515 RTDyld.reset(new decltype(RTDyld)::element_type(*BC->EFMM, Resolver)); 516 RTDyld->setProcessAllSections(true); 517 RTDyld->loadObject(*Obj); 518 if (RTDyld->hasError()) { 519 outs() << "BOLT-ERROR: RTDyld failed.\n"; 520 exit(1); 521 } 522 523 // Assign addresses to all sections. If key corresponds to the object 524 // created by ourselves, call our regular mapping function. If we are 525 // loading additional objects as part of runtime libraries for 526 // instrumentation, treat them as extra sections. 527 mapCodeSections(); 528 mapInstrumentationSection("__counters"); 529 mapInstrumentationSection("__tables"); 530 531 // TODO: Refactor addRuntimeLibSections to work properly on Mach-O 532 // and use it here. 533 //FIXME! Put this in RtLibrary->link 534 // mapInstrumentationSection("I__setup"); 535 // mapInstrumentationSection("I__fini"); 536 // mapInstrumentationSection("I__data"); 537 // mapInstrumentationSection("I__text"); 538 // mapInstrumentationSection("I__cstring"); 539 // mapInstrumentationSection("I__literal16"); 540 541 // if (auto *RtLibrary = BC->getRuntimeLibrary()) { 542 // RtLibrary->link(*BC, ToolPath, *ES, *OLT); 543 // } 544 } 545 546 void MachORewriteInstance::writeInstrumentationSection(StringRef SectionName, 547 raw_pwrite_stream &OS) { 548 if (!opts::Instrument) 549 return; 550 ErrorOr<BinarySection &> Section = BC->getUniqueSectionByName(SectionName); 551 if (!Section) { 552 llvm::errs() << "Cannot find " + SectionName + " section\n"; 553 exit(1); 554 } 555 if (!Section->hasValidSectionID()) 556 return; 557 assert(Section->getInputFileOffset() && 558 "Section input offset cannot be zero"); 559 assert(Section->getAllocAddress() && "Section alloc address cannot be zero"); 560 assert(Section->getOutputSize() && "Section output size cannot be zero"); 561 OS.pwrite(reinterpret_cast<char *>(Section->getAllocAddress()), 562 Section->getOutputSize(), Section->getInputFileOffset()); 563 } 564 565 void MachORewriteInstance::rewriteFile() { 566 std::error_code EC; 567 Out = std::make_unique<ToolOutputFile>(opts::OutputFilename, EC, 568 sys::fs::OF_None); 569 check_error(EC, "cannot create output executable file"); 570 raw_fd_ostream &OS = Out->os(); 571 OS << InputFile->getData(); 572 573 for (auto &BFI : BC->getBinaryFunctions()) { 574 BinaryFunction &Function = BFI.second; 575 if (!Function.isSimple()) 576 continue; 577 assert(Function.isEmitted() && "Simple function has not been emitted"); 578 if (!opts::Instrument && (Function.getImageSize() > Function.getMaxSize())) 579 continue; 580 if (opts::Verbosity >= 2) 581 outs() << "BOLT: rewriting function \"" << Function << "\"\n"; 582 OS.pwrite(reinterpret_cast<char *>(Function.getImageAddress()), 583 Function.getImageSize(), Function.getFileOffset()); 584 } 585 586 for (const BinaryFunction *Function : BC->getInjectedBinaryFunctions()) { 587 OS.pwrite(reinterpret_cast<char *>(Function->getImageAddress()), 588 Function->getImageSize(), Function->getFileOffset()); 589 } 590 591 writeInstrumentationSection("__counters", OS); 592 writeInstrumentationSection("__tables", OS); 593 594 // TODO: Refactor addRuntimeLibSections to work properly on Mach-O and 595 // use it here. 596 writeInstrumentationSection("I__setup", OS); 597 writeInstrumentationSection("I__fini", OS); 598 writeInstrumentationSection("I__data", OS); 599 writeInstrumentationSection("I__text", OS); 600 writeInstrumentationSection("I__cstring", OS); 601 writeInstrumentationSection("I__literal16", OS); 602 603 Out->keep(); 604 EC = sys::fs::setPermissions(opts::OutputFilename, 605 sys::fs::perms::all_all); 606 check_error(EC, "cannot set permissions of output file"); 607 } 608 609 void MachORewriteInstance::adjustCommandLineOptions() { 610 //FIXME! Upstream change 611 // opts::CheckOverlappingElements = false; 612 if (!opts::AlignText.getNumOccurrences()) 613 opts::AlignText = BC->PageAlign; 614 if (opts::Instrument.getNumOccurrences()) 615 opts::ForcePatch = true; 616 opts::JumpTables = JTS_MOVE; 617 opts::InstrumentCalls = false; 618 opts::RuntimeInstrumentationLib = "libbolt_rt_instr_osx.a"; 619 } 620 621 void MachORewriteInstance::run() { 622 adjustCommandLineOptions(); 623 624 readSpecialSections(); 625 626 discoverFileObjects(); 627 628 preprocessProfileData(); 629 630 disassembleFunctions(); 631 632 processProfileDataPreCFG(); 633 634 buildFunctionsCFG(); 635 636 processProfileData(); 637 638 postProcessFunctions(); 639 640 runOptimizationPasses(); 641 642 emitAndLink(); 643 644 rewriteFile(); 645 } 646 647 MachORewriteInstance::~MachORewriteInstance() {} 648 649 } // namespace bolt 650 } // namespace llvm 651