Welcome to mirror list, hosted at ThFree Co, Russian Federation.

JumpTable.cpp « Core « lib « bolt - github.com/llvm/llvm-project.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 2b1035d6ab715e7e6ff0dfffe2b12c350b20bdb8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
//===- bolt/Core/JumpTable.cpp - Jump table at low-level IR ---------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// This file implements the JumpTable class.
//
//===----------------------------------------------------------------------===//

#include "bolt/Core/JumpTable.h"
#include "bolt/Core/BinaryFunction.h"
#include "bolt/Core/BinarySection.h"
#include "llvm/Support/CommandLine.h"

#define DEBUG_TYPE "bolt"

using namespace llvm;
using namespace bolt;

using JumpTable = bolt::JumpTable;

namespace opts {
extern cl::opt<JumpTableSupportLevel> JumpTables;
extern cl::opt<unsigned> Verbosity;
} // namespace opts

bolt::JumpTable::JumpTable(MCSymbol &Symbol, uint64_t Address, size_t EntrySize,
                           JumpTableType Type, LabelMapType &&Labels,
                           BinarySection &Section)
    : BinaryData(Symbol, Address, 0, EntrySize, Section), EntrySize(EntrySize),
      OutputEntrySize(EntrySize), Type(Type), Labels(Labels) {}

std::pair<size_t, size_t>
bolt::JumpTable::getEntriesForAddress(const uint64_t Addr) const {
  // Check if this is not an address, but a cloned JT id
  if ((int64_t)Addr < 0ll)
    return std::make_pair(0, Entries.size());

  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);
      const uint64_t NextOffset =
          NextLI == Labels.end() ? getSize() : NextLI->first;
      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);
}

bool bolt::JumpTable::replaceDestination(uint64_t JTAddress,
                                         const MCSymbol *OldDest,
                                         MCSymbol *NewDest) {
  bool Patched = false;
  const std::pair<size_t, size_t> Range = getEntriesForAddress(JTAddress);
  for (auto I = &Entries[Range.first], E = &Entries[Range.second]; I != E;
       ++I) {
    MCSymbol *&Entry = *I;
    if (Entry == OldDest) {
      Patched = true;
      Entry = NewDest;
    }
  }
  return Patched;
}

void bolt::JumpTable::updateOriginal() {
  BinaryContext &BC = getSection().getBinaryContext();
  const uint64_t BaseOffset = getAddress() - getSection().getAddress();
  uint64_t EntryOffset = BaseOffset;
  for (MCSymbol *Entry : Entries) {
    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;
  }
}

void bolt::JumpTable::print(raw_ostream &OS) const {
  uint64_t Offset = 0;
  if (Type == JTT_PIC)
    OS << "PIC ";
  ListSeparator LS;

  OS << "Jump table " << getName() << " for function ";
  for (BinaryFunction *Frag : Parents)
    OS << LS << *Frag;
  OS << " at 0x" << Twine::utohexstr(getAddress()) << " with a total count of "
     << Count << ":\n";
  for (const uint64_t EntryAddress : EntriesAsAddress)
    OS << "  absolute offset: 0x" << Twine::utohexstr(EntryAddress) << '\n';
  for (const MCSymbol *Entry : Entries) {
    auto LI = Labels.find(Offset);
    if (Offset && LI != Labels.end()) {
      OS << "Jump Table " << LI->second->getName() << " at 0x"
         << Twine::utohexstr(getAddress() + Offset)
         << " (possibly part of larger jump table):\n";
    }
    OS << format("  0x%04" PRIx64 " : ", Offset) << Entry->getName();
    if (!Counts.empty()) {
      OS << " : " << Counts[Offset / EntrySize].Mispreds << "/"
         << Counts[Offset / EntrySize].Count;
    }
    OS << '\n';
    Offset += EntrySize;
  }
  OS << "\n\n";
}