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 | Align getStubAlignment() override { return Align(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(reason: "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.starts_with(Prefix: getImportSymbolPrefix())) { |
64 | TargetSectionID = SectionID; |
65 | TargetOffset = getDLLImportOffset(SectionID, Stubs, Name: TargetName, SetSectionIDMinus1: true); |
66 | TargetName = StringRef(); |
67 | IsExtern = false; |
68 | } else if (!IsExtern) { |
69 | if (auto TargetSectionIDOrErr = findOrEmitSection( |
70 | Obj, Section: *Section, IsCode: Section->isText(), LocalSections&: ObjSectionToID)) |
71 | TargetSectionID = *TargetSectionIDOrErr; |
72 | else |
73 | return TargetSectionIDOrErr.takeError(); |
74 | if (RelType != COFF::IMAGE_REL_I386_SECTION) |
75 | TargetOffset = getSymbolOffset(Sym: *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(Src: Displacement, Size: 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, SymbolName: 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, SectionID: TargetSectionID); |
120 | break; |
121 | } |
122 | case COFF::IMAGE_REL_I386_SECTION: { |
123 | RelocationEntry RE = |
124 | RelocationEntry(TargetSectionID, Offset, RelType, 0); |
125 | addRelocationForSection(RE, SectionID: TargetSectionID); |
126 | break; |
127 | } |
128 | case COFF::IMAGE_REL_I386_SECREL: { |
129 | RelocationEntry RE = |
130 | RelocationEntry(SectionID, Offset, RelType, TargetOffset + Addend); |
131 | addRelocationForSection(RE, SectionID: 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(OffsetBytes: 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 | OffsetBytes: 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(Value: Result, Dst: Target, Size: 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(OffsetBytes: 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(Value: Result, Dst: Target, Size: 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(Value: Result, Dst: Target, Size: 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(Value: RE.SectionID, Dst: Target, Size: 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(Value: RE.Addend, Dst: Target, Size: 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 | |