[InstCombine] Signed saturation tests. NFC
[llvm-complete.git] / lib / ExecutionEngine / RuntimeDyld / Targets / RuntimeDyldCOFFThumb.h
blobbb2e9626e0b07c538f1039b0a55395048d765b67
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.
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"
22 namespace llvm {
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();
28 if (!SymTypeOrErr) {
29 std::string Buf;
30 raw_string_ostream OS(Buf);
31 logAllUnhandledErrors(SymTypeOrErr.takeError(), OS);
32 OS.flush();
33 report_fatal_error(Buf);
36 if (*SymTypeOrErr != object::SymbolRef::ST_Function)
37 return false;
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 &
44 COFF::IMAGE_SCN_MEM_16BIT;
47 class RuntimeDyldCOFFThumb : public RuntimeDyldCOFF {
48 public:
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();
70 if (!TargetNameOrErr)
71 return TargetNameOrErr.takeError();
72 StringRef TargetName = *TargetNameOrErr;
74 auto SectionOrErr = Symbol->getSection();
75 if (!SectionOrErr)
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.
83 uint64_t Addend = 0;
84 SectionEntry &AddendSection = Sections[SectionID];
85 uintptr_t ObjTarget = AddendSection.getObjAddress() + Offset;
86 uint8_t *Displacement = (uint8_t *)ObjTarget;
88 switch (RelType) {
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);
93 break;
94 default:
95 break;
98 #if !defined(NDEBUG)
99 SmallString<32> RelTypeName;
100 RelI->getTypeName(RelTypeName);
101 #endif
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);
110 } else {
111 if (auto TargetSectionIDOrErr =
112 findOrEmitSection(Obj, *Section, Section->isText(), ObjSectionToID))
113 TargetSectionID = *TargetSectionIDOrErr;
114 else
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);
121 switch (RelType) {
122 default: llvm_unreachable("unsupported relocation type");
123 case COFF::IMAGE_REL_ARM_ABSOLUTE:
124 // This relocation is ignored.
125 break;
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);
131 break;
133 case COFF::IMAGE_REL_ARM_ADDR32NB: {
134 RelocationEntry RE =
135 RelocationEntry(SectionID, Offset, RelType, Addend, TargetSectionID,
136 getSymbolOffset(*Symbol), 0, 0, false, 0);
137 addRelocationForSection(RE, TargetSectionID);
138 break;
140 case COFF::IMAGE_REL_ARM_SECTION: {
141 RelocationEntry RE =
142 RelocationEntry(TargetSectionID, Offset, RelType, 0);
143 addRelocationForSection(RE, TargetSectionID);
144 break;
146 case COFF::IMAGE_REL_ARM_SECREL: {
147 RelocationEntry RE = RelocationEntry(SectionID, Offset, RelType,
148 getSymbolOffset(*Symbol) + Addend);
149 addRelocationForSection(RE, TargetSectionID);
150 break;
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);
157 break;
159 case COFF::IMAGE_REL_ARM_BRANCH20T:
160 case COFF::IMAGE_REL_ARM_BRANCH24T:
161 case COFF::IMAGE_REL_ARM_BLX23T: {
162 RelocationEntry RE =
163 RelocationEntry(SectionID, Offset, RelType,
164 getSymbolOffset(*Symbol) + Addend, true, 0);
165 addRelocationForSection(RE, TargetSectionID);
166 break;
171 return ++RelI;
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.
183 break;
184 case COFF::IMAGE_REL_ARM_ADDR32: {
185 // The target's 32-bit VA.
186 uint64_t Result =
187 RE.Sections.SectionA == static_cast<uint32_t>(-1)
188 ? Value
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)
196 << '\n');
197 writeBytesUnaligned(Result, Target, 4);
198 break;
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)
210 << '\n');
211 Result |= ISASelectionBit;
212 writeBytesUnaligned(Result, Target, 4);
213 break;
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);
223 break;
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
230 << '\n');
231 writeBytesUnaligned(RE.Addend, Target, 2);
232 break;
233 case COFF::IMAGE_REL_ARM_MOV32T: {
234 // 32-bit VA of the target applied to a contiguous MOVW+MOVT pair.
235 uint64_t Result =
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)
242 << '\n');
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);
260 break;
262 case COFF::IMAGE_REL_ARM_BRANCH20T: {
263 // The most significant 20-bits of the signed 21-bit relative displacement
264 uint64_t Value =
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");
275 break;
277 case COFF::IMAGE_REL_ARM_BRANCH24T: {
278 // The most significant 24-bits of the signed 25-bit relative displacement
279 uint64_t Value =
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");
290 break;
292 case COFF::IMAGE_REL_ARM_BLX23T: {
293 // The most significant 24-bits of the signed 25-bit relative displacement
294 uint64_t Value =
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");
305 break;
310 void registerEHFrames() override {}
315 #endif