| 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 | |