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