Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFThumb.h
35294 views
1
//===--- RuntimeDyldCOFFThumb.h --- COFF/Thumb specific code ---*- C++ --*-===//
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
// COFF thumb support for MC-JIT runtime dynamic linker.
10
//
11
//===----------------------------------------------------------------------===//
12
13
#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFTHUMB_H
14
#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFTHUMB_H
15
16
#include "../RuntimeDyldCOFF.h"
17
#include "llvm/ADT/SmallString.h"
18
#include "llvm/BinaryFormat/COFF.h"
19
#include "llvm/Object/COFF.h"
20
21
#define DEBUG_TYPE "dyld"
22
23
namespace llvm {
24
25
static bool isThumbFunc(object::symbol_iterator Symbol,
26
const object::ObjectFile &Obj,
27
object::section_iterator Section) {
28
Expected<object::SymbolRef::Type> SymTypeOrErr = Symbol->getType();
29
if (!SymTypeOrErr) {
30
std::string Buf;
31
raw_string_ostream OS(Buf);
32
logAllUnhandledErrors(SymTypeOrErr.takeError(), OS);
33
report_fatal_error(Twine(OS.str()));
34
}
35
36
if (*SymTypeOrErr != object::SymbolRef::ST_Function)
37
return false;
38
39
// We check the IMAGE_SCN_MEM_16BIT flag in the section of the symbol to tell
40
// if it's thumb or not
41
return cast<object::COFFObjectFile>(Obj)
42
.getCOFFSection(*Section)
43
->Characteristics &
44
COFF::IMAGE_SCN_MEM_16BIT;
45
}
46
47
class RuntimeDyldCOFFThumb : public RuntimeDyldCOFF {
48
public:
49
RuntimeDyldCOFFThumb(RuntimeDyld::MemoryManager &MM,
50
JITSymbolResolver &Resolver)
51
: RuntimeDyldCOFF(MM, Resolver, 4, COFF::IMAGE_REL_ARM_ADDR32) {}
52
53
unsigned getMaxStubSize() const override {
54
return 16; // 8-byte load instructions, 4-byte jump, 4-byte padding
55
}
56
57
Expected<JITSymbolFlags> getJITSymbolFlags(const SymbolRef &SR) override {
58
59
auto Flags = RuntimeDyldImpl::getJITSymbolFlags(SR);
60
61
if (!Flags) {
62
return Flags.takeError();
63
}
64
auto SectionIterOrErr = SR.getSection();
65
if (!SectionIterOrErr) {
66
return SectionIterOrErr.takeError();
67
}
68
SectionRef Sec = *SectionIterOrErr.get();
69
const object::COFFObjectFile *COFFObjPtr =
70
cast<object::COFFObjectFile>(Sec.getObject());
71
const coff_section *CoffSec = COFFObjPtr->getCOFFSection(Sec);
72
bool isThumb = CoffSec->Characteristics & COFF::IMAGE_SCN_MEM_16BIT;
73
74
Flags->getTargetFlags() = isThumb;
75
76
return Flags;
77
}
78
79
Align getStubAlignment() override { return Align(1); }
80
81
Expected<object::relocation_iterator>
82
processRelocationRef(unsigned SectionID,
83
object::relocation_iterator RelI,
84
const object::ObjectFile &Obj,
85
ObjSectionToIDMap &ObjSectionToID,
86
StubMap &Stubs) override {
87
auto Symbol = RelI->getSymbol();
88
if (Symbol == Obj.symbol_end())
89
report_fatal_error("Unknown symbol in relocation");
90
91
Expected<StringRef> TargetNameOrErr = Symbol->getName();
92
if (!TargetNameOrErr)
93
return TargetNameOrErr.takeError();
94
StringRef TargetName = *TargetNameOrErr;
95
96
auto SectionOrErr = Symbol->getSection();
97
if (!SectionOrErr)
98
return SectionOrErr.takeError();
99
auto Section = *SectionOrErr;
100
101
uint64_t RelType = RelI->getType();
102
uint64_t Offset = RelI->getOffset();
103
104
// Determine the Addend used to adjust the relocation value.
105
uint64_t Addend = 0;
106
SectionEntry &AddendSection = Sections[SectionID];
107
uintptr_t ObjTarget = AddendSection.getObjAddress() + Offset;
108
uint8_t *Displacement = (uint8_t *)ObjTarget;
109
110
switch (RelType) {
111
case COFF::IMAGE_REL_ARM_ADDR32:
112
case COFF::IMAGE_REL_ARM_ADDR32NB:
113
case COFF::IMAGE_REL_ARM_SECREL:
114
Addend = readBytesUnaligned(Displacement, 4);
115
break;
116
default:
117
break;
118
}
119
120
#if !defined(NDEBUG)
121
SmallString<32> RelTypeName;
122
RelI->getTypeName(RelTypeName);
123
#endif
124
LLVM_DEBUG(dbgs() << "\t\tIn Section " << SectionID << " Offset " << Offset
125
<< " RelType: " << RelTypeName << " TargetName: "
126
<< TargetName << " Addend " << Addend << "\n");
127
128
bool IsExtern = Section == Obj.section_end();
129
unsigned TargetSectionID = -1;
130
uint64_t TargetOffset = -1;
131
132
if (TargetName.starts_with(getImportSymbolPrefix())) {
133
TargetSectionID = SectionID;
134
TargetOffset = getDLLImportOffset(SectionID, Stubs, TargetName, true);
135
TargetName = StringRef();
136
IsExtern = false;
137
} else if (!IsExtern) {
138
if (auto TargetSectionIDOrErr =
139
findOrEmitSection(Obj, *Section, Section->isText(), ObjSectionToID))
140
TargetSectionID = *TargetSectionIDOrErr;
141
else
142
return TargetSectionIDOrErr.takeError();
143
if (RelType != COFF::IMAGE_REL_ARM_SECTION)
144
TargetOffset = getSymbolOffset(*Symbol);
145
}
146
147
if (IsExtern) {
148
RelocationEntry RE(SectionID, Offset, RelType, 0, -1, 0, 0, 0, false, 0);
149
addRelocationForSymbol(RE, TargetName);
150
} else {
151
152
// We need to find out if the relocation is relative to a thumb function
153
// so that we include the ISA selection bit when resolve the relocation
154
bool IsTargetThumbFunc = isThumbFunc(Symbol, Obj, Section);
155
156
switch (RelType) {
157
default: llvm_unreachable("unsupported relocation type");
158
case COFF::IMAGE_REL_ARM_ABSOLUTE:
159
// This relocation is ignored.
160
break;
161
case COFF::IMAGE_REL_ARM_ADDR32: {
162
RelocationEntry RE =
163
RelocationEntry(SectionID, Offset, RelType, Addend, TargetSectionID,
164
TargetOffset, 0, 0, false, 0, IsTargetThumbFunc);
165
addRelocationForSection(RE, TargetSectionID);
166
break;
167
}
168
case COFF::IMAGE_REL_ARM_ADDR32NB: {
169
RelocationEntry RE =
170
RelocationEntry(SectionID, Offset, RelType, Addend, TargetSectionID,
171
TargetOffset, 0, 0, false, 0);
172
addRelocationForSection(RE, TargetSectionID);
173
break;
174
}
175
case COFF::IMAGE_REL_ARM_SECTION: {
176
RelocationEntry RE =
177
RelocationEntry(TargetSectionID, Offset, RelType, 0);
178
addRelocationForSection(RE, TargetSectionID);
179
break;
180
}
181
case COFF::IMAGE_REL_ARM_SECREL: {
182
RelocationEntry RE =
183
RelocationEntry(SectionID, Offset, RelType, TargetOffset + Addend);
184
addRelocationForSection(RE, TargetSectionID);
185
break;
186
}
187
case COFF::IMAGE_REL_ARM_MOV32T: {
188
RelocationEntry RE =
189
RelocationEntry(SectionID, Offset, RelType, Addend, TargetSectionID,
190
TargetOffset, 0, 0, false, 0, IsTargetThumbFunc);
191
addRelocationForSection(RE, TargetSectionID);
192
break;
193
}
194
case COFF::IMAGE_REL_ARM_BRANCH20T:
195
case COFF::IMAGE_REL_ARM_BRANCH24T:
196
case COFF::IMAGE_REL_ARM_BLX23T: {
197
RelocationEntry RE = RelocationEntry(SectionID, Offset, RelType,
198
TargetOffset + Addend, true, 0);
199
addRelocationForSection(RE, TargetSectionID);
200
break;
201
}
202
}
203
}
204
205
return ++RelI;
206
}
207
208
void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override {
209
const auto Section = Sections[RE.SectionID];
210
uint8_t *Target = Section.getAddressWithOffset(RE.Offset);
211
int ISASelectionBit = RE.IsTargetThumbFunc ? 1 : 0;
212
213
switch (RE.RelType) {
214
default: llvm_unreachable("unsupported relocation type");
215
case COFF::IMAGE_REL_ARM_ABSOLUTE:
216
// This relocation is ignored.
217
break;
218
case COFF::IMAGE_REL_ARM_ADDR32: {
219
// The target's 32-bit VA.
220
uint64_t Result =
221
RE.Sections.SectionA == static_cast<uint32_t>(-1)
222
? Value
223
: Sections[RE.Sections.SectionA].getLoadAddressWithOffset(RE.Addend);
224
Result |= ISASelectionBit;
225
assert(Result <= UINT32_MAX && "relocation overflow");
226
LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
227
<< " RelType: IMAGE_REL_ARM_ADDR32"
228
<< " TargetSection: " << RE.Sections.SectionA
229
<< " Value: " << format("0x%08" PRIx32, Result)
230
<< '\n');
231
writeBytesUnaligned(Result, Target, 4);
232
break;
233
}
234
case COFF::IMAGE_REL_ARM_ADDR32NB: {
235
// The target's 32-bit RVA.
236
// NOTE: use Section[0].getLoadAddress() as an approximation of ImageBase
237
uint64_t Result = Sections[RE.Sections.SectionA].getLoadAddress() -
238
Sections[0].getLoadAddress() + RE.Addend;
239
assert(Result <= UINT32_MAX && "relocation overflow");
240
LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
241
<< " RelType: IMAGE_REL_ARM_ADDR32NB"
242
<< " TargetSection: " << RE.Sections.SectionA
243
<< " Value: " << format("0x%08" PRIx32, Result)
244
<< '\n');
245
Result |= ISASelectionBit;
246
writeBytesUnaligned(Result, Target, 4);
247
break;
248
}
249
case COFF::IMAGE_REL_ARM_SECTION:
250
// 16-bit section index of the section that contains the target.
251
assert(static_cast<uint32_t>(RE.SectionID) <= UINT16_MAX &&
252
"relocation overflow");
253
LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
254
<< " RelType: IMAGE_REL_ARM_SECTION Value: "
255
<< RE.SectionID << '\n');
256
writeBytesUnaligned(RE.SectionID, Target, 2);
257
break;
258
case COFF::IMAGE_REL_ARM_SECREL:
259
// 32-bit offset of the target from the beginning of its section.
260
assert(static_cast<uint64_t>(RE.Addend) <= UINT32_MAX &&
261
"relocation overflow");
262
LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
263
<< " RelType: IMAGE_REL_ARM_SECREL Value: " << RE.Addend
264
<< '\n');
265
writeBytesUnaligned(RE.Addend, Target, 2);
266
break;
267
case COFF::IMAGE_REL_ARM_MOV32T: {
268
// 32-bit VA of the target applied to a contiguous MOVW+MOVT pair.
269
uint64_t Result =
270
Sections[RE.Sections.SectionA].getLoadAddressWithOffset(RE.Addend);
271
assert(Result <= UINT32_MAX && "relocation overflow");
272
LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
273
<< " RelType: IMAGE_REL_ARM_MOV32T"
274
<< " TargetSection: " << RE.Sections.SectionA
275
<< " Value: " << format("0x%08" PRIx32, Result)
276
<< '\n');
277
278
// MOVW(T3): |11110|i|10|0|1|0|0|imm4|0|imm3|Rd|imm8|
279
// imm32 = zext imm4:i:imm3:imm8
280
// MOVT(T1): |11110|i|10|1|1|0|0|imm4|0|imm3|Rd|imm8|
281
// imm16 = imm4:i:imm3:imm8
282
283
auto EncodeImmediate = [](uint8_t *Bytes, uint16_t Immediate) {
284
Bytes[0] |= ((Immediate & 0xf000) >> 12);
285
Bytes[1] |= ((Immediate & 0x0800) >> 11);
286
Bytes[2] |= ((Immediate & 0x00ff) >> 0);
287
Bytes[3] |= (((Immediate & 0x0700) >> 8) << 4);
288
};
289
290
EncodeImmediate(&Target[0],
291
(static_cast<uint32_t>(Result) >> 00) | ISASelectionBit);
292
EncodeImmediate(&Target[4], static_cast<uint32_t>(Result) >> 16);
293
break;
294
}
295
case COFF::IMAGE_REL_ARM_BRANCH20T: {
296
// The most significant 20-bits of the signed 21-bit relative displacement
297
uint64_t Value =
298
RE.Addend - (Sections[RE.SectionID].getLoadAddress() + RE.Offset) - 4;
299
assert(static_cast<int64_t>(RE.Addend) <= INT32_MAX &&
300
"relocation overflow");
301
assert(static_cast<int64_t>(RE.Addend) >= INT32_MIN &&
302
"relocation underflow");
303
LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
304
<< " RelType: IMAGE_REL_ARM_BRANCH20T"
305
<< " Value: " << static_cast<int32_t>(Value) << '\n');
306
static_cast<void>(Value);
307
llvm_unreachable("unimplemented relocation");
308
break;
309
}
310
case COFF::IMAGE_REL_ARM_BRANCH24T: {
311
// The most significant 24-bits of the signed 25-bit relative displacement
312
uint64_t Value =
313
RE.Addend - (Sections[RE.SectionID].getLoadAddress() + RE.Offset) - 4;
314
assert(static_cast<int64_t>(RE.Addend) <= INT32_MAX &&
315
"relocation overflow");
316
assert(static_cast<int64_t>(RE.Addend) >= INT32_MIN &&
317
"relocation underflow");
318
LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
319
<< " RelType: IMAGE_REL_ARM_BRANCH24T"
320
<< " Value: " << static_cast<int32_t>(Value) << '\n');
321
static_cast<void>(Value);
322
llvm_unreachable("unimplemented relocation");
323
break;
324
}
325
case COFF::IMAGE_REL_ARM_BLX23T: {
326
// The most significant 24-bits of the signed 25-bit relative displacement
327
uint64_t Value =
328
RE.Addend - (Sections[RE.SectionID].getLoadAddress() + RE.Offset) - 4;
329
assert(static_cast<int64_t>(RE.Addend) <= INT32_MAX &&
330
"relocation overflow");
331
assert(static_cast<int64_t>(RE.Addend) >= INT32_MIN &&
332
"relocation underflow");
333
LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
334
<< " RelType: IMAGE_REL_ARM_BLX23T"
335
<< " Value: " << static_cast<int32_t>(Value) << '\n');
336
static_cast<void>(Value);
337
llvm_unreachable("unimplemented relocation");
338
break;
339
}
340
}
341
}
342
343
void registerEHFrames() override {}
344
};
345
346
}
347
348
#endif
349
350