xref: /llvm-project/bolt/lib/Core/AddressMap.cpp (revision 8244ff6739a09cb75e6e7fd1c24b85e2b1397266)
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 
emitAddress(MCStreamer & Streamer,uint64_t InputAddress,const MCSymbol * OutputLabel)22 static void emitAddress(MCStreamer &Streamer, uint64_t InputAddress,
23                         const MCSymbol *OutputLabel) {
24   Streamer.emitIntValue(InputAddress, 8);
25   Streamer.emitSymbolValue(OutputLabel, 8);
26 }
27 
emitLabel(MCStreamer & Streamer,const MCSymbol * OutputLabel)28 static void emitLabel(MCStreamer &Streamer, const MCSymbol *OutputLabel) {
29   Streamer.emitIntValue(reinterpret_cast<uint64_t>(OutputLabel), 8);
30   Streamer.emitSymbolValue(OutputLabel, 8);
31 }
32 
emit(MCStreamer & Streamer,BinaryContext & BC)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(AddressSectionName, ELF::SHT_PROGBITS, Flags)
39       .setLinkOnly();
40   BC.registerOrUpdateSection(LabelSectionName, ELF::SHT_PROGBITS, 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(BC.getDataSection(LabelSectionName));
52       emitLabel(Streamer, BB.getLabel());
53 
54       if (!BB.hasLocSyms())
55         continue;
56 
57       Streamer.switchSection(BC.getDataSection(AddressSectionName));
58       for (auto [Offset, Symbol] : BB.getLocSyms())
59         emitAddress(Streamer, BFAddress + Offset, Symbol);
60     }
61   }
62 }
63 
parse(BinaryContext & BC)64 std::optional<AddressMap> AddressMap::parse(BinaryContext &BC) {
65   auto AddressMapSection = BC.getUniqueSectionByName(AddressSectionName);
66   auto LabelMapSection = BC.getUniqueSectionByName(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(Cursor)) {
85           const uint64_t Input = DE.getAddress(Cursor);
86           const uint64_t Output = DE.getAddress(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(AddressMapSection->getOutputSize() /
96                                       EntrySize);
97     parseSection(*AddressMapSection, [&](uint64_t Input, uint64_t Output) {
98       if (!Parsed.Address2AddressMap.count(Input))
99         Parsed.Address2AddressMap.insert({Input, Output});
100     });
101   }
102 
103   if (LabelMapSection) {
104     Parsed.Label2AddrMap.reserve(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           {reinterpret_cast<const MCSymbol *>(Input), Output});
111     });
112   }
113 
114   return Parsed;
115 }
116 
117 } // namespace bolt
118 } // namespace llvm
119