1 //===--- RuntimeDyldCOFFThumb.h --- COFF/Thumb specific code ---*- C++ --*-===//
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
7 //===----------------------------------------------------------------------===//
9 // COFF thumb support for MC-JIT runtime dynamic linker.
11 //===----------------------------------------------------------------------===//
13 #ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFTHUMB_H
14 #define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFTHUMB_H
16 #include "../RuntimeDyldCOFF.h"
17 #include "llvm/ADT/SmallString.h"
18 #include "llvm/BinaryFormat/COFF.h"
19 #include "llvm/Object/COFF.h"
21 #define DEBUG_TYPE "dyld"
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();
31 raw_string_ostream
OS(Buf
);
32 logAllUnhandledErrors(SymTypeOrErr
.takeError(), OS
);
33 report_fatal_error(Twine(OS
.str()));
36 if (*SymTypeOrErr
!= object::SymbolRef::ST_Function
)
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
)
44 COFF::IMAGE_SCN_MEM_16BIT
;
47 class RuntimeDyldCOFFThumb
: public RuntimeDyldCOFF
{
49 RuntimeDyldCOFFThumb(RuntimeDyld::MemoryManager
&MM
,
50 JITSymbolResolver
&Resolver
)
51 : RuntimeDyldCOFF(MM
, Resolver
, 4, COFF::IMAGE_REL_ARM_ADDR32
) {}
53 unsigned getMaxStubSize() const override
{
54 return 16; // 8-byte load instructions, 4-byte jump, 4-byte padding
57 Expected
<JITSymbolFlags
> getJITSymbolFlags(const SymbolRef
&SR
) override
{
59 auto Flags
= RuntimeDyldImpl::getJITSymbolFlags(SR
);
62 return Flags
.takeError();
64 auto SectionIterOrErr
= SR
.getSection();
65 if (!SectionIterOrErr
) {
66 return SectionIterOrErr
.takeError();
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
;
74 Flags
->getTargetFlags() = isThumb
;
79 Align
getStubAlignment() override
{ return Align(1); }
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");
91 Expected
<StringRef
> TargetNameOrErr
= Symbol
->getName();
93 return TargetNameOrErr
.takeError();
94 StringRef TargetName
= *TargetNameOrErr
;
96 auto SectionOrErr
= Symbol
->getSection();
98 return SectionOrErr
.takeError();
99 auto Section
= *SectionOrErr
;
101 uint64_t RelType
= RelI
->getType();
102 uint64_t Offset
= RelI
->getOffset();
104 // Determine the Addend used to adjust the relocation value.
106 SectionEntry
&AddendSection
= Sections
[SectionID
];
107 uintptr_t ObjTarget
= AddendSection
.getObjAddress() + Offset
;
108 uint8_t *Displacement
= (uint8_t *)ObjTarget
;
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);
121 SmallString
<32> RelTypeName
;
122 RelI
->getTypeName(RelTypeName
);
124 LLVM_DEBUG(dbgs() << "\t\tIn Section " << SectionID
<< " Offset " << Offset
125 << " RelType: " << RelTypeName
<< " TargetName: "
126 << TargetName
<< " Addend " << Addend
<< "\n");
128 bool IsExtern
= Section
== Obj
.section_end();
129 unsigned TargetSectionID
= -1;
130 uint64_t TargetOffset
= -1;
132 if (TargetName
.startswith(getImportSymbolPrefix())) {
133 TargetSectionID
= SectionID
;
134 TargetOffset
= getDLLImportOffset(SectionID
, Stubs
, TargetName
, true);
135 TargetName
= StringRef();
137 } else if (!IsExtern
) {
138 if (auto TargetSectionIDOrErr
=
139 findOrEmitSection(Obj
, *Section
, Section
->isText(), ObjSectionToID
))
140 TargetSectionID
= *TargetSectionIDOrErr
;
142 return TargetSectionIDOrErr
.takeError();
143 if (RelType
!= COFF::IMAGE_REL_ARM_SECTION
)
144 TargetOffset
= getSymbolOffset(*Symbol
);
148 RelocationEntry
RE(SectionID
, Offset
, RelType
, 0, -1, 0, 0, 0, false, 0);
149 addRelocationForSymbol(RE
, TargetName
);
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
);
157 default: llvm_unreachable("unsupported relocation type");
158 case COFF::IMAGE_REL_ARM_ABSOLUTE
:
159 // This relocation is ignored.
161 case COFF::IMAGE_REL_ARM_ADDR32
: {
163 RelocationEntry(SectionID
, Offset
, RelType
, Addend
, TargetSectionID
,
164 TargetOffset
, 0, 0, false, 0, IsTargetThumbFunc
);
165 addRelocationForSection(RE
, TargetSectionID
);
168 case COFF::IMAGE_REL_ARM_ADDR32NB
: {
170 RelocationEntry(SectionID
, Offset
, RelType
, Addend
, TargetSectionID
,
171 TargetOffset
, 0, 0, false, 0);
172 addRelocationForSection(RE
, TargetSectionID
);
175 case COFF::IMAGE_REL_ARM_SECTION
: {
177 RelocationEntry(TargetSectionID
, Offset
, RelType
, 0);
178 addRelocationForSection(RE
, TargetSectionID
);
181 case COFF::IMAGE_REL_ARM_SECREL
: {
183 RelocationEntry(SectionID
, Offset
, RelType
, TargetOffset
+ Addend
);
184 addRelocationForSection(RE
, TargetSectionID
);
187 case COFF::IMAGE_REL_ARM_MOV32T
: {
189 RelocationEntry(SectionID
, Offset
, RelType
, Addend
, TargetSectionID
,
190 TargetOffset
, 0, 0, false, 0, IsTargetThumbFunc
);
191 addRelocationForSection(RE
, TargetSectionID
);
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
);
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;
213 switch (RE
.RelType
) {
214 default: llvm_unreachable("unsupported relocation type");
215 case COFF::IMAGE_REL_ARM_ABSOLUTE
:
216 // This relocation is ignored.
218 case COFF::IMAGE_REL_ARM_ADDR32
: {
219 // The target's 32-bit VA.
221 RE
.Sections
.SectionA
== static_cast<uint32_t>(-1)
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
)
231 writeBytesUnaligned(Result
, Target
, 4);
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
)
245 Result
|= ISASelectionBit
;
246 writeBytesUnaligned(Result
, Target
, 4);
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);
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
265 writeBytesUnaligned(RE
.Addend
, Target
, 2);
267 case COFF::IMAGE_REL_ARM_MOV32T
: {
268 // 32-bit VA of the target applied to a contiguous MOVW+MOVT pair.
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
)
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
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);
290 EncodeImmediate(&Target
[0],
291 (static_cast<uint32_t>(Result
) >> 00) | ISASelectionBit
);
292 EncodeImmediate(&Target
[4], static_cast<uint32_t>(Result
) >> 16);
295 case COFF::IMAGE_REL_ARM_BRANCH20T
: {
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");
310 case COFF::IMAGE_REL_ARM_BRANCH24T
: {
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");
325 case COFF::IMAGE_REL_ARM_BLX23T
: {
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");
343 void registerEHFrames() override
{}