xref: /llvm-project/bolt/lib/Core/JumpTable.cpp (revision 2f09f445b2d6b3ef197aecd8d1e06d08140380f3)
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