1 | //===- bolt/Core/AddressMap.cpp - Input-output Address Map ----------------===// |
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/Core/AddressMap.h" |
10 | #include "bolt/Core/BinaryContext.h" |
11 | #include "bolt/Core/BinaryFunction.h" |
12 | #include "bolt/Core/BinarySection.h" |
13 | #include "llvm/MC/MCStreamer.h" |
14 | #include "llvm/Support/DataExtractor.h" |
15 | |
16 | namespace llvm { |
17 | namespace bolt { |
18 | |
19 | const char *const AddressMap::AddressSectionName = ".bolt.addr2addr_map" ; |
20 | const char *const AddressMap::LabelSectionName = ".bolt.label2addr_map" ; |
21 | |
22 | static void emitAddress(MCStreamer &Streamer, uint64_t InputAddress, |
23 | const MCSymbol *OutputLabel) { |
24 | Streamer.emitIntValue(Value: InputAddress, Size: 8); |
25 | Streamer.emitSymbolValue(Sym: OutputLabel, Size: 8); |
26 | } |
27 | |
28 | static void emitLabel(MCStreamer &Streamer, const MCSymbol *OutputLabel) { |
29 | Streamer.emitIntValue(Value: reinterpret_cast<uint64_t>(OutputLabel), Size: 8); |
30 | Streamer.emitSymbolValue(Sym: OutputLabel, Size: 8); |
31 | } |
32 | |
33 | void AddressMap::emit(MCStreamer &Streamer, BinaryContext &BC) { |
34 | // Mark map sections as link-only to avoid allocation in the output file. |
35 | const unsigned Flags = BinarySection::getFlags(/*IsReadOnly*/ true, |
36 | /*IsText*/ false, |
37 | /*IsAllocatable*/ true); |
38 | BC.registerOrUpdateSection(Name: AddressSectionName, ELFType: ELF::SHT_PROGBITS, ELFFlags: Flags) |
39 | .setLinkOnly(); |
40 | BC.registerOrUpdateSection(Name: LabelSectionName, ELFType: ELF::SHT_PROGBITS, ELFFlags: Flags) |
41 | .setLinkOnly(); |
42 | |
43 | for (const auto &[BFAddress, BF] : BC.getBinaryFunctions()) { |
44 | if (!BF.requiresAddressMap()) |
45 | continue; |
46 | |
47 | for (const auto &BB : BF) { |
48 | if (!BB.getLabel()->isDefined()) |
49 | continue; |
50 | |
51 | Streamer.switchSection(Section: BC.getDataSection(SectionName: LabelSectionName)); |
52 | emitLabel(Streamer, OutputLabel: BB.getLabel()); |
53 | |
54 | if (!BB.hasLocSyms()) |
55 | continue; |
56 | |
57 | Streamer.switchSection(Section: BC.getDataSection(SectionName: AddressSectionName)); |
58 | for (auto [Offset, Symbol] : BB.getLocSyms()) |
59 | emitAddress(Streamer, InputAddress: BFAddress + Offset, OutputLabel: Symbol); |
60 | } |
61 | } |
62 | } |
63 | |
64 | std::optional<AddressMap> AddressMap::parse(BinaryContext &BC) { |
65 | auto AddressMapSection = BC.getUniqueSectionByName(SectionName: AddressSectionName); |
66 | auto LabelMapSection = BC.getUniqueSectionByName(SectionName: LabelSectionName); |
67 | |
68 | if (!AddressMapSection && !LabelMapSection) |
69 | return std::nullopt; |
70 | |
71 | AddressMap Parsed; |
72 | |
73 | const size_t EntrySize = 2 * BC.AsmInfo->getCodePointerSize(); |
74 | auto parseSection = |
75 | [&](BinarySection &Section, |
76 | function_ref<void(uint64_t, uint64_t)> InsertCallback) { |
77 | StringRef Buffer = Section.getOutputContents(); |
78 | assert(Buffer.size() % EntrySize == 0 && "Unexpected address map size" ); |
79 | |
80 | DataExtractor DE(Buffer, BC.AsmInfo->isLittleEndian(), |
81 | BC.AsmInfo->getCodePointerSize()); |
82 | DataExtractor::Cursor Cursor(0); |
83 | |
84 | while (Cursor && !DE.eof(C: Cursor)) { |
85 | const uint64_t Input = DE.getAddress(C&: Cursor); |
86 | const uint64_t Output = DE.getAddress(C&: Cursor); |
87 | InsertCallback(Input, Output); |
88 | } |
89 | |
90 | assert(Cursor && "Error reading address map section" ); |
91 | BC.deregisterSection(Section); |
92 | }; |
93 | |
94 | if (AddressMapSection) { |
95 | Parsed.Address2AddressMap.reserve(n: AddressMapSection->getOutputSize() / |
96 | EntrySize); |
97 | parseSection(*AddressMapSection, [&](uint64_t Input, uint64_t Output) { |
98 | if (!Parsed.Address2AddressMap.count(x: Input)) |
99 | Parsed.Address2AddressMap.insert(x: {Input, Output}); |
100 | }); |
101 | } |
102 | |
103 | if (LabelMapSection) { |
104 | Parsed.Label2AddrMap.reserve(NumEntries: LabelMapSection->getOutputSize() / EntrySize); |
105 | parseSection(*LabelMapSection, [&](uint64_t Input, uint64_t Output) { |
106 | assert(!Parsed.Label2AddrMap.count( |
107 | reinterpret_cast<const MCSymbol *>(Input)) && |
108 | "Duplicate label entry detected." ); |
109 | Parsed.Label2AddrMap.insert( |
110 | KV: {reinterpret_cast<const MCSymbol *>(Input), Output}); |
111 | }); |
112 | } |
113 | |
114 | return Parsed; |
115 | } |
116 | |
117 | } // namespace bolt |
118 | } // namespace llvm |
119 | |