LLVM 20.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"
19#include "llvm/Object/COFF.h"
20
21#define DEBUG_TYPE "dyld"
22
23namespace llvm {
24
26 const object::ObjectFile &Obj,
28 Expected<object::SymbolRef::Type> SymTypeOrErr = Symbol->getType();
29 if (!SymTypeOrErr) {
30 std::string Buf;
32 logAllUnhandledErrors(SymTypeOrErr.takeError(), OS);
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 &
45}
46
48public:
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
58
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);
73
74 Flags->getTargetFlags() = isThumb;
75
76 return Flags;
77 }
78
79 Align getStubAlignment() override { return Align(1); }
80
82 processRelocationRef(unsigned SectionID,
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) {
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");
159 // This relocation is ignored.
160 break;
162 RelocationEntry RE =
163 RelocationEntry(SectionID, Offset, RelType, Addend, TargetSectionID,
164 TargetOffset, 0, 0, false, 0, IsTargetThumbFunc);
165 addRelocationForSection(RE, TargetSectionID);
166 break;
167 }
169 RelocationEntry RE =
170 RelocationEntry(SectionID, Offset, RelType, Addend, TargetSectionID,
171 TargetOffset, 0, 0, false, 0);
172 addRelocationForSection(RE, TargetSectionID);
173 break;
174 }
176 RelocationEntry RE =
177 RelocationEntry(TargetSectionID, Offset, RelType, 0);
178 addRelocationForSection(RE, TargetSectionID);
179 break;
180 }
182 RelocationEntry RE =
183 RelocationEntry(SectionID, Offset, RelType, TargetOffset + Addend);
184 addRelocationForSection(RE, TargetSectionID);
185 break;
186 }
188 RelocationEntry RE =
189 RelocationEntry(SectionID, Offset, RelType, Addend, TargetSectionID,
190 TargetOffset, 0, 0, false, 0, IsTargetThumbFunc);
191 addRelocationForSection(RE, TargetSectionID);
192 break;
193 }
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
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");
216 // This relocation is ignored.
217 break;
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 }
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 }
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');
257 break;
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');
266 break;
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 }
296 // The most significant 20-bits of the signed 21-bit relative displacement
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 }
311 // The most significant 24-bits of the signed 25-bit relative displacement
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 }
326 // The most significant 24-bits of the signed 25-bit relative displacement
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
static bool isThumb(const MCSubtargetInfo &STI)
#define LLVM_DEBUG(...)
Definition: Debug.h:106
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
raw_pwrite_stream & OS
This file defines the SmallString class.
Tagged union holding either a T or a Error.
Definition: Error.h:481
Error takeError()
Take ownership of the stored error.
Definition: Error.h:608
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:2203
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
Expected< JITSymbolFlags > getJITSymbolFlags(const SymbolRef &SR) override
Generate JITSymbolFlags from a libObject symbol.
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.
virtual Expected< JITSymbolFlags > getJITSymbolFlags(const SymbolRef &Sym)
Generate JITSymbolFlags from a libObject symbol.
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:51
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
Definition: StringRef.h:265
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
const coff_section * getCOFFSection(const SectionRef &Section) const
This class is the base class for all object file types.
Definition: ObjectFile.h:229
virtual section_iterator section_end() const =0
This is a value type class that represents a single section in the list of sections in the object fil...
Definition: ObjectFile.h:81
const ObjectFile * getObject() const
Definition: ObjectFile.h:602
This is a value type class that represents a single symbol in the list of symbols in the object file.
Definition: ObjectFile.h:168
Expected< section_iterator > getSection() const
Get section this symbol is defined in reference to.
Definition: ObjectFile.h:480
virtual basic_symbol_iterator symbol_end() const =0
A raw_ostream that writes to an std::string.
Definition: raw_ostream.h:661
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ IMAGE_SCN_MEM_16BIT
Definition: COFF.h:311
@ IMAGE_REL_ARM_BRANCH20T
Definition: COFF.h:393
@ IMAGE_REL_ARM_ADDR32NB
Definition: COFF.h:382
@ IMAGE_REL_ARM_ADDR32
Definition: COFF.h:381
@ IMAGE_REL_ARM_MOV32T
Definition: COFF.h:392
@ IMAGE_REL_ARM_BRANCH24T
Definition: COFF.h:394
@ IMAGE_REL_ARM_ABSOLUTE
Definition: COFF.h:380
@ IMAGE_REL_ARM_BLX23T
Definition: COFF.h:395
@ IMAGE_REL_ARM_SECREL
Definition: COFF.h:390
@ IMAGE_REL_ARM_SECTION
Definition: COFF.h:389
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
@ Offset
Definition: DWP.cpp:480
void logAllUnhandledErrors(Error E, raw_ostream &OS, Twine ErrorBanner={})
Log all errors (if any) in E to OS.
Definition: Error.cpp:65
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:167
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
Definition: Format.h:125
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
support::ulittle32_t Characteristics
Definition: COFF.h:454