1 //===--- JumpTable.h - Representation of a jump table ---------------------===// 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 //===----------------------------------------------------------------------===// 10 11 #include "bolt/Core/JumpTable.h" 12 #include "bolt/Core/BinaryFunction.h" 13 #include "bolt/Core/BinarySection.h" 14 #include "llvm/Support/CommandLine.h" 15 #include "llvm/Support/Debug.h" 16 17 #define DEBUG_TYPE "bolt" 18 19 using namespace llvm; 20 using namespace bolt; 21 22 using JumpTable = bolt::JumpTable; 23 24 namespace opts { 25 extern cl::opt<JumpTableSupportLevel> JumpTables; 26 extern cl::opt<unsigned> Verbosity; 27 } // namespace opts 28 29 bolt::JumpTable::JumpTable(MCSymbol &Symbol, uint64_t Address, size_t EntrySize, 30 JumpTableType Type, LabelMapType &&Labels, 31 BinaryFunction &BF, BinarySection &Section) 32 : BinaryData(Symbol, Address, 0, EntrySize, Section), EntrySize(EntrySize), 33 OutputEntrySize(EntrySize), Type(Type), Labels(Labels), Parent(&BF) {} 34 35 std::pair<size_t, size_t> 36 bolt::JumpTable::getEntriesForAddress(const uint64_t Addr) const { 37 // Check if this is not an address, but a cloned JT id 38 if ((int64_t)Addr < 0ll) 39 return std::make_pair(0, Entries.size()); 40 41 const uint64_t InstOffset = Addr - getAddress(); 42 size_t StartIndex = 0, EndIndex = 0; 43 uint64_t Offset = 0; 44 45 for (size_t I = 0; I < Entries.size(); ++I) { 46 auto LI = Labels.find(Offset); 47 if (LI != Labels.end()) { 48 const auto NextLI = std::next(LI); 49 const uint64_t NextOffset = 50 NextLI == Labels.end() ? getSize() : NextLI->first; 51 if (InstOffset >= LI->first && InstOffset < NextOffset) { 52 StartIndex = I; 53 EndIndex = I; 54 while (Offset < NextOffset) { 55 ++EndIndex; 56 Offset += EntrySize; 57 } 58 break; 59 } 60 } 61 Offset += EntrySize; 62 } 63 64 return std::make_pair(StartIndex, EndIndex); 65 } 66 67 bool bolt::JumpTable::replaceDestination(uint64_t JTAddress, 68 const MCSymbol *OldDest, 69 MCSymbol *NewDest) { 70 bool Patched = false; 71 const std::pair<size_t, size_t> Range = getEntriesForAddress(JTAddress); 72 for (auto I = &Entries[Range.first], E = &Entries[Range.second]; I != E; 73 ++I) { 74 MCSymbol *&Entry = *I; 75 if (Entry == OldDest) { 76 Patched = true; 77 Entry = NewDest; 78 } 79 } 80 return Patched; 81 } 82 83 void bolt::JumpTable::updateOriginal() { 84 BinaryContext &BC = getSection().getBinaryContext(); 85 const uint64_t BaseOffset = getAddress() - getSection().getAddress(); 86 uint64_t EntryOffset = BaseOffset; 87 for (MCSymbol *Entry : Entries) { 88 const uint64_t RelType = 89 Type == JTT_NORMAL ? ELF::R_X86_64_64 : ELF::R_X86_64_PC32; 90 const uint64_t RelAddend = 91 Type == JTT_NORMAL ? 0 : EntryOffset - BaseOffset; 92 // Replace existing relocation with the new one to allow any modifications 93 // to the original jump table. 94 if (BC.HasRelocations) 95 getOutputSection().removeRelocationAt(EntryOffset); 96 getOutputSection().addRelocation(EntryOffset, Entry, RelType, RelAddend); 97 EntryOffset += EntrySize; 98 } 99 } 100 101 void bolt::JumpTable::print(raw_ostream &OS) const { 102 uint64_t Offset = 0; 103 if (Type == JTT_PIC) 104 OS << "PIC "; 105 OS << "Jump table " << getName() << " for function " << *Parent << " at 0x" 106 << Twine::utohexstr(getAddress()) << " with a total count of " << Count 107 << ":\n"; 108 for (const uint64_t EntryOffset : OffsetEntries) { 109 OS << " 0x" << Twine::utohexstr(EntryOffset) << '\n'; 110 } 111 for (const MCSymbol *Entry : Entries) { 112 auto LI = Labels.find(Offset); 113 if (Offset && LI != Labels.end()) { 114 OS << "Jump Table " << LI->second->getName() << " at 0x" 115 << Twine::utohexstr(getAddress() + Offset) 116 << " (possibly part of larger jump table):\n"; 117 } 118 OS << format(" 0x%04" PRIx64 " : ", Offset) << Entry->getName(); 119 if (!Counts.empty()) { 120 OS << " : " << Counts[Offset / EntrySize].Mispreds << "/" 121 << Counts[Offset / EntrySize].Count; 122 } 123 OS << '\n'; 124 Offset += EntrySize; 125 } 126 OS << "\n\n"; 127 } 128