blob: 8c6af0bd9c6dc54778214e632fa46c6c93b8eede [file] [log] [blame]
Saleem Abdulrasoolf6b5f0f2016-06-24 14:11:44 +00001//===--- RuntimeDyldCOFFThumb.h --- COFF/Thumb specific code ---*- C++ --*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// COFF thumb support for MC-JIT runtime dynamic linker.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFTHUMB_H
15#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFTHUMB_H
16
17#include "llvm/Object/COFF.h"
18#include "llvm/Support/COFF.h"
19#include "../RuntimeDyldCOFF.h"
20
21#define DEBUG_TYPE "dyld"
22
23namespace llvm {
24
Walter Erquinigob58d6a52016-10-17 18:56:18 +000025static bool isThumbFunc(symbol_iterator Symbol, const ObjectFile &Obj,
26 section_iterator Section) {
27 Expected<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);
34 }
35
36 if (*SymTypeOrErr != 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<COFFObjectFile>(Obj).getCOFFSection(*Section)->Characteristics &
42 COFF::IMAGE_SCN_MEM_16BIT;
43}
44
Saleem Abdulrasoolf6b5f0f2016-06-24 14:11:44 +000045class RuntimeDyldCOFFThumb : public RuntimeDyldCOFF {
46public:
47 RuntimeDyldCOFFThumb(RuntimeDyld::MemoryManager &MM,
Lang Hamesad4a9112016-08-01 20:49:11 +000048 JITSymbolResolver &Resolver)
Saleem Abdulrasoolf6b5f0f2016-06-24 14:11:44 +000049 : RuntimeDyldCOFF(MM, Resolver) {}
50
51 unsigned getMaxStubSize() override {
52 return 16; // 8-byte load instructions, 4-byte jump, 4-byte padding
53 }
54
55 unsigned getStubAlignment() override { return 1; }
56
57 Expected<relocation_iterator>
58 processRelocationRef(unsigned SectionID,
59 relocation_iterator RelI,
60 const ObjectFile &Obj,
61 ObjSectionToIDMap &ObjSectionToID,
62 StubMap &Stubs) override {
63 auto Symbol = RelI->getSymbol();
64 if (Symbol == Obj.symbol_end())
65 report_fatal_error("Unknown symbol in relocation");
66
67 Expected<StringRef> TargetNameOrErr = Symbol->getName();
68 if (!TargetNameOrErr)
69 return TargetNameOrErr.takeError();
70 StringRef TargetName = *TargetNameOrErr;
71
72 auto SectionOrErr = Symbol->getSection();
73 if (!SectionOrErr)
74 return SectionOrErr.takeError();
75 auto Section = *SectionOrErr;
76
77 uint64_t RelType = RelI->getType();
78 uint64_t Offset = RelI->getOffset();
79
80 // Determine the Addend used to adjust the relocation value.
81 uint64_t Addend = 0;
82 SectionEntry &AddendSection = Sections[SectionID];
83 uintptr_t ObjTarget = AddendSection.getObjAddress() + Offset;
84 uint8_t *Displacement = (uint8_t *)ObjTarget;
85
86 switch (RelType) {
87 case COFF::IMAGE_REL_ARM_ADDR32:
88 case COFF::IMAGE_REL_ARM_ADDR32NB:
89 case COFF::IMAGE_REL_ARM_SECREL:
90 Addend = readBytesUnaligned(Displacement, 4);
91 break;
92 default:
93 break;
94 }
95
96#if !defined(NDEBUG)
97 SmallString<32> RelTypeName;
98 RelI->getTypeName(RelTypeName);
99#endif
100 DEBUG(dbgs() << "\t\tIn Section " << SectionID << " Offset " << Offset
101 << " RelType: " << RelTypeName << " TargetName: " << TargetName
102 << " Addend " << Addend << "\n");
103
104 unsigned TargetSectionID = -1;
105 if (Section == Obj.section_end()) {
106 RelocationEntry RE(SectionID, Offset, RelType, 0, -1, 0, 0, 0, false, 0);
107 addRelocationForSymbol(RE, TargetName);
108 } else {
109 if (auto TargetSectionIDOrErr =
110 findOrEmitSection(Obj, *Section, Section->isText(), ObjSectionToID))
111 TargetSectionID = *TargetSectionIDOrErr;
112 else
113 return TargetSectionIDOrErr.takeError();
114
Walter Erquinigob58d6a52016-10-17 18:56:18 +0000115 // We need to find out if the relocation is relative to a thumb function
116 // so that we include the ISA selection bit when resolve the relocation
117 bool IsTargetThumbFunc = isThumbFunc(Symbol, Obj, Section);
118
Saleem Abdulrasoolf6b5f0f2016-06-24 14:11:44 +0000119 switch (RelType) {
120 default: llvm_unreachable("unsupported relocation type");
121 case COFF::IMAGE_REL_ARM_ABSOLUTE:
122 // This relocation is ignored.
123 break;
Walter Erquinigob58d6a52016-10-17 18:56:18 +0000124 case COFF::IMAGE_REL_ARM_ADDR32: {
125 RelocationEntry RE = RelocationEntry(
126 SectionID, Offset, RelType, Addend, TargetSectionID,
127 getSymbolOffset(*Symbol), 0, 0, false, 0, IsTargetThumbFunc);
128 addRelocationForSection(RE, TargetSectionID);
129 break;
130 }
Saleem Abdulrasoolf6b5f0f2016-06-24 14:11:44 +0000131 case COFF::IMAGE_REL_ARM_ADDR32NB: {
132 RelocationEntry RE =
133 RelocationEntry(SectionID, Offset, RelType, Addend, TargetSectionID,
134 getSymbolOffset(*Symbol), 0, 0, false, 0);
135 addRelocationForSection(RE, TargetSectionID);
136 break;
137 }
138 case COFF::IMAGE_REL_ARM_SECTION: {
139 RelocationEntry RE =
140 RelocationEntry(TargetSectionID, Offset, RelType, 0);
141 addRelocationForSection(RE, TargetSectionID);
142 break;
143 }
144 case COFF::IMAGE_REL_ARM_SECREL: {
145 RelocationEntry RE = RelocationEntry(SectionID, Offset, RelType,
146 getSymbolOffset(*Symbol) + Addend);
147 addRelocationForSection(RE, TargetSectionID);
148 break;
149 }
150 case COFF::IMAGE_REL_ARM_MOV32T: {
Walter Erquinigob58d6a52016-10-17 18:56:18 +0000151 RelocationEntry RE = RelocationEntry(
152 SectionID, Offset, RelType, Addend, TargetSectionID,
153 getSymbolOffset(*Symbol), 0, 0, false, 0, IsTargetThumbFunc);
Saleem Abdulrasoolf6b5f0f2016-06-24 14:11:44 +0000154 addRelocationForSection(RE, TargetSectionID);
155 break;
156 }
157 case COFF::IMAGE_REL_ARM_BRANCH20T:
158 case COFF::IMAGE_REL_ARM_BRANCH24T:
159 case COFF::IMAGE_REL_ARM_BLX23T: {
160 RelocationEntry RE =
161 RelocationEntry(SectionID, Offset, RelType,
162 getSymbolOffset(*Symbol) + Addend, true, 0);
163 addRelocationForSection(RE, TargetSectionID);
164 break;
165 }
166 }
167 }
168
169 return ++RelI;
170 }
171
172 void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override {
173 const auto Section = Sections[RE.SectionID];
174 uint8_t *Target = Section.getAddressWithOffset(RE.Offset);
Walter Erquinigob58d6a52016-10-17 18:56:18 +0000175 int ISASelectionBit = RE.IsTargetThumbFunc ? 1 : 0;
Saleem Abdulrasoolf6b5f0f2016-06-24 14:11:44 +0000176
177 switch (RE.RelType) {
178 default: llvm_unreachable("unsupported relocation type");
179 case COFF::IMAGE_REL_ARM_ABSOLUTE:
180 // This relocation is ignored.
181 break;
182 case COFF::IMAGE_REL_ARM_ADDR32: {
183 // The target's 32-bit VA.
184 uint64_t Result =
185 RE.Sections.SectionA == static_cast<uint32_t>(-1)
186 ? Value
187 : Sections[RE.Sections.SectionA].getLoadAddressWithOffset(RE.Addend);
Walter Erquinigob58d6a52016-10-17 18:56:18 +0000188 Result |= ISASelectionBit;
Saleem Abdulrasoolf6b5f0f2016-06-24 14:11:44 +0000189 assert(static_cast<int32_t>(Result) <= INT32_MAX &&
190 "relocation overflow");
191 assert(static_cast<int32_t>(Result) >= INT32_MIN &&
192 "relocation underflow");
193 DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
194 << " RelType: IMAGE_REL_ARM_ADDR32"
195 << " TargetSection: " << RE.Sections.SectionA
196 << " Value: " << format("0x%08" PRIx32, Result) << '\n');
197 writeBytesUnaligned(Result, Target, 4);
198 break;
199 }
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(static_cast<int32_t>(Result) <= INT32_MAX &&
206 "relocation overflow");
207 assert(static_cast<int32_t>(Result) >= INT32_MIN &&
208 "relocation underflow");
209 DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
210 << " RelType: IMAGE_REL_ARM_ADDR32NB"
211 << " TargetSection: " << RE.Sections.SectionA
212 << " Value: " << format("0x%08" PRIx32, Result) << '\n');
Walter Erquinigob58d6a52016-10-17 18:56:18 +0000213 Result |= ISASelectionBit;
Saleem Abdulrasoolf6b5f0f2016-06-24 14:11:44 +0000214 writeBytesUnaligned(Result, Target, 4);
215 break;
216 }
217 case COFF::IMAGE_REL_ARM_SECTION:
218 // 16-bit section index of the section that contains the target.
219 assert(static_cast<int32_t>(RE.SectionID) <= INT16_MAX &&
220 "relocation overflow");
221 assert(static_cast<int32_t>(RE.SectionID) >= INT16_MIN &&
222 "relocation underflow");
223 DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
224 << " RelType: IMAGE_REL_ARM_SECTION Value: " << RE.SectionID
225 << '\n');
226 writeBytesUnaligned(RE.SectionID, Target, 2);
227 break;
228 case COFF::IMAGE_REL_ARM_SECREL:
229 // 32-bit offset of the target from the beginning of its section.
230 assert(static_cast<int32_t>(RE.Addend) <= INT32_MAX &&
231 "relocation overflow");
232 assert(static_cast<int32_t>(RE.Addend) >= INT32_MIN &&
233 "relocation underflow");
234 DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
235 << " RelType: IMAGE_REL_ARM_SECREL Value: " << RE.Addend
236 << '\n');
237 writeBytesUnaligned(RE.Addend, Target, 2);
238 break;
239 case COFF::IMAGE_REL_ARM_MOV32T: {
240 // 32-bit VA of the target applied to a contiguous MOVW+MOVT pair.
241 uint64_t Result =
242 Sections[RE.Sections.SectionA].getLoadAddressWithOffset(RE.Addend);
243 assert(static_cast<int32_t>(Result) <= INT32_MAX &&
244 "relocation overflow");
245 assert(static_cast<int32_t>(Result) >= INT32_MIN &&
246 "relocation underflow");
247 DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
248 << " RelType: IMAGE_REL_ARM_MOV32T"
249 << " TargetSection: " << RE.Sections.SectionA
250 << " Value: " << format("0x%08" PRIx32, Result) << '\n');
251
252 // MOVW(T3): |11110|i|10|0|1|0|0|imm4|0|imm3|Rd|imm8|
253 // imm32 = zext imm4:i:imm3:imm8
254 // MOVT(T1): |11110|i|10|1|1|0|0|imm4|0|imm3|Rd|imm8|
255 // imm16 = imm4:i:imm3:imm8
256
257 auto EncodeImmediate = [](uint8_t *Bytes, uint16_t Immediate) {
258 Bytes[0] |= ((Immediate & 0xf000) >> 12);
259 Bytes[1] |= ((Immediate & 0x0800) >> 11);
260 Bytes[2] |= ((Immediate & 0x00ff) >> 0);
Saleem Abdulrasoolef721072016-08-29 20:42:03 +0000261 Bytes[3] |= (((Immediate & 0x0700) >> 8) << 4);
Saleem Abdulrasoolf6b5f0f2016-06-24 14:11:44 +0000262 };
263
Walter Erquinigob58d6a52016-10-17 18:56:18 +0000264 EncodeImmediate(&Target[0],
265 (static_cast<uint32_t>(Result) >> 00) | ISASelectionBit);
Saleem Abdulrasoolf6b5f0f2016-06-24 14:11:44 +0000266 EncodeImmediate(&Target[4], static_cast<uint32_t>(Result) >> 16);
267
268 break;
269 }
270 case COFF::IMAGE_REL_ARM_BRANCH20T: {
271 // The most significant 20-bits of the signed 21-bit relative displacement
272 uint64_t Value =
273 RE.Addend - (Sections[RE.SectionID].getLoadAddress() + RE.Offset) - 4;
274 assert(static_cast<int32_t>(RE.Addend) <= INT32_MAX &&
275 "relocation overflow");
276 assert(static_cast<int32_t>(RE.Addend) >= INT32_MIN &&
277 "relocation underflow");
278 DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
279 << " RelType: IMAGE_REL_ARM_BRANCH20T"
280 << " Value: " << static_cast<int32_t>(Value) << '\n');
Saleem Abdulrasoole7050742016-06-24 14:31:09 +0000281 static_cast<void>(Value);
Saleem Abdulrasoolf6b5f0f2016-06-24 14:11:44 +0000282 llvm_unreachable("unimplemented relocation");
283 break;
284 }
285 case COFF::IMAGE_REL_ARM_BRANCH24T: {
286 // The most significant 24-bits of the signed 25-bit relative displacement
287 uint64_t Value =
288 RE.Addend - (Sections[RE.SectionID].getLoadAddress() + RE.Offset) - 4;
289 assert(static_cast<int32_t>(RE.Addend) <= INT32_MAX &&
290 "relocation overflow");
291 assert(static_cast<int32_t>(RE.Addend) >= INT32_MIN &&
292 "relocation underflow");
293 DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
294 << " RelType: IMAGE_REL_ARM_BRANCH24T"
295 << " Value: " << static_cast<int32_t>(Value) << '\n');
Saleem Abdulrasoole7050742016-06-24 14:31:09 +0000296 static_cast<void>(Value);
Saleem Abdulrasoolf6b5f0f2016-06-24 14:11:44 +0000297 llvm_unreachable("unimplemented relocation");
298 break;
299 }
300 case COFF::IMAGE_REL_ARM_BLX23T: {
301 // The most significant 24-bits of the signed 25-bit relative displacement
302 uint64_t Value =
303 RE.Addend - (Sections[RE.SectionID].getLoadAddress() + RE.Offset) - 4;
304 assert(static_cast<int32_t>(RE.Addend) <= INT32_MAX &&
305 "relocation overflow");
306 assert(static_cast<int32_t>(RE.Addend) >= INT32_MIN &&
307 "relocation underflow");
308 DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
309 << " RelType: IMAGE_REL_ARM_BLX23T"
310 << " Value: " << static_cast<int32_t>(Value) << '\n');
Saleem Abdulrasoole7050742016-06-24 14:31:09 +0000311 static_cast<void>(Value);
Saleem Abdulrasoolf6b5f0f2016-06-24 14:11:44 +0000312 llvm_unreachable("unimplemented relocation");
313 break;
314 }
315 }
316 }
317
318 void registerEHFrames() override {}
319 void deregisterEHFrames() override {}
320};
321
322}
323
324#endif
325