2021-12-22 02:21:41 +08:00
|
|
|
//===- bolt/Core/JumpTable.cpp - Jump table at low-level IR ---------------===//
|
2017-11-15 12:05:11 +08:00
|
|
|
//
|
2021-03-16 09:04:18 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2017-11-15 12:05:11 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
2021-12-22 02:21:41 +08:00
|
|
|
// This file implements the JumpTable class.
|
|
|
|
//
|
2017-11-15 12:05:11 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2021-10-09 02:47:10 +08:00
|
|
|
#include "bolt/Core/JumpTable.h"
|
|
|
|
#include "bolt/Core/BinaryFunction.h"
|
|
|
|
#include "bolt/Core/BinarySection.h"
|
2017-11-15 12:05:11 +08:00
|
|
|
#include "llvm/Support/CommandLine.h"
|
|
|
|
#include "llvm/Support/Debug.h"
|
|
|
|
|
|
|
|
#define DEBUG_TYPE "bolt"
|
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
using namespace bolt;
|
|
|
|
|
2021-06-03 13:46:57 +08:00
|
|
|
using JumpTable = bolt::JumpTable;
|
|
|
|
|
2017-11-15 12:05:11 +08:00
|
|
|
namespace opts {
|
|
|
|
extern cl::opt<JumpTableSupportLevel> JumpTables;
|
|
|
|
extern cl::opt<unsigned> Verbosity;
|
2021-12-15 08:52:51 +08:00
|
|
|
} // namespace opts
|
2017-11-15 12:05:11 +08:00
|
|
|
|
2021-06-03 13:46:57 +08:00
|
|
|
bolt::JumpTable::JumpTable(MCSymbol &Symbol, uint64_t Address, size_t EntrySize,
|
|
|
|
JumpTableType Type, LabelMapType &&Labels,
|
|
|
|
BinaryFunction &BF, BinarySection &Section)
|
|
|
|
: BinaryData(Symbol, Address, 0, EntrySize, Section), EntrySize(EntrySize),
|
|
|
|
OutputEntrySize(EntrySize), Type(Type), Labels(Labels), Parent(&BF) {}
|
2019-05-03 08:42:06 +08:00
|
|
|
|
2017-11-15 12:05:11 +08:00
|
|
|
std::pair<size_t, size_t>
|
2021-06-03 13:46:57 +08:00
|
|
|
bolt::JumpTable::getEntriesForAddress(const uint64_t Addr) const {
|
2019-07-03 07:56:41 +08:00
|
|
|
// Check if this is not an address, but a cloned JT id
|
|
|
|
if ((int64_t)Addr < 0ll)
|
|
|
|
return std::make_pair(0, Entries.size());
|
|
|
|
|
2017-11-15 12:05:11 +08:00
|
|
|
const uint64_t InstOffset = Addr - getAddress();
|
|
|
|
size_t StartIndex = 0, EndIndex = 0;
|
|
|
|
uint64_t Offset = 0;
|
|
|
|
|
|
|
|
for (size_t I = 0; I < Entries.size(); ++I) {
|
|
|
|
auto LI = Labels.find(Offset);
|
|
|
|
if (LI != Labels.end()) {
|
|
|
|
const auto NextLI = std::next(LI);
|
2021-04-08 15:19:26 +08:00
|
|
|
const uint64_t NextOffset =
|
|
|
|
NextLI == Labels.end() ? getSize() : NextLI->first;
|
2017-11-15 12:05:11 +08:00
|
|
|
if (InstOffset >= LI->first && InstOffset < NextOffset) {
|
|
|
|
StartIndex = I;
|
|
|
|
EndIndex = I;
|
|
|
|
while (Offset < NextOffset) {
|
|
|
|
++EndIndex;
|
|
|
|
Offset += EntrySize;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Offset += EntrySize;
|
|
|
|
}
|
|
|
|
|
|
|
|
return std::make_pair(StartIndex, EndIndex);
|
|
|
|
}
|
|
|
|
|
2021-06-03 13:46:57 +08:00
|
|
|
bool bolt::JumpTable::replaceDestination(uint64_t JTAddress,
|
|
|
|
const MCSymbol *OldDest,
|
|
|
|
MCSymbol *NewDest) {
|
2021-05-14 01:50:47 +08:00
|
|
|
bool Patched = false;
|
2021-04-08 15:19:26 +08:00
|
|
|
const std::pair<size_t, size_t> Range = getEntriesForAddress(JTAddress);
|
2019-07-03 07:56:41 +08:00
|
|
|
for (auto I = &Entries[Range.first], E = &Entries[Range.second]; I != E;
|
|
|
|
++I) {
|
2021-04-08 15:19:26 +08:00
|
|
|
MCSymbol *&Entry = *I;
|
2017-11-15 12:05:11 +08:00
|
|
|
if (Entry == OldDest) {
|
|
|
|
Patched = true;
|
|
|
|
Entry = NewDest;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Patched;
|
|
|
|
}
|
|
|
|
|
2021-06-03 13:46:57 +08:00
|
|
|
void bolt::JumpTable::updateOriginal() {
|
2021-05-13 14:35:10 +08:00
|
|
|
BinaryContext &BC = getSection().getBinaryContext();
|
2017-11-15 12:05:11 +08:00
|
|
|
const uint64_t BaseOffset = getAddress() - getSection().getAddress();
|
2021-05-13 14:35:10 +08:00
|
|
|
uint64_t EntryOffset = BaseOffset;
|
2021-04-08 15:19:26 +08:00
|
|
|
for (MCSymbol *Entry : Entries) {
|
2021-05-13 14:35:10 +08:00
|
|
|
const uint64_t RelType =
|
|
|
|
Type == JTT_NORMAL ? ELF::R_X86_64_64 : ELF::R_X86_64_PC32;
|
|
|
|
const uint64_t RelAddend =
|
|
|
|
Type == JTT_NORMAL ? 0 : EntryOffset - BaseOffset;
|
|
|
|
// Replace existing relocation with the new one to allow any modifications
|
|
|
|
// to the original jump table.
|
|
|
|
if (BC.HasRelocations)
|
|
|
|
getOutputSection().removeRelocationAt(EntryOffset);
|
|
|
|
getOutputSection().addRelocation(EntryOffset, Entry, RelType, RelAddend);
|
|
|
|
EntryOffset += EntrySize;
|
2017-11-15 12:05:11 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-03 13:46:57 +08:00
|
|
|
void bolt::JumpTable::print(raw_ostream &OS) const {
|
2017-11-15 12:05:11 +08:00
|
|
|
uint64_t Offset = 0;
|
2019-06-29 00:21:27 +08:00
|
|
|
if (Type == JTT_PIC)
|
|
|
|
OS << "PIC ";
|
|
|
|
OS << "Jump table " << getName() << " for function " << *Parent << " at 0x"
|
|
|
|
<< Twine::utohexstr(getAddress()) << " with a total count of " << Count
|
|
|
|
<< ":\n";
|
2021-12-21 03:07:46 +08:00
|
|
|
for (const uint64_t EntryOffset : OffsetEntries)
|
2019-11-11 13:09:01 +08:00
|
|
|
OS << " 0x" << Twine::utohexstr(EntryOffset) << '\n';
|
2021-04-08 15:19:26 +08:00
|
|
|
for (const MCSymbol *Entry : Entries) {
|
2017-11-15 12:05:11 +08:00
|
|
|
auto LI = Labels.find(Offset);
|
2019-06-29 00:21:27 +08:00
|
|
|
if (Offset && LI != Labels.end()) {
|
|
|
|
OS << "Jump Table " << LI->second->getName() << " at 0x"
|
|
|
|
<< Twine::utohexstr(getAddress() + Offset)
|
2021-12-15 08:52:51 +08:00
|
|
|
<< " (possibly part of larger jump table):\n";
|
2017-11-15 12:05:11 +08:00
|
|
|
}
|
|
|
|
OS << format(" 0x%04" PRIx64 " : ", Offset) << Entry->getName();
|
|
|
|
if (!Counts.empty()) {
|
2021-12-15 08:52:51 +08:00
|
|
|
OS << " : " << Counts[Offset / EntrySize].Mispreds << "/"
|
|
|
|
<< Counts[Offset / EntrySize].Count;
|
2017-11-15 12:05:11 +08:00
|
|
|
}
|
|
|
|
OS << '\n';
|
|
|
|
Offset += EntrySize;
|
|
|
|
}
|
|
|
|
OS << "\n\n";
|
|
|
|
}
|