LLVM 17.0.0git
RuntimeDyldCOFFThumb.h
Go to the documentation of this file.
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"
18#include "llvm/Object/COFF.h"
19
20#define DEBUG_TYPE "dyld"
21
22namespace llvm {
23
25 const object::ObjectFile &Obj,
27 Expected<object::SymbolRef::Type> SymTypeOrErr = Symbol->getType();
28 if (!SymTypeOrErr) {
29 std::string Buf;
30 raw_string_ostream OS(Buf);
31 logAllUnhandledErrors(SymTypeOrErr.takeError(), OS);
33 }
34
35 if (*SymTypeOrErr != object::SymbolRef::ST_Function)
36 return false;
37
38 // We check the IMAGE_SCN_MEM_16BIT flag in the section of the symbol to tell
39 // if it's thumb or not
40 return cast<object::COFFObjectFile>(Obj)
41 .getCOFFSection(*Section)
42 ->Characteristics &
44}
45
47public:
50 : RuntimeDyldCOFF(MM, Resolver, 4, COFF::IMAGE_REL_ARM_ADDR32) {}
51
52 unsigned getMaxStubSize() const override {
53 return 16; // 8-byte load instructions, 4-byte jump, 4-byte padding
54 }
55
56 Align getStubAlignment() override { return Align(1); }
57
59 processRelocationRef(unsigned SectionID,
61 const object::ObjectFile &Obj,
62 ObjSectionToIDMap &ObjSectionToID,
63 StubMap &Stubs) override {
64 auto Symbol = RelI->getSymbol();
65 if (Symbol == Obj.symbol_end())
66 report_fatal_error("Unknown symbol in relocation");
67
68 Expected<StringRef> TargetNameOrErr = Symbol->getName();
69 if (!TargetNameOrErr)
70 return TargetNameOrErr.takeError();
71 StringRef TargetName = *TargetNameOrErr;
72
73 auto SectionOrErr = Symbol->getSection();
74 if (!SectionOrErr)
75 return SectionOrErr.takeError();
76 auto Section = *SectionOrErr;
77
78 uint64_t RelType = RelI->getType();
79 uint64_t Offset = RelI->getOffset();
80
81 // Determine the Addend used to adjust the relocation value.
82 uint64_t Addend = 0;
83 SectionEntry &AddendSection = Sections[SectionID];
84 uintptr_t ObjTarget = AddendSection.getObjAddress() + Offset;
85 uint8_t *Displacement = (uint8_t *)ObjTarget;
86
87 switch (RelType) {
91 Addend = readBytesUnaligned(Displacement, 4);
92 break;
93 default:
94 break;
95 }
96
97#if !defined(NDEBUG)
98 SmallString<32> RelTypeName;
99 RelI->getTypeName(RelTypeName);
100#endif
101 LLVM_DEBUG(dbgs() << "\t\tIn Section " << SectionID << " Offset " << Offset
102 << " RelType: " << RelTypeName << " TargetName: "
103 << TargetName << " Addend " << Addend << "\n");
104
105 bool IsExtern = Section == Obj.section_end();
106 unsigned TargetSectionID = -1;
107 uint64_t TargetOffset = -1;
108
109 if (TargetName.startswith(getImportSymbolPrefix())) {
110 TargetSectionID = SectionID;
111 TargetOffset = getDLLImportOffset(SectionID, Stubs, TargetName, true);
112 TargetName = StringRef();
113 IsExtern = false;
114 } else if (!IsExtern) {
115 if (auto TargetSectionIDOrErr =
116 findOrEmitSection(Obj, *Section, Section->isText(), ObjSectionToID))
117 TargetSectionID = *TargetSectionIDOrErr;
118 else
119 return TargetSectionIDOrErr.takeError();
120 if (RelType != COFF::IMAGE_REL_ARM_SECTION)
121 TargetOffset = getSymbolOffset(*Symbol);
122 }
123
124 if (IsExtern) {
125 RelocationEntry RE(SectionID, Offset, RelType, 0, -1, 0, 0, 0, false, 0);
126 addRelocationForSymbol(RE, TargetName);
127 } else {
128
129 // We need to find out if the relocation is relative to a thumb function
130 // so that we include the ISA selection bit when resolve the relocation
131 bool IsTargetThumbFunc = isThumbFunc(Symbol, Obj, Section);
132
133 switch (RelType) {
134 default: llvm_unreachable("unsupported relocation type");
136 // This relocation is ignored.
137 break;
139 RelocationEntry RE =
140 RelocationEntry(SectionID, Offset, RelType, Addend, TargetSectionID,
141 TargetOffset, 0, 0, false, 0, IsTargetThumbFunc);
142 addRelocationForSection(RE, TargetSectionID);
143 break;
144 }
146 RelocationEntry RE =
147 RelocationEntry(SectionID, Offset, RelType, Addend, TargetSectionID,
148 TargetOffset, 0, 0, false, 0);
149 addRelocationForSection(RE, TargetSectionID);
150 break;
151 }
153 RelocationEntry RE =
154 RelocationEntry(TargetSectionID, Offset, RelType, 0);
155 addRelocationForSection(RE, TargetSectionID);
156 break;
157 }
159 RelocationEntry RE =
160 RelocationEntry(SectionID, Offset, RelType, TargetOffset + Addend);
161 addRelocationForSection(RE, TargetSectionID);
162 break;
163 }
165 RelocationEntry RE =
166 RelocationEntry(SectionID, Offset, RelType, Addend, TargetSectionID,
167 TargetOffset, 0, 0, false, 0, IsTargetThumbFunc);
168 addRelocationForSection(RE, TargetSectionID);
169 break;
170 }
174 RelocationEntry RE = RelocationEntry(SectionID, Offset, RelType,
175 TargetOffset + Addend, true, 0);
176 addRelocationForSection(RE, TargetSectionID);
177 break;
178 }
179 }
180 }
181
182 return ++RelI;
183 }
184
186 const auto Section = Sections[RE.SectionID];
187 uint8_t *Target = Section.getAddressWithOffset(RE.Offset);
188 int ISASelectionBit = RE.IsTargetThumbFunc ? 1 : 0;
189
190 switch (RE.RelType) {
191 default: llvm_unreachable("unsupported relocation type");
193 // This relocation is ignored.
194 break;
196 // The target's 32-bit VA.
197 uint64_t Result =
198 RE.Sections.SectionA == static_cast<uint32_t>(-1)
199 ? Value
200 : Sections[RE.Sections.SectionA].getLoadAddressWithOffset(RE.Addend);
201 Result |= ISASelectionBit;
202 assert(Result <= UINT32_MAX && "relocation overflow");
203 LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
204 << " RelType: IMAGE_REL_ARM_ADDR32"
205 << " TargetSection: " << RE.Sections.SectionA
206 << " Value: " << format("0x%08" PRIx32, Result)
207 << '\n');
208 writeBytesUnaligned(Result, Target, 4);
209 break;
210 }
212 // The target's 32-bit RVA.
213 // NOTE: use Section[0].getLoadAddress() as an approximation of ImageBase
214 uint64_t Result = Sections[RE.Sections.SectionA].getLoadAddress() -
215 Sections[0].getLoadAddress() + RE.Addend;
216 assert(Result <= UINT32_MAX && "relocation overflow");
217 LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
218 << " RelType: IMAGE_REL_ARM_ADDR32NB"
219 << " TargetSection: " << RE.Sections.SectionA
220 << " Value: " << format("0x%08" PRIx32, Result)
221 << '\n');
222 Result |= ISASelectionBit;
223 writeBytesUnaligned(Result, Target, 4);
224 break;
225 }
227 // 16-bit section index of the section that contains the target.
228 assert(static_cast<uint32_t>(RE.SectionID) <= UINT16_MAX &&
229 "relocation overflow");
230 LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
231 << " RelType: IMAGE_REL_ARM_SECTION Value: "
232 << RE.SectionID << '\n');
234 break;
236 // 32-bit offset of the target from the beginning of its section.
237 assert(static_cast<uint64_t>(RE.Addend) <= UINT32_MAX &&
238 "relocation overflow");
239 LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
240 << " RelType: IMAGE_REL_ARM_SECREL Value: " << RE.Addend
241 << '\n');
243 break;
245 // 32-bit VA of the target applied to a contiguous MOVW+MOVT pair.
246 uint64_t Result =
247 Sections[RE.Sections.SectionA].getLoadAddressWithOffset(RE.Addend);
248 assert(Result <= UINT32_MAX && "relocation overflow");
249 LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
250 << " RelType: IMAGE_REL_ARM_MOV32T"
251 << " TargetSection: " << RE.Sections.SectionA
252 << " Value: " << format("0x%08" PRIx32, Result)
253 << '\n');
254
255 // MOVW(T3): |11110|i|10|0|1|0|0|imm4|0|imm3|Rd|imm8|
256 // imm32 = zext imm4:i:imm3:imm8
257 // MOVT(T1): |11110|i|10|1|1|0|0|imm4|0|imm3|Rd|imm8|
258 // imm16 = imm4:i:imm3:imm8
259
260 auto EncodeImmediate = [](uint8_t *Bytes, uint16_t Immediate) {
261 Bytes[0] |= ((Immediate & 0xf000) >> 12);
262 Bytes[1] |= ((Immediate & 0x0800) >> 11);
263 Bytes[2] |= ((Immediate & 0x00ff) >> 0);
264 Bytes[3] |= (((Immediate & 0x0700) >> 8) << 4);
265 };
266
267 EncodeImmediate(&Target[0],
268 (static_cast<uint32_t>(Result) >> 00) | ISASelectionBit);
269 EncodeImmediate(&Target[4], static_cast<uint32_t>(Result) >> 16);
270 break;
271 }
273 // The most significant 20-bits of the signed 21-bit relative displacement
275 RE.Addend - (Sections[RE.SectionID].getLoadAddress() + RE.Offset) - 4;
276 assert(static_cast<int64_t>(RE.Addend) <= INT32_MAX &&
277 "relocation overflow");
278 assert(static_cast<int64_t>(RE.Addend) >= INT32_MIN &&
279 "relocation underflow");
280 LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
281 << " RelType: IMAGE_REL_ARM_BRANCH20T"
282 << " Value: " << static_cast<int32_t>(Value) << '\n');
283 static_cast<void>(Value);
284 llvm_unreachable("unimplemented relocation");
285 break;
286 }
288 // The most significant 24-bits of the signed 25-bit relative displacement
290 RE.Addend - (Sections[RE.SectionID].getLoadAddress() + RE.Offset) - 4;
291 assert(static_cast<int64_t>(RE.Addend) <= INT32_MAX &&
292 "relocation overflow");
293 assert(static_cast<int64_t>(RE.Addend) >= INT32_MIN &&
294 "relocation underflow");
295 LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
296 << " RelType: IMAGE_REL_ARM_BRANCH24T"
297 << " Value: " << static_cast<int32_t>(Value) << '\n');
298 static_cast<void>(Value);
299 llvm_unreachable("unimplemented relocation");
300 break;
301 }
303 // The most significant 24-bits of the signed 25-bit relative displacement
305 RE.Addend - (Sections[RE.SectionID].getLoadAddress() + RE.Offset) - 4;
306 assert(static_cast<int64_t>(RE.Addend) <= INT32_MAX &&
307 "relocation overflow");
308 assert(static_cast<int64_t>(RE.Addend) >= INT32_MIN &&
309 "relocation underflow");
310 LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
311 << " RelType: IMAGE_REL_ARM_BLX23T"
312 << " Value: " << static_cast<int32_t>(Value) << '\n');
313 static_cast<void>(Value);
314 llvm_unreachable("unimplemented relocation");
315 break;
316 }
317 }
318 }
319
320 void registerEHFrames() override {}
321};
322
323}
324
325#endif
#define LLVM_DEBUG(X)
Definition: Debug.h:101
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
Tagged union holding either a T or a Error.
Definition: Error.h:470
Error takeError()
Take ownership of the stored error.
Definition: Error.h:597
Symbol resolution interface.
Definition: JITSymbol.h:371
RelocationEntry - used to represent relocations internally in the dynamic linker.
uint32_t RelType
RelType - relocation type.
uint64_t Offset
Offset - offset into the section.
int64_t Addend
Addend - the relocation addend encoded in the instruction itself.
unsigned SectionID
SectionID - the section this relocation points to.
Interface for looking up the initializer for a variable name, used by Init::resolveReferences.
Definition: Record.h:2137
Expected< object::relocation_iterator > processRelocationRef(unsigned SectionID, object::relocation_iterator RelI, const object::ObjectFile &Obj, ObjSectionToIDMap &ObjSectionToID, StubMap &Stubs) override
Parses one or more object file relocations (some object files use relocation pairs) and stores it to ...
void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override
A object file specific relocation resolver.
unsigned getMaxStubSize() const override
RuntimeDyldCOFFThumb(RuntimeDyld::MemoryManager &MM, JITSymbolResolver &Resolver)
uint64_t getSymbolOffset(const SymbolRef &Sym)
static constexpr StringRef getImportSymbolPrefix()
uint64_t getDLLImportOffset(unsigned SectionID, StubMap &Stubs, StringRef Name, bool SetSectionIDMinus1=false)
std::map< SectionRef, unsigned > ObjSectionToIDMap
std::map< RelocationValueRef, uintptr_t > StubMap
void addRelocationForSymbol(const RelocationEntry &RE, StringRef SymbolName)
void addRelocationForSection(const RelocationEntry &RE, unsigned SectionID)
Expected< unsigned > findOrEmitSection(const ObjectFile &Obj, const SectionRef &Section, bool IsCode, ObjSectionToIDMap &LocalSections)
Find Section in LocalSections.
void writeBytesUnaligned(uint64_t Value, uint8_t *Dst, unsigned Size) const
Endian-aware write.
uint64_t readBytesUnaligned(uint8_t *Src, unsigned Size) const
Endian-aware read Read the least significant Size bytes from Src.
SectionEntry - represents a section emitted into memory by the dynamic linker.
uintptr_t getObjAddress() const
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
Definition: SmallString.h:26
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
bool startswith(StringRef Prefix) const
Definition: StringRef.h:261
Target - Wrapper for Target specific information.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:81
LLVM Value Representation.
Definition: Value.h:74
This class is the base class for all object file types.
Definition: ObjectFile.h:228
virtual section_iterator section_end() const =0
virtual basic_symbol_iterator symbol_end() const =0
A raw_ostream that writes to an std::string.
Definition: raw_ostream.h:642
std::string & str()
Returns the string's reference.
Definition: raw_ostream.h:660
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ IMAGE_SCN_MEM_16BIT
Definition: COFF.h:297
@ IMAGE_REL_ARM_BRANCH20T
Definition: COFF.h:379
@ IMAGE_REL_ARM_ADDR32NB
Definition: COFF.h:368
@ IMAGE_REL_ARM_ADDR32
Definition: COFF.h:367
@ IMAGE_REL_ARM_MOV32T
Definition: COFF.h:378
@ IMAGE_REL_ARM_BRANCH24T
Definition: COFF.h:380
@ IMAGE_REL_ARM_ABSOLUTE
Definition: COFF.h:366
@ IMAGE_REL_ARM_BLX23T
Definition: COFF.h:381
@ IMAGE_REL_ARM_SECREL
Definition: COFF.h:376
@ IMAGE_REL_ARM_SECTION
Definition: COFF.h:375
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
@ Offset
Definition: DWP.cpp:406
void logAllUnhandledErrors(Error E, raw_ostream &OS, Twine ErrorBanner={})
Log all errors (if any) in E to OS.
Definition: Error.cpp:63
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
Definition: Error.cpp:145
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
Definition: Format.h:124
static bool isThumbFunc(object::symbol_iterator Symbol, const object::ObjectFile &Obj, object::section_iterator Section)
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition: Alignment.h:39