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

source code of bolt/lib/Rewrite/MachORewriteInstance.cpp