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
) {}
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 unsigned TargetSectionID
= -1;
107 if (Section
== Obj
.section_end()) {
108 RelocationEntry
RE(SectionID
, Offset
, RelType
, 0, -1, 0, 0, 0, false, 0);
109 addRelocationForSymbol(RE
, TargetName
);
111 if (auto TargetSectionIDOrErr
=
112 findOrEmitSection(Obj
, *Section
, Section
->isText(), ObjSectionToID
))
113 TargetSectionID
= *TargetSectionIDOrErr
;
115 return TargetSectionIDOrErr
.takeError();
117 // We need to find out if the relocation is relative to a thumb function
118 // so that we include the ISA selection bit when resolve the relocation
119 bool IsTargetThumbFunc
= isThumbFunc(Symbol
, Obj
, Section
);
122 default: llvm_unreachable("unsupported relocation type");
123 case COFF::IMAGE_REL_ARM_ABSOLUTE
:
124 // This relocation is ignored.
126 case COFF::IMAGE_REL_ARM_ADDR32
: {
127 RelocationEntry RE
= RelocationEntry(
128 SectionID
, Offset
, RelType
, Addend
, TargetSectionID
,
129 getSymbolOffset(*Symbol
), 0, 0, false, 0, IsTargetThumbFunc
);
130 addRelocationForSection(RE
, TargetSectionID
);
133 case COFF::IMAGE_REL_ARM_ADDR32NB
: {
135 RelocationEntry(SectionID
, Offset
, RelType
, Addend
, TargetSectionID
,
136 getSymbolOffset(*Symbol
), 0, 0, false, 0);
137 addRelocationForSection(RE
, TargetSectionID
);
140 case COFF::IMAGE_REL_ARM_SECTION
: {
142 RelocationEntry(TargetSectionID
, Offset
, RelType
, 0);
143 addRelocationForSection(RE
, TargetSectionID
);
146 case COFF::IMAGE_REL_ARM_SECREL
: {
147 RelocationEntry RE
= RelocationEntry(SectionID
, Offset
, RelType
,
148 getSymbolOffset(*Symbol
) + Addend
);
149 addRelocationForSection(RE
, TargetSectionID
);
152 case COFF::IMAGE_REL_ARM_MOV32T
: {
153 RelocationEntry RE
= RelocationEntry(
154 SectionID
, Offset
, RelType
, Addend
, TargetSectionID
,
155 getSymbolOffset(*Symbol
), 0, 0, false, 0, IsTargetThumbFunc
);
156 addRelocationForSection(RE
, TargetSectionID
);
159 case COFF::IMAGE_REL_ARM_BRANCH20T
:
160 case COFF::IMAGE_REL_ARM_BRANCH24T
:
161 case COFF::IMAGE_REL_ARM_BLX23T
: {
163 RelocationEntry(SectionID
, Offset
, RelType
,
164 getSymbolOffset(*Symbol
) + Addend
, true, 0);
165 addRelocationForSection(RE
, TargetSectionID
);
174 void resolveRelocation(const RelocationEntry
&RE
, uint64_t Value
) override
{
175 const auto Section
= Sections
[RE
.SectionID
];
176 uint8_t *Target
= Section
.getAddressWithOffset(RE
.Offset
);
177 int ISASelectionBit
= RE
.IsTargetThumbFunc
? 1 : 0;
179 switch (RE
.RelType
) {
180 default: llvm_unreachable("unsupported relocation type");
181 case COFF::IMAGE_REL_ARM_ABSOLUTE
:
182 // This relocation is ignored.
184 case COFF::IMAGE_REL_ARM_ADDR32
: {
185 // The target's 32-bit VA.
187 RE
.Sections
.SectionA
== static_cast<uint32_t>(-1)
189 : Sections
[RE
.Sections
.SectionA
].getLoadAddressWithOffset(RE
.Addend
);
190 Result
|= ISASelectionBit
;
191 assert(Result
<= UINT32_MAX
&& "relocation overflow");
192 LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE
.Offset
193 << " RelType: IMAGE_REL_ARM_ADDR32"
194 << " TargetSection: " << RE
.Sections
.SectionA
195 << " Value: " << format("0x%08" PRIx32
, Result
)
197 writeBytesUnaligned(Result
, Target
, 4);
200 case COFF::IMAGE_REL_ARM_ADDR32NB
: {
201 // The target's 32-bit RVA.
202 // NOTE: use Section[0].getLoadAddress() as an approximation of ImageBase
203 uint64_t Result
= Sections
[RE
.Sections
.SectionA
].getLoadAddress() -
204 Sections
[0].getLoadAddress() + RE
.Addend
;
205 assert(Result
<= UINT32_MAX
&& "relocation overflow");
206 LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE
.Offset
207 << " RelType: IMAGE_REL_ARM_ADDR32NB"
208 << " TargetSection: " << RE
.Sections
.SectionA
209 << " Value: " << format("0x%08" PRIx32
, Result
)
211 Result
|= ISASelectionBit
;
212 writeBytesUnaligned(Result
, Target
, 4);
215 case COFF::IMAGE_REL_ARM_SECTION
:
216 // 16-bit section index of the section that contains the target.
217 assert(static_cast<uint32_t>(RE
.SectionID
) <= UINT16_MAX
&&
218 "relocation overflow");
219 LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE
.Offset
220 << " RelType: IMAGE_REL_ARM_SECTION Value: "
221 << RE
.SectionID
<< '\n');
222 writeBytesUnaligned(RE
.SectionID
, Target
, 2);
224 case COFF::IMAGE_REL_ARM_SECREL
:
225 // 32-bit offset of the target from the beginning of its section.
226 assert(static_cast<uint64_t>(RE
.Addend
) <= UINT32_MAX
&&
227 "relocation overflow");
228 LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE
.Offset
229 << " RelType: IMAGE_REL_ARM_SECREL Value: " << RE
.Addend
231 writeBytesUnaligned(RE
.Addend
, Target
, 2);
233 case COFF::IMAGE_REL_ARM_MOV32T
: {
234 // 32-bit VA of the target applied to a contiguous MOVW+MOVT pair.
236 Sections
[RE
.Sections
.SectionA
].getLoadAddressWithOffset(RE
.Addend
);
237 assert(Result
<= UINT32_MAX
&& "relocation overflow");
238 LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE
.Offset
239 << " RelType: IMAGE_REL_ARM_MOV32T"
240 << " TargetSection: " << RE
.Sections
.SectionA
241 << " Value: " << format("0x%08" PRIx32
, Result
)
244 // MOVW(T3): |11110|i|10|0|1|0|0|imm4|0|imm3|Rd|imm8|
245 // imm32 = zext imm4:i:imm3:imm8
246 // MOVT(T1): |11110|i|10|1|1|0|0|imm4|0|imm3|Rd|imm8|
247 // imm16 = imm4:i:imm3:imm8
249 auto EncodeImmediate
= [](uint8_t *Bytes
, uint16_t Immediate
) {
250 Bytes
[0] |= ((Immediate
& 0xf000) >> 12);
251 Bytes
[1] |= ((Immediate
& 0x0800) >> 11);
252 Bytes
[2] |= ((Immediate
& 0x00ff) >> 0);
253 Bytes
[3] |= (((Immediate
& 0x0700) >> 8) << 4);
256 EncodeImmediate(&Target
[0],
257 (static_cast<uint32_t>(Result
) >> 00) | ISASelectionBit
);
258 EncodeImmediate(&Target
[4], static_cast<uint32_t>(Result
) >> 16);
262 case COFF::IMAGE_REL_ARM_BRANCH20T
: {
263 // The most significant 20-bits of the signed 21-bit relative displacement
265 RE
.Addend
- (Sections
[RE
.SectionID
].getLoadAddress() + RE
.Offset
) - 4;
266 assert(static_cast<int64_t>(RE
.Addend
) <= INT32_MAX
&&
267 "relocation overflow");
268 assert(static_cast<int64_t>(RE
.Addend
) >= INT32_MIN
&&
269 "relocation underflow");
270 LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE
.Offset
271 << " RelType: IMAGE_REL_ARM_BRANCH20T"
272 << " Value: " << static_cast<int32_t>(Value
) << '\n');
273 static_cast<void>(Value
);
274 llvm_unreachable("unimplemented relocation");
277 case COFF::IMAGE_REL_ARM_BRANCH24T
: {
278 // The most significant 24-bits of the signed 25-bit relative displacement
280 RE
.Addend
- (Sections
[RE
.SectionID
].getLoadAddress() + RE
.Offset
) - 4;
281 assert(static_cast<int64_t>(RE
.Addend
) <= INT32_MAX
&&
282 "relocation overflow");
283 assert(static_cast<int64_t>(RE
.Addend
) >= INT32_MIN
&&
284 "relocation underflow");
285 LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE
.Offset
286 << " RelType: IMAGE_REL_ARM_BRANCH24T"
287 << " Value: " << static_cast<int32_t>(Value
) << '\n');
288 static_cast<void>(Value
);
289 llvm_unreachable("unimplemented relocation");
292 case COFF::IMAGE_REL_ARM_BLX23T
: {
293 // The most significant 24-bits of the signed 25-bit relative displacement
295 RE
.Addend
- (Sections
[RE
.SectionID
].getLoadAddress() + RE
.Offset
) - 4;
296 assert(static_cast<int64_t>(RE
.Addend
) <= INT32_MAX
&&
297 "relocation overflow");
298 assert(static_cast<int64_t>(RE
.Addend
) >= INT32_MIN
&&
299 "relocation underflow");
300 LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE
.Offset
301 << " RelType: IMAGE_REL_ARM_BLX23T"
302 << " Value: " << static_cast<int32_t>(Value
) << '\n');
303 static_cast<void>(Value
);
304 llvm_unreachable("unimplemented relocation");
310 void registerEHFrames() override
{}