1 //===--- RuntimeDyldCOFFI386.h --- COFF/X86_64 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 x86 support for MC-JIT runtime dynamic linker.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFI386_H
14 #define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFI386_H
15 
16 #include "../RuntimeDyldCOFF.h"
17 #include "llvm/BinaryFormat/COFF.h"
18 #include "llvm/Object/COFF.h"
19 
20 #define DEBUG_TYPE "dyld"
21 
22 namespace llvm {
23 
24 class RuntimeDyldCOFFI386 : public RuntimeDyldCOFF {
25 public:
26   RuntimeDyldCOFFI386(RuntimeDyld::MemoryManager &MM,
27                       JITSymbolResolver &Resolver)
28       : RuntimeDyldCOFF(MM, Resolver, 4, COFF::IMAGE_REL_I386_DIR32) {}
29 
30   unsigned getMaxStubSize() const override {
31     return 8; // 2-byte jmp instruction + 32-bit relative address + 2 byte pad
32   }
33 
34   unsigned getStubAlignment() override { return 1; }
35 
36   Expected<object::relocation_iterator>
37   processRelocationRef(unsigned SectionID,
38                        object::relocation_iterator RelI,
39                        const object::ObjectFile &Obj,
40                        ObjSectionToIDMap &ObjSectionToID,
41                        StubMap &Stubs) override {
42 
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     bool IsExtern = Section == Obj.section_end();
57 
58     uint64_t RelType = RelI->getType();
59     uint64_t Offset = RelI->getOffset();
60 
61     unsigned TargetSectionID = -1;
62     uint64_t TargetOffset = -1;
63     if (TargetName.startswith(getImportSymbolPrefix())) {
64       TargetSectionID = SectionID;
65       TargetOffset = getDLLImportOffset(SectionID, Stubs, TargetName, true);
66       TargetName = StringRef();
67       IsExtern = false;
68     } else if (!IsExtern) {
69       if (auto TargetSectionIDOrErr = findOrEmitSection(
70               Obj, *Section, Section->isText(), ObjSectionToID))
71         TargetSectionID = *TargetSectionIDOrErr;
72       else
73         return TargetSectionIDOrErr.takeError();
74       if (RelType != COFF::IMAGE_REL_I386_SECTION)
75         TargetOffset = getSymbolOffset(*Symbol);
76     }
77 
78     // Determine the Addend used to adjust the relocation value.
79     uint64_t Addend = 0;
80     SectionEntry &AddendSection = Sections[SectionID];
81     uintptr_t ObjTarget = AddendSection.getObjAddress() + Offset;
82     uint8_t *Displacement = (uint8_t *)ObjTarget;
83 
84     switch (RelType) {
85     case COFF::IMAGE_REL_I386_DIR32:
86     case COFF::IMAGE_REL_I386_DIR32NB:
87     case COFF::IMAGE_REL_I386_SECREL:
88     case COFF::IMAGE_REL_I386_REL32: {
89       Addend = readBytesUnaligned(Displacement, 4);
90       break;
91     }
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     if (IsExtern) {
105       RelocationEntry RE(SectionID, Offset, RelType, 0, -1, 0, 0, 0, false, 0);
106       addRelocationForSymbol(RE, TargetName);
107     } else {
108 
109       switch (RelType) {
110       case COFF::IMAGE_REL_I386_ABSOLUTE:
111         // This relocation is ignored.
112         break;
113       case COFF::IMAGE_REL_I386_DIR32:
114       case COFF::IMAGE_REL_I386_DIR32NB:
115       case COFF::IMAGE_REL_I386_REL32: {
116         RelocationEntry RE =
117             RelocationEntry(SectionID, Offset, RelType, Addend, TargetSectionID,
118                             TargetOffset, 0, 0, false, 0);
119         addRelocationForSection(RE, TargetSectionID);
120         break;
121       }
122       case COFF::IMAGE_REL_I386_SECTION: {
123         RelocationEntry RE =
124             RelocationEntry(TargetSectionID, Offset, RelType, 0);
125         addRelocationForSection(RE, TargetSectionID);
126         break;
127       }
128       case COFF::IMAGE_REL_I386_SECREL: {
129         RelocationEntry RE =
130             RelocationEntry(SectionID, Offset, RelType, TargetOffset + Addend);
131         addRelocationForSection(RE, TargetSectionID);
132         break;
133       }
134       default:
135         llvm_unreachable("unsupported relocation type");
136       }
137     }
138 
139     return ++RelI;
140   }
141 
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     case COFF::IMAGE_REL_I386_ABSOLUTE:
148       // This relocation is ignored.
149       break;
150     case COFF::IMAGE_REL_I386_DIR32: {
151       // The target's 32-bit VA.
152       uint64_t Result =
153           RE.Sections.SectionA == static_cast<uint32_t>(-1)
154               ? Value
155               : Sections[RE.Sections.SectionA].getLoadAddressWithOffset(
156                     RE.Addend);
157       assert(Result <= UINT32_MAX && "relocation overflow");
158       LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
159                         << " RelType: IMAGE_REL_I386_DIR32"
160                         << " TargetSection: " << RE.Sections.SectionA
161                         << " Value: " << format("0x%08" PRIx32, Result)
162                         << '\n');
163       writeBytesUnaligned(Result, Target, 4);
164       break;
165     }
166     case COFF::IMAGE_REL_I386_DIR32NB: {
167       // The target's 32-bit RVA.
168       // NOTE: use Section[0].getLoadAddress() as an approximation of ImageBase
169       uint64_t Result =
170           Sections[RE.Sections.SectionA].getLoadAddressWithOffset(RE.Addend) -
171           Sections[0].getLoadAddress();
172       assert(Result <= UINT32_MAX && "relocation overflow");
173       LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
174                         << " RelType: IMAGE_REL_I386_DIR32NB"
175                         << " TargetSection: " << RE.Sections.SectionA
176                         << " Value: " << format("0x%08" PRIx32, Result)
177                         << '\n');
178       writeBytesUnaligned(Result, Target, 4);
179       break;
180     }
181     case COFF::IMAGE_REL_I386_REL32: {
182       // 32-bit relative displacement to the target.
183       uint64_t Result = RE.Sections.SectionA == static_cast<uint32_t>(-1)
184                             ? Value
185                             : Sections[RE.Sections.SectionA].getLoadAddress();
186       Result = Result - Section.getLoadAddress() + RE.Addend - 4 - RE.Offset;
187       assert(static_cast<int64_t>(Result) <= INT32_MAX &&
188              "relocation overflow");
189       assert(static_cast<int64_t>(Result) >= INT32_MIN &&
190              "relocation underflow");
191       LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
192                         << " RelType: IMAGE_REL_I386_REL32"
193                         << " TargetSection: " << RE.Sections.SectionA
194                         << " Value: " << format("0x%08" PRIx32, Result)
195                         << '\n');
196       writeBytesUnaligned(Result, Target, 4);
197       break;
198     }
199     case COFF::IMAGE_REL_I386_SECTION:
200       // 16-bit section index of the section that contains the target.
201       assert(static_cast<uint32_t>(RE.SectionID) <= UINT16_MAX &&
202              "relocation overflow");
203       LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
204                         << " RelType: IMAGE_REL_I386_SECTION Value: "
205                         << RE.SectionID << '\n');
206       writeBytesUnaligned(RE.SectionID, Target, 2);
207       break;
208     case COFF::IMAGE_REL_I386_SECREL:
209       // 32-bit offset of the target from the beginning of its section.
210       assert(static_cast<uint64_t>(RE.Addend) <= UINT32_MAX &&
211              "relocation overflow");
212       LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
213                         << " RelType: IMAGE_REL_I386_SECREL Value: "
214                         << RE.Addend << '\n');
215       writeBytesUnaligned(RE.Addend, Target, 4);
216       break;
217     default:
218       llvm_unreachable("unsupported relocation type");
219     }
220   }
221 
222   void registerEHFrames() override {}
223 };
224 
225 }
226 
227 #endif
228 
229