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/BinaryFormat/COFF.h"
18 #include "llvm/Object/COFF.h"
20 #define DEBUG_TYPE "dyld"
24 static bool isThumbFunc(object::symbol_iterator Symbol
,
25 const object::ObjectFile
&Obj
,
26 object::section_iterator Section
) {
27 Expected
<object::SymbolRef::Type
> SymTypeOrErr
= Symbol
->getType();
30 raw_string_ostream
OS(Buf
);
31 logAllUnhandledErrors(SymTypeOrErr
.takeError(), OS
);
33 report_fatal_error(Buf
);
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 unsigned getStubAlignment() override
{ return 1; }
59 Expected
<object::relocation_iterator
>
60 processRelocationRef(unsigned SectionID
,
61 object::relocation_iterator RelI
,
62 const object::ObjectFile
&Obj
,
63 ObjSectionToIDMap
&ObjSectionToID
,
64 StubMap
&Stubs
) override
{
65 auto Symbol
= RelI
->getSymbol();
66 if (Symbol
== Obj
.symbol_end())
67 report_fatal_error("Unknown symbol in relocation");
69 Expected
<StringRef
> TargetNameOrErr
= Symbol
->getName();
71 return TargetNameOrErr
.takeError();
72 StringRef TargetName
= *TargetNameOrErr
;
74 auto SectionOrErr
= Symbol
->getSection();
76 return SectionOrErr
.takeError();
77 auto Section
= *SectionOrErr
;
79 uint64_t RelType
= RelI
->getType();
80 uint64_t Offset
= RelI
->getOffset();
82 // Determine the Addend used to adjust the relocation value.
84 SectionEntry
&AddendSection
= Sections
[SectionID
];
85 uintptr_t ObjTarget
= AddendSection
.getObjAddress() + Offset
;
86 uint8_t *Displacement
= (uint8_t *)ObjTarget
;
89 case COFF::IMAGE_REL_ARM_ADDR32
:
90 case COFF::IMAGE_REL_ARM_ADDR32NB
:
91 case COFF::IMAGE_REL_ARM_SECREL
:
92 Addend
= readBytesUnaligned(Displacement
, 4);
99 SmallString
<32> RelTypeName
;
100 RelI
->getTypeName(RelTypeName
);
102 LLVM_DEBUG(dbgs() << "\t\tIn Section " << SectionID
<< " Offset " << Offset
103 << " RelType: " << RelTypeName
<< " TargetName: "
104 << TargetName
<< " Addend " << Addend
<< "\n");
106 bool IsExtern
= Section
== Obj
.section_end();
107 unsigned TargetSectionID
= -1;
108 uint64_t TargetOffset
= -1;
110 if (TargetName
.startswith(getImportSymbolPrefix())) {
111 TargetSectionID
= SectionID
;
112 TargetOffset
= getDLLImportOffset(SectionID
, Stubs
, TargetName
, true);
113 TargetName
= StringRef();
115 } else if (!IsExtern
) {
116 if (auto TargetSectionIDOrErr
=
117 findOrEmitSection(Obj
, *Section
, Section
->isText(), ObjSectionToID
))
118 TargetSectionID
= *TargetSectionIDOrErr
;
120 return TargetSectionIDOrErr
.takeError();
121 if (RelType
!= COFF::IMAGE_REL_ARM_SECTION
)
122 TargetOffset
= getSymbolOffset(*Symbol
);
126 RelocationEntry
RE(SectionID
, Offset
, RelType
, 0, -1, 0, 0, 0, false, 0);
127 addRelocationForSymbol(RE
, TargetName
);
130 // We need to find out if the relocation is relative to a thumb function
131 // so that we include the ISA selection bit when resolve the relocation
132 bool IsTargetThumbFunc
= isThumbFunc(Symbol
, Obj
, Section
);
135 default: llvm_unreachable("unsupported relocation type");
136 case COFF::IMAGE_REL_ARM_ABSOLUTE
:
137 // This relocation is ignored.
139 case COFF::IMAGE_REL_ARM_ADDR32
: {
141 RelocationEntry(SectionID
, Offset
, RelType
, Addend
, TargetSectionID
,
142 TargetOffset
, 0, 0, false, 0, IsTargetThumbFunc
);
143 addRelocationForSection(RE
, TargetSectionID
);
146 case COFF::IMAGE_REL_ARM_ADDR32NB
: {
148 RelocationEntry(SectionID
, Offset
, RelType
, Addend
, TargetSectionID
,
149 TargetOffset
, 0, 0, false, 0);
150 addRelocationForSection(RE
, TargetSectionID
);
153 case COFF::IMAGE_REL_ARM_SECTION
: {
155 RelocationEntry(TargetSectionID
, Offset
, RelType
, 0);
156 addRelocationForSection(RE
, TargetSectionID
);
159 case COFF::IMAGE_REL_ARM_SECREL
: {
161 RelocationEntry(SectionID
, Offset
, RelType
, TargetOffset
+ Addend
);
162 addRelocationForSection(RE
, TargetSectionID
);
165 case COFF::IMAGE_REL_ARM_MOV32T
: {
167 RelocationEntry(SectionID
, Offset
, RelType
, Addend
, TargetSectionID
,
168 TargetOffset
, 0, 0, false, 0, IsTargetThumbFunc
);
169 addRelocationForSection(RE
, TargetSectionID
);
172 case COFF::IMAGE_REL_ARM_BRANCH20T
:
173 case COFF::IMAGE_REL_ARM_BRANCH24T
:
174 case COFF::IMAGE_REL_ARM_BLX23T
: {
175 RelocationEntry RE
= RelocationEntry(SectionID
, Offset
, RelType
,
176 TargetOffset
+ Addend
, true, 0);
177 addRelocationForSection(RE
, TargetSectionID
);
186 void resolveRelocation(const RelocationEntry
&RE
, uint64_t Value
) override
{
187 const auto Section
= Sections
[RE
.SectionID
];
188 uint8_t *Target
= Section
.getAddressWithOffset(RE
.Offset
);
189 int ISASelectionBit
= RE
.IsTargetThumbFunc
? 1 : 0;
191 switch (RE
.RelType
) {
192 default: llvm_unreachable("unsupported relocation type");
193 case COFF::IMAGE_REL_ARM_ABSOLUTE
:
194 // This relocation is ignored.
196 case COFF::IMAGE_REL_ARM_ADDR32
: {
197 // The target's 32-bit VA.
199 RE
.Sections
.SectionA
== static_cast<uint32_t>(-1)
201 : Sections
[RE
.Sections
.SectionA
].getLoadAddressWithOffset(RE
.Addend
);
202 Result
|= ISASelectionBit
;
203 assert(Result
<= UINT32_MAX
&& "relocation overflow");
204 LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE
.Offset
205 << " RelType: IMAGE_REL_ARM_ADDR32"
206 << " TargetSection: " << RE
.Sections
.SectionA
207 << " Value: " << format("0x%08" PRIx32
, Result
)
209 writeBytesUnaligned(Result
, Target
, 4);
212 case COFF::IMAGE_REL_ARM_ADDR32NB
: {
213 // The target's 32-bit RVA.
214 // NOTE: use Section[0].getLoadAddress() as an approximation of ImageBase
215 uint64_t Result
= Sections
[RE
.Sections
.SectionA
].getLoadAddress() -
216 Sections
[0].getLoadAddress() + RE
.Addend
;
217 assert(Result
<= UINT32_MAX
&& "relocation overflow");
218 LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE
.Offset
219 << " RelType: IMAGE_REL_ARM_ADDR32NB"
220 << " TargetSection: " << RE
.Sections
.SectionA
221 << " Value: " << format("0x%08" PRIx32
, Result
)
223 Result
|= ISASelectionBit
;
224 writeBytesUnaligned(Result
, Target
, 4);
227 case COFF::IMAGE_REL_ARM_SECTION
:
228 // 16-bit section index of the section that contains the target.
229 assert(static_cast<uint32_t>(RE
.SectionID
) <= UINT16_MAX
&&
230 "relocation overflow");
231 LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE
.Offset
232 << " RelType: IMAGE_REL_ARM_SECTION Value: "
233 << RE
.SectionID
<< '\n');
234 writeBytesUnaligned(RE
.SectionID
, Target
, 2);
236 case COFF::IMAGE_REL_ARM_SECREL
:
237 // 32-bit offset of the target from the beginning of its section.
238 assert(static_cast<uint64_t>(RE
.Addend
) <= UINT32_MAX
&&
239 "relocation overflow");
240 LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE
.Offset
241 << " RelType: IMAGE_REL_ARM_SECREL Value: " << RE
.Addend
243 writeBytesUnaligned(RE
.Addend
, Target
, 2);
245 case COFF::IMAGE_REL_ARM_MOV32T
: {
246 // 32-bit VA of the target applied to a contiguous MOVW+MOVT pair.
248 Sections
[RE
.Sections
.SectionA
].getLoadAddressWithOffset(RE
.Addend
);
249 assert(Result
<= UINT32_MAX
&& "relocation overflow");
250 LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE
.Offset
251 << " RelType: IMAGE_REL_ARM_MOV32T"
252 << " TargetSection: " << RE
.Sections
.SectionA
253 << " Value: " << format("0x%08" PRIx32
, Result
)
256 // MOVW(T3): |11110|i|10|0|1|0|0|imm4|0|imm3|Rd|imm8|
257 // imm32 = zext imm4:i:imm3:imm8
258 // MOVT(T1): |11110|i|10|1|1|0|0|imm4|0|imm3|Rd|imm8|
259 // imm16 = imm4:i:imm3:imm8
261 auto EncodeImmediate
= [](uint8_t *Bytes
, uint16_t Immediate
) {
262 Bytes
[0] |= ((Immediate
& 0xf000) >> 12);
263 Bytes
[1] |= ((Immediate
& 0x0800) >> 11);
264 Bytes
[2] |= ((Immediate
& 0x00ff) >> 0);
265 Bytes
[3] |= (((Immediate
& 0x0700) >> 8) << 4);
268 EncodeImmediate(&Target
[0],
269 (static_cast<uint32_t>(Result
) >> 00) | ISASelectionBit
);
270 EncodeImmediate(&Target
[4], static_cast<uint32_t>(Result
) >> 16);
273 case COFF::IMAGE_REL_ARM_BRANCH20T
: {
274 // The most significant 20-bits of the signed 21-bit relative displacement
276 RE
.Addend
- (Sections
[RE
.SectionID
].getLoadAddress() + RE
.Offset
) - 4;
277 assert(static_cast<int64_t>(RE
.Addend
) <= INT32_MAX
&&
278 "relocation overflow");
279 assert(static_cast<int64_t>(RE
.Addend
) >= INT32_MIN
&&
280 "relocation underflow");
281 LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE
.Offset
282 << " RelType: IMAGE_REL_ARM_BRANCH20T"
283 << " Value: " << static_cast<int32_t>(Value
) << '\n');
284 static_cast<void>(Value
);
285 llvm_unreachable("unimplemented relocation");
288 case COFF::IMAGE_REL_ARM_BRANCH24T
: {
289 // The most significant 24-bits of the signed 25-bit relative displacement
291 RE
.Addend
- (Sections
[RE
.SectionID
].getLoadAddress() + RE
.Offset
) - 4;
292 assert(static_cast<int64_t>(RE
.Addend
) <= INT32_MAX
&&
293 "relocation overflow");
294 assert(static_cast<int64_t>(RE
.Addend
) >= INT32_MIN
&&
295 "relocation underflow");
296 LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE
.Offset
297 << " RelType: IMAGE_REL_ARM_BRANCH24T"
298 << " Value: " << static_cast<int32_t>(Value
) << '\n');
299 static_cast<void>(Value
);
300 llvm_unreachable("unimplemented relocation");
303 case COFF::IMAGE_REL_ARM_BLX23T
: {
304 // The most significant 24-bits of the signed 25-bit relative displacement
306 RE
.Addend
- (Sections
[RE
.SectionID
].getLoadAddress() + RE
.Offset
) - 4;
307 assert(static_cast<int64_t>(RE
.Addend
) <= INT32_MAX
&&
308 "relocation overflow");
309 assert(static_cast<int64_t>(RE
.Addend
) >= INT32_MIN
&&
310 "relocation underflow");
311 LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE
.Offset
312 << " RelType: IMAGE_REL_ARM_BLX23T"
313 << " Value: " << static_cast<int32_t>(Value
) << '\n');
314 static_cast<void>(Value
);
315 llvm_unreachable("unimplemented relocation");
321 void registerEHFrames() override
{}