]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFThumb.h
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / contrib / llvm / lib / ExecutionEngine / RuntimeDyld / Targets / RuntimeDyldCOFFThumb.h
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 static 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
45 class RuntimeDyldCOFFThumb : public RuntimeDyldCOFF {
46 public:
47   RuntimeDyldCOFFThumb(RuntimeDyld::MemoryManager &MM,
48                        JITSymbolResolver &Resolver)
49       : 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     LLVM_DEBUG(dbgs() << "\t\tIn Section " << SectionID << " Offset " << Offset
101                       << " RelType: " << RelTypeName << " TargetName: "
102                       << TargetName << " 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
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       bool IsTargetThumbFunc = isThumbFunc(Symbol, Obj, Section);
118
119       switch (RelType) {
120       default: llvm_unreachable("unsupported relocation type");
121       case COFF::IMAGE_REL_ARM_ABSOLUTE:
122         // This relocation is ignored.
123         break;
124       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       }
131       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: {
151         RelocationEntry RE = RelocationEntry(
152             SectionID, Offset, RelType, Addend, TargetSectionID,
153             getSymbolOffset(*Symbol), 0, 0, false, 0, IsTargetThumbFunc);
154         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);
175     int ISASelectionBit = RE.IsTargetThumbFunc ? 1 : 0;
176
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);
188       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       writeBytesUnaligned(Result, Target, 4);
196       break;
197     }
198     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       uint64_t Result = Sections[RE.Sections.SectionA].getLoadAddress() -
202                         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       Result |= ISASelectionBit;
210       writeBytesUnaligned(Result, Target, 4);
211       break;
212     }
213     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       writeBytesUnaligned(RE.SectionID, Target, 2);
221       break;
222     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       writeBytesUnaligned(RE.Addend, Target, 2);
230       break;
231     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           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         Bytes[0] |= ((Immediate & 0xf000) >> 12);
249         Bytes[1] |= ((Immediate & 0x0800) >> 11);
250         Bytes[2] |= ((Immediate & 0x00ff) >>  0);
251         Bytes[3] |= (((Immediate & 0x0700) >>  8) << 4);
252       };
253
254       EncodeImmediate(&Target[0],
255                       (static_cast<uint32_t>(Result) >> 00) | ISASelectionBit);
256       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   }
307
308   void registerEHFrames() override {}
309 };
310
311 }
312
313 #endif