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