1//===- bolt/Rewrite/RewriteInstance.h - ELF rewriter ------------*- C++ -*-===//
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// Interface to control an instance of a binary rewriting process.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef BOLT_REWRITE_REWRITE_INSTANCE_H
14#define BOLT_REWRITE_REWRITE_INSTANCE_H
15
16#include "bolt/Core/BinaryContext.h"
17#include "bolt/Core/Linker.h"
18#include "bolt/Rewrite/MetadataManager.h"
19#include "bolt/Utils/NameResolver.h"
20#include "llvm/MC/StringTableBuilder.h"
21#include "llvm/Object/ELFObjectFile.h"
22#include "llvm/Object/ObjectFile.h"
23#include "llvm/Support/Error.h"
24#include <map>
25#include <set>
26#include <unordered_map>
27
28namespace llvm {
29
30class ToolOutputFile;
31
32namespace bolt {
33
34class BoltAddressTranslation;
35class CFIReaderWriter;
36class DWARFRewriter;
37class ProfileReaderBase;
38
39/// This class encapsulates all data necessary to carry on binary reading,
40/// disassembly, CFG building, BB reordering (among other binary-level
41/// optimizations) and rewriting. It also has the logic to coordinate such
42/// events.
43class RewriteInstance {
44public:
45 // This constructor has complex initialization that can fail during
46 // construction. Constructors can’t return errors, so clients must test \p Err
47 // after the object is constructed. Use `create` method instead.
48 RewriteInstance(llvm::object::ELFObjectFileBase *File, const int Argc,
49 const char *const *Argv, StringRef ToolPath,
50 raw_ostream &Stdout, raw_ostream &Stderr, Error &Err);
51
52 static Expected<std::unique_ptr<RewriteInstance>>
53 create(llvm::object::ELFObjectFileBase *File, const int Argc,
54 const char *const *Argv, StringRef ToolPath,
55 raw_ostream &Stdout = llvm::outs(),
56 raw_ostream &Stderr = llvm::errs());
57 ~RewriteInstance();
58
59 /// Assign profile from \p Filename to this instance.
60 Error setProfile(StringRef Filename);
61
62 /// Run all the necessary steps to read, optimize and rewrite the binary.
63 Error run();
64
65 /// Diff this instance against another one. Non-const since we may run passes
66 /// to fold identical functions.
67 void compare(RewriteInstance &RI2);
68
69 /// Return binary context.
70 const BinaryContext &getBinaryContext() const { return *BC; }
71
72 /// Return total score of all functions for this instance.
73 uint64_t getTotalScore() const { return BC->TotalScore; }
74
75 /// Return the name of the input file.
76 StringRef getInputFilename() const {
77 assert(InputFile && "cannot have an instance without a file");
78 return InputFile->getFileName();
79 }
80
81 /// Set the build-id string if we did not fail to parse the contents of the
82 /// ELF note section containing build-id information.
83 void parseBuildID();
84
85 /// The build-id is typically a stream of 20 bytes. Return these bytes in
86 /// printable hexadecimal form if they are available, or std::nullopt
87 /// otherwise.
88 std::optional<std::string> getPrintableBuildID() const;
89
90 /// If this instance uses a profile, return appropriate profile reader.
91 const ProfileReaderBase *getProfileReader() const {
92 return ProfileReader.get();
93 }
94
95private:
96 /// Populate array of binary functions and other objects of interest
97 /// from meta data in the file.
98 void discoverFileObjects();
99
100 /// Check whether we should use DT_FINI or DT_FINI_ARRAY for instrumentation.
101 /// DT_FINI is preferred; DT_FINI_ARRAY is only used when no DT_FINI entry was
102 /// found.
103 Error discoverRtFiniAddress();
104
105 /// If DT_FINI_ARRAY is used for instrumentation, update the relocation of its
106 /// first entry to point to the instrumentation library's fini address.
107 void updateRtFiniReloc();
108
109 /// Create and initialize metadata rewriters for this instance.
110 void initializeMetadataManager();
111
112 /// Process fragments, locate parent functions.
113 void registerFragments();
114
115 /// Read info from special sections. E.g. eh_frame and .gcc_except_table
116 /// for exception and stack unwinding information.
117 Error readSpecialSections();
118
119 /// Adjust supplied command-line options based on input data.
120 void adjustCommandLineOptions();
121
122 /// Process runtime relocations.
123 void processDynamicRelocations();
124
125 /// Process input relocations.
126 void processRelocations();
127
128 /// Read relocations from a given section.
129 void readDynamicRelocations(const object::SectionRef &Section, bool IsJmpRel);
130
131 /// Read relocations from a given RELR section.
132 void readDynamicRelrRelocations(BinarySection &Section);
133
134 /// Print relocation information.
135 void printRelocationInfo(const RelocationRef &Rel, StringRef SymbolName,
136 uint64_t SymbolAddress, uint64_t Addend,
137 uint64_t ExtractedValue) const;
138
139 /// Read relocations from a given section.
140 void readRelocations(const object::SectionRef &Section);
141
142 /// Handle one relocation.
143 void handleRelocation(const object::SectionRef &RelocatedSection,
144 const RelocationRef &Rel);
145
146 /// Mark functions that are not meant for processing as ignored.
147 void selectFunctionsToProcess();
148
149 /// Read information from debug sections.
150 void readDebugInfo();
151
152 /// Read profile data without having disassembled functions available.
153 void preprocessProfileData();
154
155 void processProfileDataPreCFG();
156
157 /// Associate profile data with functions and data objects.
158 void processProfileData();
159
160 /// Disassemble each function in the binary and associate it with a
161 /// BinaryFunction object, preparing all information necessary for binary
162 /// optimization.
163 void disassembleFunctions();
164
165 void buildFunctionsCFG();
166
167 void postProcessFunctions();
168
169 void preregisterSections();
170
171 /// Run optimizations that operate at the binary, or post-linker, level.
172 void runOptimizationPasses();
173
174 /// Write code and data into an intermediary object file, map virtual to real
175 /// addresses and link the object file, resolving all relocations and
176 /// performing final relaxation.
177 void emitAndLink();
178
179 /// Link additional runtime code to support instrumentation.
180 void linkRuntime();
181
182 /// Process metadata in special sections before CFG is built for functions.
183 void processMetadataPreCFG();
184
185 /// Process metadata in special sections after CFG is built for functions.
186 void processMetadataPostCFG();
187
188 /// Make changes to metadata before the binary is emitted.
189 void finalizeMetadataPreEmit();
190
191 /// Update debug and other auxiliary information in the file.
192 void updateMetadata();
193
194 /// Return the list of code sections in the output order.
195 std::vector<BinarySection *> getCodeSections();
196
197 /// Map all sections to their final addresses.
198 void mapFileSections(BOLTLinker::SectionMapper MapSection);
199
200 /// Map code sections generated by BOLT.
201 void mapCodeSections(BOLTLinker::SectionMapper MapSection);
202
203 /// Map the rest of allocatable sections.
204 void mapAllocatableSections(BOLTLinker::SectionMapper MapSection);
205
206 /// Update output object's values based on the final \p Layout.
207 void updateOutputValues(const BOLTLinker &Linker);
208
209 /// Rewrite back all functions (hopefully optimized) that fit in the original
210 /// memory footprint for that function. If the function is now larger and does
211 /// not fit in the binary, reject it and preserve the original version of the
212 /// function. If we couldn't understand the function for some reason in
213 /// disassembleFunctions(), also preserve the original version.
214 void rewriteFile();
215
216 /// Return address of a function in the new binary corresponding to
217 /// \p OldAddress address in the original binary.
218 uint64_t getNewFunctionAddress(uint64_t OldAddress);
219
220 /// Return address of a function or moved data in the new binary
221 /// corresponding to \p OldAddress address in the original binary.
222 uint64_t getNewFunctionOrDataAddress(uint64_t OldAddress);
223
224 /// Return value for the symbol \p Name in the output.
225 uint64_t getNewValueForSymbol(const StringRef Name);
226
227 /// Check for PT_GNU_RELRO segment presence, mark covered sections as
228 /// (dynamically) read-only (written once), as specified in LSB Chapter 12:
229 /// "segment which may be made read-only after relocations have been
230 /// processed".
231 void markGnuRelroSections();
232
233 /// Detect addresses and offsets available in the binary for allocating
234 /// new sections.
235 Error discoverStorage();
236
237 /// Adjust function sizes and set proper maximum size values after the whole
238 /// symbol table has been processed.
239 void adjustFunctionBoundaries();
240
241 /// Make .eh_frame section relocatable.
242 void relocateEHFrameSection();
243
244 /// Analyze relocation \p Rel.
245 /// Return true if the relocation was successfully processed, false otherwise.
246 /// The \p SymbolName, \p SymbolAddress, \p Addend and \p ExtractedValue
247 /// parameters will be set on success. The \p Skip argument indicates
248 /// that the relocation was analyzed, but it must not be processed.
249 bool analyzeRelocation(const object::RelocationRef &Rel, uint64_t &RType,
250 std::string &SymbolName, bool &IsSectionRelocation,
251 uint64_t &SymbolAddress, int64_t &Addend,
252 uint64_t &ExtractedValue, bool &Skip) const;
253
254 /// Rewrite non-allocatable sections with modifications.
255 void rewriteNoteSections();
256
257 /// Write .eh_frame_hdr.
258 void writeEHFrameHeader();
259
260 /// Disassemble and create function entries for PLT.
261 void disassemblePLT();
262
263 /// Auxiliary function to create .plt BinaryFunction on \p EntryAddres
264 /// with the \p EntrySize size. \p TargetAddress is the .got entry
265 /// associated address.
266 void createPLTBinaryFunction(uint64_t TargetAddress, uint64_t EntryAddress,
267 uint64_t EntrySize);
268
269 /// Disassemble PLT instruction.
270 void disassemblePLTInstruction(const BinarySection &Section,
271 uint64_t InstrOffset, MCInst &Instruction,
272 uint64_t &InstrSize);
273
274 /// Disassemble aarch64-specific .plt \p Section auxiliary function
275 void disassemblePLTSectionAArch64(BinarySection &Section);
276
277 /// Disassemble X86-specific .plt \p Section auxiliary function. \p EntrySize
278 /// is the expected .plt \p Section entry function size.
279 void disassemblePLTSectionX86(BinarySection &Section, uint64_t EntrySize);
280
281 /// Disassemble riscv-specific .plt \p Section auxiliary function
282 void disassemblePLTSectionRISCV(BinarySection &Section);
283
284 /// ELF-specific part. TODO: refactor into new class.
285#define ELF_FUNCTION(TYPE, FUNC) \
286 template <typename ELFT> TYPE FUNC(object::ELFObjectFile<ELFT> *Obj); \
287 TYPE FUNC() { \
288 if (auto *ELF32LE = dyn_cast<object::ELF32LEObjectFile>(InputFile)) \
289 return FUNC(ELF32LE); \
290 if (auto *ELF64LE = dyn_cast<object::ELF64LEObjectFile>(InputFile)) \
291 return FUNC(ELF64LE); \
292 if (auto *ELF32BE = dyn_cast<object::ELF32BEObjectFile>(InputFile)) \
293 return FUNC(ELF32BE); \
294 auto *ELF64BE = cast<object::ELF64BEObjectFile>(InputFile); \
295 return FUNC(ELF64BE); \
296 }
297
298 /// Patch ELF book-keeping info.
299 void patchELFPHDRTable();
300
301 /// Create section header table.
302 ELF_FUNCTION(void, patchELFSectionHeaderTable);
303
304 /// Create the regular symbol table and patch dyn symbol tables.
305 ELF_FUNCTION(void, patchELFSymTabs);
306
307 /// Read dynamic section/segment of ELF.
308 ELF_FUNCTION(Error, readELFDynamic);
309
310 /// Patch dynamic section/segment of ELF.
311 ELF_FUNCTION(void, patchELFDynamic);
312
313 /// Patch .got
314 ELF_FUNCTION(void, patchELFGOT);
315
316 /// Patch allocatable relocation sections.
317 ELF_FUNCTION(void, patchELFAllocatableRelaSections);
318
319 /// Patch allocatable relr section.
320 ELF_FUNCTION(void, patchELFAllocatableRelrSection);
321
322 /// Finalize memory image of section header string table.
323 ELF_FUNCTION(void, finalizeSectionStringTable);
324
325 /// Return a list of all sections to include in the output binary.
326 /// Populate \p NewSectionIndex with a map of input to output indices.
327 template <typename ELFT>
328 std::vector<typename object::ELFObjectFile<ELFT>::Elf_Shdr>
329 getOutputSections(object::ELFObjectFile<ELFT> *File,
330 std::vector<uint32_t> &NewSectionIndex);
331
332 /// Return true if \p Section should be stripped from the output binary.
333 template <typename ELFShdrTy>
334 bool shouldStrip(const ELFShdrTy &Section, StringRef SectionName);
335
336 /// Write ELF symbol table using \p Write and \p AddToStrTab functions
337 /// based on the input file symbol table passed in \p SymTabSection.
338 /// \p IsDynSym is set to true for dynamic symbol table since we
339 /// are updating it in-place with minimal modifications.
340 template <typename ELFT, typename WriteFuncTy, typename StrTabFuncTy>
341 void updateELFSymbolTable(
342 object::ELFObjectFile<ELFT> *File, bool IsDynSym,
343 const typename object::ELFObjectFile<ELFT>::Elf_Shdr &SymTabSection,
344 const std::vector<uint32_t> &NewSectionIndex, WriteFuncTy Write,
345 StrTabFuncTy AddToStrTab);
346
347 /// Get output index in dynamic symbol table.
348 uint32_t getOutputDynamicSymbolIndex(const MCSymbol *Symbol) {
349 auto It = SymbolIndex.find(x: Symbol);
350 if (It != SymbolIndex.end())
351 return It->second;
352 return 0;
353 }
354
355 /// Add a notes section containing the BOLT revision and command line options.
356 void addBoltInfoSection();
357
358 /// Add a notes section containing the serialized BOLT Address Translation
359 /// maps that can be used to enable sampling of the output binary for the
360 /// purpose of generating BOLT profile data for the input binary.
361 void addBATSection();
362
363 /// Loop over now emitted functions to write translation maps
364 void encodeBATSection();
365
366 /// Update the ELF note section containing the binary build-id to reflect
367 /// a new build-id, so tools can differentiate between the old and the
368 /// rewritten binary.
369 void patchBuildID();
370
371 /// Return file offset corresponding to a virtual \p Address.
372 /// Return 0 if the address has no mapping in the file, including being
373 /// part of .bss section.
374 uint64_t getFileOffsetForAddress(uint64_t Address) const;
375
376 /// Return true if we will overwrite contents of the section instead
377 /// of appending contents to it.
378 bool willOverwriteSection(StringRef SectionName);
379
380public:
381 /// Standard ELF sections we overwrite.
382 static constexpr const char *SectionsToOverwrite[] = {
383 ".shstrtab",
384 ".symtab",
385 ".strtab",
386 };
387
388 /// Debug section to we overwrite while updating the debug info.
389 static std::vector<std::string> DebugSectionsToOverwrite;
390
391 /// Return true if the section holds debug information.
392 static bool isDebugSection(StringRef SectionName);
393
394 /// Adds Debug section to overwrite.
395 static void addToDebugSectionsToOverwrite(const char *Section) {
396 DebugSectionsToOverwrite.emplace_back(args&: Section);
397 }
398
399private:
400 /// Manage a pipeline of metadata handlers.
401 class MetadataManager MetadataManager;
402
403 static const char TimerGroupName[];
404
405 static const char TimerGroupDesc[];
406
407 /// Alignment value used for .eh_frame_hdr.
408 static constexpr uint64_t EHFrameHdrAlign = 4;
409
410 /// Sections created by BOLT will have an internal name that starts with the
411 /// following prefix. Note that the prefix is used for a section lookup
412 /// internally and the section name in the output might be different.
413 static StringRef getNewSecPrefix() { return ".bolt.new"; }
414
415 /// String to be added before the original section name.
416 ///
417 /// When BOLT creates a new section with the same name as the one in the
418 /// input file, it may need to preserve the original section. This prefix
419 /// will be added to the name of the original section.
420 static StringRef getOrgSecPrefix() { return ".bolt.org"; }
421
422 /// Section name used for extra BOLT code in addition to .text.
423 static StringRef getBOLTTextSectionName() { return ".bolt.text"; }
424
425 /// Common section names.
426 static StringRef getEHFrameSectionName() { return ".eh_frame"; }
427 static StringRef getRelaDynSectionName() { return ".rela.dyn"; }
428
429 /// An instance of the input binary we are processing, externally owned.
430 llvm::object::ELFObjectFileBase *InputFile;
431
432 /// Command line args used to process binary.
433 const int Argc;
434 const char *const *Argv;
435 StringRef ToolPath;
436
437 std::unique_ptr<ProfileReaderBase> ProfileReader;
438
439 std::unique_ptr<BinaryContext> BC;
440 std::unique_ptr<CFIReaderWriter> CFIRdWrt;
441
442 // Run ExecutionEngine linker with custom memory manager and symbol resolver.
443 std::unique_ptr<BOLTLinker> Linker;
444
445 /// Output file where we mix original code from the input binary and
446 /// optimized code for selected functions.
447 std::unique_ptr<ToolOutputFile> Out;
448
449 /// Offset in the input file where non-allocatable sections start.
450 uint64_t FirstNonAllocatableOffset{0};
451
452 /// Information about program header table.
453 uint64_t PHDRTableAddress{0};
454 uint64_t PHDRTableOffset{0};
455 unsigned Phnum{0};
456
457 /// New code segment info.
458 uint64_t NewTextSegmentAddress{0};
459 uint64_t NewTextSegmentOffset{0};
460 uint64_t NewTextSegmentSize{0};
461
462 /// New writable segment info.
463 uint64_t NewWritableSegmentAddress{0};
464 uint64_t NewWritableSegmentSize{0};
465
466 /// Track next available address for new allocatable sections.
467 uint64_t NextAvailableAddress{0};
468
469 /// Location and size of dynamic relocations.
470 std::optional<uint64_t> DynamicRelocationsAddress;
471 uint64_t DynamicRelocationsSize{0};
472 uint64_t DynamicRelativeRelocationsCount{0};
473
474 // Location and size of .relr.dyn relocations.
475 std::optional<uint64_t> DynamicRelrAddress;
476 uint64_t DynamicRelrSize{0};
477 uint64_t DynamicRelrEntrySize{0};
478
479 /// PLT relocations are special kind of dynamic relocations stored separately.
480 std::optional<uint64_t> PLTRelocationsAddress;
481 uint64_t PLTRelocationsSize{0};
482
483 /// True if relocation of specified type came from .rela.plt
484 DenseMap<uint64_t, bool> IsJmpRelocation;
485
486 /// Index of specified symbol in the dynamic symbol table. NOTE Currently it
487 /// is filled and used only with the relocations-related symbols.
488 std::unordered_map<const MCSymbol *, uint32_t> SymbolIndex;
489
490 /// Store all non-zero symbols in this map for a quick address lookup.
491 std::map<uint64_t, llvm::object::SymbolRef> FileSymRefs;
492
493 std::unique_ptr<DWARFRewriter> DebugInfoRewriter;
494
495 std::unique_ptr<BoltAddressTranslation> BAT;
496
497 /// Number of local symbols in newly written symbol table.
498 uint64_t NumLocalSymbols{0};
499
500 /// Information on special Procedure Linkage Table sections. There are
501 /// multiple variants generated by different linkers.
502 struct PLTSectionInfo {
503 const char *Name;
504 uint64_t EntrySize{0};
505 };
506
507 /// Different types of X86-64 PLT sections.
508 const PLTSectionInfo X86_64_PLTSections[4] = {
509 { .Name: ".plt", .EntrySize: 16 },
510 { .Name: ".plt.got", .EntrySize: 8 },
511 { .Name: ".plt.sec", .EntrySize: 8 },
512 { .Name: nullptr, .EntrySize: 0 }
513 };
514
515 /// AArch64 PLT sections.
516 const PLTSectionInfo AArch64_PLTSections[4] = {
517 {.Name: ".plt"}, {.Name: ".plt.got"}, {.Name: ".iplt"}, {.Name: nullptr}};
518
519 /// RISCV PLT sections.
520 const PLTSectionInfo RISCV_PLTSections[2] = {{.Name: ".plt"}, {.Name: nullptr}};
521
522 /// Return PLT information for a section with \p SectionName or nullptr
523 /// if the section is not PLT.
524 const PLTSectionInfo *getPLTSectionInfo(StringRef SectionName) {
525 const PLTSectionInfo *PLTSI = nullptr;
526 switch (BC->TheTriple->getArch()) {
527 default:
528 break;
529 case Triple::x86_64:
530 PLTSI = X86_64_PLTSections;
531 break;
532 case Triple::aarch64:
533 PLTSI = AArch64_PLTSections;
534 break;
535 case Triple::riscv64:
536 PLTSI = RISCV_PLTSections;
537 break;
538 }
539 for (; PLTSI && PLTSI->Name; ++PLTSI)
540 if (SectionName == PLTSI->Name)
541 return PLTSI;
542
543 return nullptr;
544 }
545
546 /// Exception handling and stack unwinding information in this binary.
547 ErrorOr<BinarySection &> EHFrameSection{std::errc::bad_address};
548
549 /// .note.gnu.build-id section.
550 ErrorOr<BinarySection &> BuildIDSection{std::errc::bad_address};
551
552 /// Helper for accessing sections by name.
553 BinarySection *getSection(const Twine &Name) {
554 ErrorOr<BinarySection &> ErrOrSection = BC->getUniqueSectionByName(SectionName: Name);
555 return ErrOrSection ? &ErrOrSection.get() : nullptr;
556 }
557
558 /// A reference to the build-id bytes in the original binary
559 StringRef BuildID;
560
561 /// Keep track of functions we fail to write in the binary. We need to avoid
562 /// rewriting CFI info for these functions.
563 std::vector<uint64_t> FailedAddresses;
564
565 /// Keep track of which functions didn't fit in their original space in the
566 /// last emission, so that we may either decide to split or not optimize them.
567 std::set<uint64_t> LargeFunctions;
568
569 /// Section header string table.
570 StringTableBuilder SHStrTab;
571
572 /// A rewrite of strtab
573 std::string NewStrTab;
574
575 /// Number of processed to data relocations. Used to implement the
576 /// -max-relocations debugging option.
577 uint64_t NumDataRelocations{0};
578
579 /// Number of failed to process relocations.
580 uint64_t NumFailedRelocations{0};
581
582 NameResolver NR;
583
584 friend class RewriteInstanceDiff;
585};
586
587MCPlusBuilder *createMCPlusBuilder(const Triple::ArchType Arch,
588 const MCInstrAnalysis *Analysis,
589 const MCInstrInfo *Info,
590 const MCRegisterInfo *RegInfo,
591 const MCSubtargetInfo *STI);
592
593} // namespace bolt
594} // namespace llvm
595
596#endif
597

source code of bolt/include/bolt/Rewrite/RewriteInstance.h