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