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
22namespace llvm {
23
24class RuntimeDyldCOFFI386 : public RuntimeDyldCOFF {
25public:
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