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

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

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