xref: /llvm-project/bolt/lib/Core/AddressMap.cpp (revision 8244ff6739a09cb75e6e7fd1c24b85e2b1397266)
1*8244ff67Smaksfb //===- bolt/Core/AddressMap.cpp - Input-output Address Map ----------------===//
2*8244ff67Smaksfb //
3*8244ff67Smaksfb // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*8244ff67Smaksfb // See https://llvm.org/LICENSE.txt for license information.
5*8244ff67Smaksfb // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*8244ff67Smaksfb //
7*8244ff67Smaksfb //===----------------------------------------------------------------------===//
8*8244ff67Smaksfb 
923c8d382SJob Noorman #include "bolt/Core/AddressMap.h"
1023c8d382SJob Noorman #include "bolt/Core/BinaryContext.h"
1123c8d382SJob Noorman #include "bolt/Core/BinaryFunction.h"
12*8244ff67Smaksfb #include "bolt/Core/BinarySection.h"
1323c8d382SJob Noorman #include "llvm/MC/MCStreamer.h"
1423c8d382SJob Noorman #include "llvm/Support/DataExtractor.h"
1523c8d382SJob Noorman 
1623c8d382SJob Noorman namespace llvm {
1723c8d382SJob Noorman namespace bolt {
1823c8d382SJob Noorman 
19*8244ff67Smaksfb const char *const AddressMap::AddressSectionName = ".bolt.addr2addr_map";
20*8244ff67Smaksfb const char *const AddressMap::LabelSectionName = ".bolt.label2addr_map";
2123c8d382SJob Noorman 
emitAddress(MCStreamer & Streamer,uint64_t InputAddress,const MCSymbol * OutputLabel)22*8244ff67Smaksfb static void emitAddress(MCStreamer &Streamer, uint64_t InputAddress,
2323c8d382SJob Noorman                         const MCSymbol *OutputLabel) {
2423c8d382SJob Noorman   Streamer.emitIntValue(InputAddress, 8);
2523c8d382SJob Noorman   Streamer.emitSymbolValue(OutputLabel, 8);
2623c8d382SJob Noorman }
2723c8d382SJob Noorman 
emitLabel(MCStreamer & Streamer,const MCSymbol * OutputLabel)28*8244ff67Smaksfb static void emitLabel(MCStreamer &Streamer, const MCSymbol *OutputLabel) {
29*8244ff67Smaksfb   Streamer.emitIntValue(reinterpret_cast<uint64_t>(OutputLabel), 8);
30*8244ff67Smaksfb   Streamer.emitSymbolValue(OutputLabel, 8);
31*8244ff67Smaksfb }
32*8244ff67Smaksfb 
emit(MCStreamer & Streamer,BinaryContext & BC)3323c8d382SJob Noorman void AddressMap::emit(MCStreamer &Streamer, BinaryContext &BC) {
34*8244ff67Smaksfb   // Mark map sections as link-only to avoid allocation in the output file.
35*8244ff67Smaksfb   const unsigned Flags = BinarySection::getFlags(/*IsReadOnly*/ true,
36*8244ff67Smaksfb                                                  /*IsText*/ false,
37*8244ff67Smaksfb                                                  /*IsAllocatable*/ true);
38*8244ff67Smaksfb   BC.registerOrUpdateSection(AddressSectionName, ELF::SHT_PROGBITS, Flags)
39*8244ff67Smaksfb       .setLinkOnly();
40*8244ff67Smaksfb   BC.registerOrUpdateSection(LabelSectionName, ELF::SHT_PROGBITS, Flags)
41*8244ff67Smaksfb       .setLinkOnly();
4223c8d382SJob Noorman 
4323c8d382SJob Noorman   for (const auto &[BFAddress, BF] : BC.getBinaryFunctions()) {
4423c8d382SJob Noorman     if (!BF.requiresAddressMap())
4523c8d382SJob Noorman       continue;
4623c8d382SJob Noorman 
4723c8d382SJob Noorman     for (const auto &BB : BF) {
4823c8d382SJob Noorman       if (!BB.getLabel()->isDefined())
4923c8d382SJob Noorman         continue;
5023c8d382SJob Noorman 
51*8244ff67Smaksfb       Streamer.switchSection(BC.getDataSection(LabelSectionName));
52*8244ff67Smaksfb       emitLabel(Streamer, BB.getLabel());
5323c8d382SJob Noorman 
5423c8d382SJob Noorman       if (!BB.hasLocSyms())
5523c8d382SJob Noorman         continue;
5623c8d382SJob Noorman 
57*8244ff67Smaksfb       Streamer.switchSection(BC.getDataSection(AddressSectionName));
5823c8d382SJob Noorman       for (auto [Offset, Symbol] : BB.getLocSyms())
59*8244ff67Smaksfb         emitAddress(Streamer, BFAddress + Offset, Symbol);
6023c8d382SJob Noorman     }
6123c8d382SJob Noorman   }
6223c8d382SJob Noorman }
6323c8d382SJob Noorman 
parse(BinaryContext & BC)64*8244ff67Smaksfb std::optional<AddressMap> AddressMap::parse(BinaryContext &BC) {
65*8244ff67Smaksfb   auto AddressMapSection = BC.getUniqueSectionByName(AddressSectionName);
66*8244ff67Smaksfb   auto LabelMapSection = BC.getUniqueSectionByName(LabelSectionName);
67*8244ff67Smaksfb 
68*8244ff67Smaksfb   if (!AddressMapSection && !LabelMapSection)
69*8244ff67Smaksfb     return std::nullopt;
70*8244ff67Smaksfb 
71*8244ff67Smaksfb   AddressMap Parsed;
72*8244ff67Smaksfb 
73*8244ff67Smaksfb   const size_t EntrySize = 2 * BC.AsmInfo->getCodePointerSize();
74*8244ff67Smaksfb   auto parseSection =
75*8244ff67Smaksfb       [&](BinarySection &Section,
76*8244ff67Smaksfb           function_ref<void(uint64_t, uint64_t)> InsertCallback) {
77*8244ff67Smaksfb         StringRef Buffer = Section.getOutputContents();
7823c8d382SJob Noorman         assert(Buffer.size() % EntrySize == 0 && "Unexpected address map size");
7923c8d382SJob Noorman 
8023c8d382SJob Noorman         DataExtractor DE(Buffer, BC.AsmInfo->isLittleEndian(),
8123c8d382SJob Noorman                          BC.AsmInfo->getCodePointerSize());
8223c8d382SJob Noorman         DataExtractor::Cursor Cursor(0);
8323c8d382SJob Noorman 
8423c8d382SJob Noorman         while (Cursor && !DE.eof(Cursor)) {
85*8244ff67Smaksfb           const uint64_t Input = DE.getAddress(Cursor);
86*8244ff67Smaksfb           const uint64_t Output = DE.getAddress(Cursor);
87*8244ff67Smaksfb           InsertCallback(Input, Output);
8823c8d382SJob Noorman         }
8923c8d382SJob Noorman 
9023c8d382SJob Noorman         assert(Cursor && "Error reading address map section");
91*8244ff67Smaksfb         BC.deregisterSection(Section);
92*8244ff67Smaksfb       };
93*8244ff67Smaksfb 
94*8244ff67Smaksfb   if (AddressMapSection) {
95*8244ff67Smaksfb     Parsed.Address2AddressMap.reserve(AddressMapSection->getOutputSize() /
96*8244ff67Smaksfb                                       EntrySize);
97*8244ff67Smaksfb     parseSection(*AddressMapSection, [&](uint64_t Input, uint64_t Output) {
98*8244ff67Smaksfb       if (!Parsed.Address2AddressMap.count(Input))
99*8244ff67Smaksfb         Parsed.Address2AddressMap.insert({Input, Output});
100*8244ff67Smaksfb     });
101*8244ff67Smaksfb   }
102*8244ff67Smaksfb 
103*8244ff67Smaksfb   if (LabelMapSection) {
104*8244ff67Smaksfb     Parsed.Label2AddrMap.reserve(LabelMapSection->getOutputSize() / EntrySize);
105*8244ff67Smaksfb     parseSection(*LabelMapSection, [&](uint64_t Input, uint64_t Output) {
106*8244ff67Smaksfb       assert(!Parsed.Label2AddrMap.count(
107*8244ff67Smaksfb                  reinterpret_cast<const MCSymbol *>(Input)) &&
108*8244ff67Smaksfb              "Duplicate label entry detected.");
109*8244ff67Smaksfb       Parsed.Label2AddrMap.insert(
110*8244ff67Smaksfb           {reinterpret_cast<const MCSymbol *>(Input), Output});
111*8244ff67Smaksfb     });
112*8244ff67Smaksfb   }
113*8244ff67Smaksfb 
11423c8d382SJob Noorman   return Parsed;
11523c8d382SJob Noorman }
11623c8d382SJob Noorman 
11723c8d382SJob Noorman } // namespace bolt
11823c8d382SJob Noorman } // namespace llvm
119