Line data Source code
1 : //===--- 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 "../RuntimeDyldCOFF.h"
18 : #include "llvm/BinaryFormat/COFF.h"
19 : #include "llvm/Object/COFF.h"
20 :
21 : #define DEBUG_TYPE "dyld"
22 :
23 : namespace llvm {
24 :
25 10 : static bool isThumbFunc(symbol_iterator Symbol, const ObjectFile &Obj,
26 : section_iterator Section) {
27 : Expected<SymbolRef::Type> SymTypeOrErr = Symbol->getType();
28 10 : if (!SymTypeOrErr) {
29 : std::string Buf;
30 : raw_string_ostream OS(Buf);
31 0 : logAllUnhandledErrors(SymTypeOrErr.takeError(), OS, "");
32 : OS.flush();
33 0 : report_fatal_error(Buf);
34 : }
35 :
36 10 : 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 2 : return cast<COFFObjectFile>(Obj).getCOFFSection(*Section)->Characteristics &
42 2 : COFF::IMAGE_SCN_MEM_16BIT;
43 : }
44 :
45 : class RuntimeDyldCOFFThumb : public RuntimeDyldCOFF {
46 : public:
47 : RuntimeDyldCOFFThumb(RuntimeDyld::MemoryManager &MM,
48 : JITSymbolResolver &Resolver)
49 1 : : RuntimeDyldCOFF(MM, Resolver) {}
50 :
51 4 : unsigned getMaxStubSize() override {
52 4 : return 16; // 8-byte load instructions, 4-byte jump, 4-byte padding
53 : }
54 :
55 6 : unsigned getStubAlignment() override { return 1; }
56 :
57 : Expected<relocation_iterator>
58 13 : processRelocationRef(unsigned SectionID,
59 : relocation_iterator RelI,
60 : const ObjectFile &Obj,
61 : ObjSectionToIDMap &ObjSectionToID,
62 : StubMap &Stubs) override {
63 13 : auto Symbol = RelI->getSymbol();
64 13 : if (Symbol == Obj.symbol_end())
65 0 : report_fatal_error("Unknown symbol in relocation");
66 :
67 : Expected<StringRef> TargetNameOrErr = Symbol->getName();
68 13 : if (!TargetNameOrErr)
69 : return TargetNameOrErr.takeError();
70 13 : StringRef TargetName = *TargetNameOrErr;
71 :
72 : auto SectionOrErr = Symbol->getSection();
73 13 : if (!SectionOrErr)
74 : return SectionOrErr.takeError();
75 13 : auto Section = *SectionOrErr;
76 :
77 13 : uint64_t RelType = RelI->getType();
78 13 : uint64_t Offset = RelI->getOffset();
79 :
80 : // Determine the Addend used to adjust the relocation value.
81 : uint64_t Addend = 0;
82 13 : SectionEntry &AddendSection = Sections[SectionID];
83 13 : uintptr_t ObjTarget = AddendSection.getObjAddress() + Offset;
84 13 : uint8_t *Displacement = (uint8_t *)ObjTarget;
85 :
86 : switch (RelType) {
87 6 : case COFF::IMAGE_REL_ARM_ADDR32:
88 : case COFF::IMAGE_REL_ARM_ADDR32NB:
89 : case COFF::IMAGE_REL_ARM_SECREL:
90 6 : Addend = readBytesUnaligned(Displacement, 4);
91 6 : break;
92 : default:
93 : break;
94 : }
95 :
96 : #if !defined(NDEBUG)
97 : SmallString<32> RelTypeName;
98 : RelI->getTypeName(RelTypeName);
99 : #endif
100 : LLVM_DEBUG(dbgs() << "\t\tIn Section " << SectionID << " Offset " << Offset
101 : << " RelType: " << RelTypeName << " TargetName: "
102 : << TargetName << " Addend " << Addend << "\n");
103 :
104 : unsigned TargetSectionID = -1;
105 13 : if (Section == Obj.section_end()) {
106 3 : RelocationEntry RE(SectionID, Offset, RelType, 0, -1, 0, 0, 0, false, 0);
107 3 : addRelocationForSymbol(RE, TargetName);
108 : } else {
109 10 : if (auto TargetSectionIDOrErr =
110 10 : findOrEmitSection(Obj, *Section, Section->isText(), ObjSectionToID))
111 10 : TargetSectionID = *TargetSectionIDOrErr;
112 : else
113 : return TargetSectionIDOrErr.takeError();
114 :
115 : // 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 10 : bool IsTargetThumbFunc = isThumbFunc(Symbol, Obj, Section);
118 :
119 10 : switch (RelType) {
120 0 : default: llvm_unreachable("unsupported relocation type");
121 : case COFF::IMAGE_REL_ARM_ABSOLUTE:
122 : // This relocation is ignored.
123 : break;
124 0 : case COFF::IMAGE_REL_ARM_ADDR32: {
125 : RelocationEntry RE = RelocationEntry(
126 : SectionID, Offset, RelType, Addend, TargetSectionID,
127 0 : getSymbolOffset(*Symbol), 0, 0, false, 0, IsTargetThumbFunc);
128 0 : addRelocationForSection(RE, TargetSectionID);
129 : break;
130 : }
131 1 : case COFF::IMAGE_REL_ARM_ADDR32NB: {
132 : RelocationEntry RE =
133 : RelocationEntry(SectionID, Offset, RelType, Addend, TargetSectionID,
134 1 : getSymbolOffset(*Symbol), 0, 0, false, 0);
135 1 : addRelocationForSection(RE, TargetSectionID);
136 : break;
137 : }
138 1 : case COFF::IMAGE_REL_ARM_SECTION: {
139 : RelocationEntry RE =
140 1 : RelocationEntry(TargetSectionID, Offset, RelType, 0);
141 1 : addRelocationForSection(RE, TargetSectionID);
142 : break;
143 : }
144 2 : case COFF::IMAGE_REL_ARM_SECREL: {
145 : RelocationEntry RE = RelocationEntry(SectionID, Offset, RelType,
146 2 : getSymbolOffset(*Symbol) + Addend);
147 2 : addRelocationForSection(RE, TargetSectionID);
148 : break;
149 : }
150 6 : case COFF::IMAGE_REL_ARM_MOV32T: {
151 : RelocationEntry RE = RelocationEntry(
152 : SectionID, Offset, RelType, Addend, TargetSectionID,
153 6 : getSymbolOffset(*Symbol), 0, 0, false, 0, IsTargetThumbFunc);
154 6 : addRelocationForSection(RE, TargetSectionID);
155 : break;
156 : }
157 0 : 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 0 : getSymbolOffset(*Symbol) + Addend, true, 0);
163 0 : addRelocationForSection(RE, TargetSectionID);
164 : break;
165 : }
166 : }
167 : }
168 :
169 : return ++RelI;
170 : }
171 :
172 13 : void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override {
173 26 : const auto Section = Sections[RE.SectionID];
174 13 : uint8_t *Target = Section.getAddressWithOffset(RE.Offset);
175 13 : int ISASelectionBit = RE.IsTargetThumbFunc ? 1 : 0;
176 :
177 13 : switch (RE.RelType) {
178 0 : default: llvm_unreachable("unsupported relocation type");
179 : case COFF::IMAGE_REL_ARM_ABSOLUTE:
180 : // This relocation is ignored.
181 : break;
182 3 : case COFF::IMAGE_REL_ARM_ADDR32: {
183 : // The target's 32-bit VA.
184 : uint64_t Result =
185 3 : RE.Sections.SectionA == static_cast<uint32_t>(-1)
186 3 : ? Value
187 0 : : Sections[RE.Sections.SectionA].getLoadAddressWithOffset(RE.Addend);
188 3 : Result |= ISASelectionBit;
189 : assert(Result <= UINT32_MAX && "relocation overflow");
190 : LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
191 : << " RelType: IMAGE_REL_ARM_ADDR32"
192 : << " TargetSection: " << RE.Sections.SectionA
193 : << " Value: " << format("0x%08" PRIx32, Result)
194 : << '\n');
195 3 : writeBytesUnaligned(Result, Target, 4);
196 3 : break;
197 : }
198 1 : case COFF::IMAGE_REL_ARM_ADDR32NB: {
199 : // The target's 32-bit RVA.
200 : // NOTE: use Section[0].getLoadAddress() as an approximation of ImageBase
201 1 : uint64_t Result = Sections[RE.Sections.SectionA].getLoadAddress() -
202 2 : Sections[0].getLoadAddress() + RE.Addend;
203 : assert(Result <= UINT32_MAX && "relocation overflow");
204 : LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
205 : << " RelType: IMAGE_REL_ARM_ADDR32NB"
206 : << " TargetSection: " << RE.Sections.SectionA
207 : << " Value: " << format("0x%08" PRIx32, Result)
208 : << '\n');
209 1 : Result |= ISASelectionBit;
210 1 : writeBytesUnaligned(Result, Target, 4);
211 1 : break;
212 : }
213 1 : case COFF::IMAGE_REL_ARM_SECTION:
214 : // 16-bit section index of the section that contains the target.
215 : assert(static_cast<uint32_t>(RE.SectionID) <= UINT16_MAX &&
216 : "relocation overflow");
217 : LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
218 : << " RelType: IMAGE_REL_ARM_SECTION Value: "
219 : << RE.SectionID << '\n');
220 1 : writeBytesUnaligned(RE.SectionID, Target, 2);
221 1 : break;
222 2 : case COFF::IMAGE_REL_ARM_SECREL:
223 : // 32-bit offset of the target from the beginning of its section.
224 : assert(static_cast<uint64_t>(RE.Addend) <= UINT32_MAX &&
225 : "relocation overflow");
226 : LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
227 : << " RelType: IMAGE_REL_ARM_SECREL Value: " << RE.Addend
228 : << '\n');
229 2 : writeBytesUnaligned(RE.Addend, Target, 2);
230 2 : break;
231 6 : case COFF::IMAGE_REL_ARM_MOV32T: {
232 : // 32-bit VA of the target applied to a contiguous MOVW+MOVT pair.
233 : uint64_t Result =
234 12 : Sections[RE.Sections.SectionA].getLoadAddressWithOffset(RE.Addend);
235 : assert(Result <= UINT32_MAX && "relocation overflow");
236 : LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
237 : << " RelType: IMAGE_REL_ARM_MOV32T"
238 : << " TargetSection: " << RE.Sections.SectionA
239 : << " Value: " << format("0x%08" PRIx32, Result)
240 : << '\n');
241 :
242 : // MOVW(T3): |11110|i|10|0|1|0|0|imm4|0|imm3|Rd|imm8|
243 : // imm32 = zext imm4:i:imm3:imm8
244 : // MOVT(T1): |11110|i|10|1|1|0|0|imm4|0|imm3|Rd|imm8|
245 : // imm16 = imm4:i:imm3:imm8
246 :
247 : auto EncodeImmediate = [](uint8_t *Bytes, uint16_t Immediate) {
248 12 : Bytes[0] |= ((Immediate & 0xf000) >> 12);
249 12 : Bytes[1] |= ((Immediate & 0x0800) >> 11);
250 12 : Bytes[2] |= ((Immediate & 0x00ff) >> 0);
251 12 : Bytes[3] |= (((Immediate & 0x0700) >> 8) << 4);
252 : };
253 :
254 6 : EncodeImmediate(&Target[0],
255 6 : (static_cast<uint32_t>(Result) >> 00) | ISASelectionBit);
256 6 : EncodeImmediate(&Target[4], static_cast<uint32_t>(Result) >> 16);
257 :
258 : break;
259 : }
260 : case COFF::IMAGE_REL_ARM_BRANCH20T: {
261 : // The most significant 20-bits of the signed 21-bit relative displacement
262 : uint64_t Value =
263 : RE.Addend - (Sections[RE.SectionID].getLoadAddress() + RE.Offset) - 4;
264 : assert(static_cast<int64_t>(RE.Addend) <= INT32_MAX &&
265 : "relocation overflow");
266 : assert(static_cast<int64_t>(RE.Addend) >= INT32_MIN &&
267 : "relocation underflow");
268 : LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
269 : << " RelType: IMAGE_REL_ARM_BRANCH20T"
270 : << " Value: " << static_cast<int32_t>(Value) << '\n');
271 : static_cast<void>(Value);
272 : llvm_unreachable("unimplemented relocation");
273 : break;
274 : }
275 : case COFF::IMAGE_REL_ARM_BRANCH24T: {
276 : // The most significant 24-bits of the signed 25-bit relative displacement
277 : uint64_t Value =
278 : RE.Addend - (Sections[RE.SectionID].getLoadAddress() + RE.Offset) - 4;
279 : assert(static_cast<int64_t>(RE.Addend) <= INT32_MAX &&
280 : "relocation overflow");
281 : assert(static_cast<int64_t>(RE.Addend) >= INT32_MIN &&
282 : "relocation underflow");
283 : LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
284 : << " RelType: IMAGE_REL_ARM_BRANCH24T"
285 : << " Value: " << static_cast<int32_t>(Value) << '\n');
286 : static_cast<void>(Value);
287 : llvm_unreachable("unimplemented relocation");
288 : break;
289 : }
290 : case COFF::IMAGE_REL_ARM_BLX23T: {
291 : // The most significant 24-bits of the signed 25-bit relative displacement
292 : uint64_t Value =
293 : RE.Addend - (Sections[RE.SectionID].getLoadAddress() + RE.Offset) - 4;
294 : assert(static_cast<int64_t>(RE.Addend) <= INT32_MAX &&
295 : "relocation overflow");
296 : assert(static_cast<int64_t>(RE.Addend) >= INT32_MIN &&
297 : "relocation underflow");
298 : LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
299 : << " RelType: IMAGE_REL_ARM_BLX23T"
300 : << " Value: " << static_cast<int32_t>(Value) << '\n');
301 : static_cast<void>(Value);
302 : llvm_unreachable("unimplemented relocation");
303 : break;
304 : }
305 : }
306 13 : }
307 :
308 1 : void registerEHFrames() override {}
309 : };
310 :
311 : }
312 :
313 : #endif
|