Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/lld/MachO/Arch/ARM64Common.cpp
34889 views
1
//===- ARM64Common.cpp ----------------------------------------------------===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
9
#include "Arch/ARM64Common.h"
10
11
#include "lld/Common/ErrorHandler.h"
12
#include "llvm/Support/Endian.h"
13
14
using namespace llvm::MachO;
15
using namespace llvm::support::endian;
16
using namespace lld;
17
using namespace lld::macho;
18
19
int64_t ARM64Common::getEmbeddedAddend(MemoryBufferRef mb, uint64_t offset,
20
const relocation_info rel) const {
21
if (rel.r_type != ARM64_RELOC_UNSIGNED &&
22
rel.r_type != ARM64_RELOC_SUBTRACTOR) {
23
// All other reloc types should use the ADDEND relocation to store their
24
// addends.
25
// TODO(gkm): extract embedded addend just so we can assert that it is 0
26
return 0;
27
}
28
29
const auto *buf = reinterpret_cast<const uint8_t *>(mb.getBufferStart());
30
const uint8_t *loc = buf + offset + rel.r_address;
31
switch (rel.r_length) {
32
case 2:
33
return static_cast<int32_t>(read32le(loc));
34
case 3:
35
return read64le(loc);
36
default:
37
llvm_unreachable("invalid r_length");
38
}
39
}
40
41
static void writeValue(uint8_t *loc, const Reloc &r, uint64_t value) {
42
switch (r.length) {
43
case 2:
44
checkInt(loc, r, value, 32);
45
write32le(loc, value);
46
break;
47
case 3:
48
write64le(loc, value);
49
break;
50
default:
51
llvm_unreachable("invalid r_length");
52
}
53
}
54
55
// For instruction relocations (load, store, add), the base
56
// instruction is pre-populated in the text section. A pre-populated
57
// instruction has opcode & register-operand bits set, with immediate
58
// operands zeroed. We read it from text, OR-in the immediate
59
// operands, then write-back the completed instruction.
60
void ARM64Common::relocateOne(uint8_t *loc, const Reloc &r, uint64_t value,
61
uint64_t pc) const {
62
auto loc32 = reinterpret_cast<uint32_t *>(loc);
63
uint32_t base = ((r.length == 2) ? read32le(loc) : 0);
64
switch (r.type) {
65
case ARM64_RELOC_BRANCH26:
66
encodeBranch26(loc32, r, base, value - pc);
67
break;
68
case ARM64_RELOC_SUBTRACTOR:
69
case ARM64_RELOC_UNSIGNED:
70
writeValue(loc, r, value);
71
break;
72
case ARM64_RELOC_POINTER_TO_GOT:
73
if (r.pcrel)
74
value -= pc;
75
writeValue(loc, r, value);
76
break;
77
case ARM64_RELOC_PAGE21:
78
case ARM64_RELOC_GOT_LOAD_PAGE21:
79
case ARM64_RELOC_TLVP_LOAD_PAGE21:
80
assert(r.pcrel);
81
encodePage21(loc32, r, base, pageBits(value) - pageBits(pc));
82
break;
83
case ARM64_RELOC_PAGEOFF12:
84
case ARM64_RELOC_GOT_LOAD_PAGEOFF12:
85
case ARM64_RELOC_TLVP_LOAD_PAGEOFF12:
86
assert(!r.pcrel);
87
encodePageOff12(loc32, r, base, value);
88
break;
89
default:
90
llvm_unreachable("unexpected relocation type");
91
}
92
}
93
94
void ARM64Common::relaxGotLoad(uint8_t *loc, uint8_t type) const {
95
// The instruction format comments below are quoted from
96
// ArmĀ® Architecture Reference Manual
97
// Armv8, for Armv8-A architecture profile
98
// ARM DDI 0487G.a (ID011921)
99
uint32_t instruction = read32le(loc);
100
// C6.2.132 LDR (immediate)
101
// This matches both the 64- and 32-bit variants:
102
// LDR <(X|W)t>, [<Xn|SP>{, #<pimm>}]
103
if ((instruction & 0xbfc00000) != 0xb9400000)
104
error(getRelocAttrs(type).name + " reloc requires LDR instruction");
105
assert(((instruction >> 10) & 0xfff) == 0 &&
106
"non-zero embedded LDR immediate");
107
// C6.2.4 ADD (immediate)
108
// ADD <Xd|SP>, <Xn|SP>, #<imm>{, <shift>}
109
instruction = ((instruction & 0x001fffff) | 0x91000000);
110
write32le(loc, instruction);
111
}
112
113
void ARM64Common::handleDtraceReloc(const Symbol *sym, const Reloc &r,
114
uint8_t *loc) const {
115
assert(r.type == ARM64_RELOC_BRANCH26);
116
117
if (config->outputType == MH_OBJECT)
118
return;
119
120
if (sym->getName().starts_with("___dtrace_probe")) {
121
// change call site to a NOP
122
write32le(loc, 0xD503201F);
123
} else if (sym->getName().starts_with("___dtrace_isenabled")) {
124
// change call site to 'MOVZ X0,0'
125
write32le(loc, 0xD2800000);
126
} else {
127
error("Unrecognized dtrace symbol prefix: " + toString(*sym));
128
}
129
}
130
131
static void reportUnalignedLdrStr(Twine loc, uint64_t va, int align,
132
const Symbol *sym) {
133
std::string symbolHint;
134
if (sym)
135
symbolHint = " (" + toString(*sym) + ")";
136
error(loc + ": " + Twine(8 * align) + "-bit LDR/STR to 0x" +
137
llvm::utohexstr(va) + symbolHint + " is not " + Twine(align) +
138
"-byte aligned");
139
}
140
141
void macho::reportUnalignedLdrStr(void *loc, const lld::macho::Reloc &r,
142
uint64_t va, int align) {
143
uint64_t off = reinterpret_cast<const uint8_t *>(loc) - in.bufferStart;
144
const InputSection *isec = offsetToInputSection(&off);
145
std::string locStr = isec ? isec->getLocation(off) : "(invalid location)";
146
::reportUnalignedLdrStr(locStr, va, align, r.referent.dyn_cast<Symbol *>());
147
}
148
149
void macho::reportUnalignedLdrStr(void *loc, lld::macho::SymbolDiagnostic d,
150
uint64_t va, int align) {
151
::reportUnalignedLdrStr(d.reason, va, align, d.symbol);
152
}
153
154