Line data Source code
1 : //===-- RuntimeDyldCOFFX86_64.h --- COFF/X86_64 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 x86_x64 support for MC-JIT runtime dynamic linker.
11 : //
12 : //===----------------------------------------------------------------------===//
13 :
14 : #ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFF86_64_H
15 : #define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFF86_64_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 : class RuntimeDyldCOFFX86_64 : public RuntimeDyldCOFF {
26 :
27 : private:
28 : // When a module is loaded we save the SectionID of the unwind
29 : // sections in a table until we receive a request to register all
30 : // unregisteredEH frame sections with the memory manager.
31 : SmallVector<SID, 2> UnregisteredEHFrameSections;
32 : SmallVector<SID, 2> RegisteredEHFrameSections;
33 : uint64_t ImageBase;
34 :
35 : // Fake an __ImageBase pointer by returning the section with the lowest adress
36 : uint64_t getImageBase() {
37 5 : if (!ImageBase) {
38 3 : ImageBase = std::numeric_limits<uint64_t>::max();
39 17 : for (const SectionEntry &Section : Sections)
40 22 : ImageBase = std::min(ImageBase, Section.getLoadAddress());
41 : }
42 5 : return ImageBase;
43 : }
44 :
45 : void write32BitOffset(uint8_t *Target, int64_t Addend, uint64_t Delta) {
46 5 : uint64_t Result = Addend + Delta;
47 : assert(Result <= UINT32_MAX && "Relocation overflow");
48 0 : writeBytesUnaligned(Result, Target, 4);
49 : }
50 :
51 : public:
52 : RuntimeDyldCOFFX86_64(RuntimeDyld::MemoryManager &MM,
53 : JITSymbolResolver &Resolver)
54 2 : : RuntimeDyldCOFF(MM, Resolver), ImageBase(0) {}
55 :
56 14 : unsigned getStubAlignment() override { return 1; }
57 :
58 : // 2-byte jmp instruction + 32-bit relative address + 64-bit absolute jump
59 10 : unsigned getMaxStubSize() override { return 14; }
60 :
61 : // The target location for the relocation is described by RE.SectionID and
62 : // RE.Offset. RE.SectionID can be used to find the SectionEntry. Each
63 : // SectionEntry has three members describing its location.
64 : // SectionEntry::Address is the address at which the section has been loaded
65 : // into memory in the current (host) process. SectionEntry::LoadAddress is
66 : // the address that the section will have in the target process.
67 : // SectionEntry::ObjAddress is the address of the bits for this section in the
68 : // original emitted object image (also in the current address space).
69 : //
70 : // Relocations will be applied as if the section were loaded at
71 : // SectionEntry::LoadAddress, but they will be applied at an address based
72 : // on SectionEntry::Address. SectionEntry::ObjAddress will be used to refer
73 : // to Target memory contents if they are required for value calculations.
74 : //
75 : // The Value parameter here is the load address of the symbol for the
76 : // relocation to be applied. For relocations which refer to symbols in the
77 : // current object Value will be the LoadAddress of the section in which
78 : // the symbol resides (RE.Addend provides additional information about the
79 : // symbol location). For external symbols, Value will be the address of the
80 : // symbol in the target address space.
81 7 : void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override {
82 7 : const SectionEntry &Section = Sections[RE.SectionID];
83 7 : uint8_t *Target = Section.getAddressWithOffset(RE.Offset);
84 :
85 7 : switch (RE.RelType) {
86 :
87 1 : case COFF::IMAGE_REL_AMD64_REL32:
88 : case COFF::IMAGE_REL_AMD64_REL32_1:
89 : case COFF::IMAGE_REL_AMD64_REL32_2:
90 : case COFF::IMAGE_REL_AMD64_REL32_3:
91 : case COFF::IMAGE_REL_AMD64_REL32_4:
92 : case COFF::IMAGE_REL_AMD64_REL32_5: {
93 1 : uint64_t FinalAddress = Section.getLoadAddressWithOffset(RE.Offset);
94 : // Delta is the distance from the start of the reloc to the end of the
95 : // instruction with the reloc.
96 1 : uint64_t Delta = 4 + (RE.RelType - COFF::IMAGE_REL_AMD64_REL32);
97 1 : Value -= FinalAddress + Delta;
98 1 : uint64_t Result = Value + RE.Addend;
99 : assert(((int64_t)Result <= INT32_MAX) && "Relocation overflow");
100 : assert(((int64_t)Result >= INT32_MIN) && "Relocation underflow");
101 1 : writeBytesUnaligned(Result, Target, 4);
102 1 : break;
103 : }
104 :
105 : case COFF::IMAGE_REL_AMD64_ADDR32NB: {
106 : // ADDR32NB requires an offset less than 2GB from 'ImageBase'.
107 : // The MemoryManager can make sure this is always true by forcing the
108 : // memory layout to be: CodeSection < ReadOnlySection < ReadWriteSection.
109 : const uint64_t ImageBase = getImageBase();
110 5 : if (Value < ImageBase || ((Value - ImageBase) > UINT32_MAX)) {
111 0 : llvm::errs() << "IMAGE_REL_AMD64_ADDR32NB relocation requires an"
112 0 : << "ordered section layout.\n";
113 : write32BitOffset(Target, 0, 0);
114 : } else {
115 5 : write32BitOffset(Target, RE.Addend, Value - ImageBase);
116 : }
117 : break;
118 : }
119 :
120 1 : case COFF::IMAGE_REL_AMD64_ADDR64: {
121 1 : writeBytesUnaligned(Value + RE.Addend, Target, 8);
122 1 : break;
123 : }
124 :
125 0 : default:
126 0 : llvm_unreachable("Relocation type not implemented yet!");
127 : break;
128 : }
129 7 : }
130 :
131 : std::tuple<uint64_t, uint64_t, uint64_t>
132 0 : generateRelocationStub(unsigned SectionID, StringRef TargetName,
133 : uint64_t Offset, uint64_t RelType, uint64_t Addend,
134 : StubMap &Stubs) {
135 : uintptr_t StubOffset;
136 0 : SectionEntry &Section = Sections[SectionID];
137 :
138 : RelocationValueRef OriginalRelValueRef;
139 0 : OriginalRelValueRef.SectionID = SectionID;
140 0 : OriginalRelValueRef.Offset = Offset;
141 0 : OriginalRelValueRef.Addend = Addend;
142 0 : OriginalRelValueRef.SymbolName = TargetName.data();
143 :
144 : auto Stub = Stubs.find(OriginalRelValueRef);
145 0 : if (Stub == Stubs.end()) {
146 : LLVM_DEBUG(dbgs() << " Create a new stub function for "
147 : << TargetName.data() << "\n");
148 :
149 0 : StubOffset = Section.getStubOffset();
150 0 : Stubs[OriginalRelValueRef] = StubOffset;
151 0 : createStubFunction(Section.getAddressWithOffset(StubOffset));
152 0 : Section.advanceStubOffset(getMaxStubSize());
153 : } else {
154 : LLVM_DEBUG(dbgs() << " Stub function found for " << TargetName.data()
155 : << "\n");
156 0 : StubOffset = Stub->second;
157 : }
158 :
159 : // FIXME: If RelType == COFF::IMAGE_REL_AMD64_ADDR32NB we should be able
160 : // to ignore the __ImageBase requirement and just forward to the stub
161 : // directly as an offset of this section:
162 : // write32BitOffset(Section.getAddressWithOffset(Offset), 0, StubOffset);
163 : // .xdata exception handler's aren't having this though.
164 :
165 : // Resolve original relocation to stub function.
166 0 : const RelocationEntry RE(SectionID, Offset, RelType, Addend);
167 0 : resolveRelocation(RE, Section.getLoadAddressWithOffset(StubOffset));
168 :
169 : // adjust relocation info so resolution writes to the stub function
170 : Addend = 0;
171 0 : Offset = StubOffset + 6;
172 : RelType = COFF::IMAGE_REL_AMD64_ADDR64;
173 :
174 0 : return std::make_tuple(Offset, RelType, Addend);
175 : }
176 :
177 : Expected<relocation_iterator>
178 7 : processRelocationRef(unsigned SectionID,
179 : relocation_iterator RelI,
180 : const ObjectFile &Obj,
181 : ObjSectionToIDMap &ObjSectionToID,
182 : StubMap &Stubs) override {
183 : // If possible, find the symbol referred to in the relocation,
184 : // and the section that contains it.
185 7 : symbol_iterator Symbol = RelI->getSymbol();
186 7 : if (Symbol == Obj.symbol_end())
187 0 : report_fatal_error("Unknown symbol in relocation");
188 : auto SectionOrError = Symbol->getSection();
189 7 : if (!SectionOrError)
190 : return SectionOrError.takeError();
191 7 : section_iterator SecI = *SectionOrError;
192 : // If there is no section, this must be an external reference.
193 7 : const bool IsExtern = SecI == Obj.section_end();
194 :
195 : // Determine the Addend used to adjust the relocation value.
196 7 : uint64_t RelType = RelI->getType();
197 7 : uint64_t Offset = RelI->getOffset();
198 7 : uint64_t Addend = 0;
199 7 : SectionEntry &Section = Sections[SectionID];
200 7 : uintptr_t ObjTarget = Section.getObjAddress() + Offset;
201 :
202 : Expected<StringRef> TargetNameOrErr = Symbol->getName();
203 7 : if (!TargetNameOrErr)
204 : return TargetNameOrErr.takeError();
205 7 : StringRef TargetName = *TargetNameOrErr;
206 :
207 7 : switch (RelType) {
208 :
209 6 : case COFF::IMAGE_REL_AMD64_REL32:
210 : case COFF::IMAGE_REL_AMD64_REL32_1:
211 : case COFF::IMAGE_REL_AMD64_REL32_2:
212 : case COFF::IMAGE_REL_AMD64_REL32_3:
213 : case COFF::IMAGE_REL_AMD64_REL32_4:
214 : case COFF::IMAGE_REL_AMD64_REL32_5:
215 : case COFF::IMAGE_REL_AMD64_ADDR32NB: {
216 6 : uint8_t *Displacement = (uint8_t *)ObjTarget;
217 6 : Addend = readBytesUnaligned(Displacement, 4);
218 :
219 6 : if (IsExtern)
220 0 : std::tie(Offset, RelType, Addend) = generateRelocationStub(
221 : SectionID, TargetName, Offset, RelType, Addend, Stubs);
222 :
223 : break;
224 : }
225 :
226 1 : case COFF::IMAGE_REL_AMD64_ADDR64: {
227 1 : uint8_t *Displacement = (uint8_t *)ObjTarget;
228 1 : Addend = readBytesUnaligned(Displacement, 8);
229 1 : break;
230 : }
231 :
232 : default:
233 : break;
234 : }
235 :
236 : LLVM_DEBUG(dbgs() << "\t\tIn Section " << SectionID << " Offset " << Offset
237 : << " RelType: " << RelType << " TargetName: "
238 : << TargetName << " Addend " << Addend << "\n");
239 :
240 7 : if (IsExtern) {
241 0 : RelocationEntry RE(SectionID, Offset, RelType, Addend);
242 0 : addRelocationForSymbol(RE, TargetName);
243 : } else {
244 7 : bool IsCode = SecI->isText();
245 : unsigned TargetSectionID;
246 7 : if (auto TargetSectionIDOrErr =
247 7 : findOrEmitSection(Obj, *SecI, IsCode, ObjSectionToID))
248 7 : TargetSectionID = *TargetSectionIDOrErr;
249 : else
250 : return TargetSectionIDOrErr.takeError();
251 7 : uint64_t TargetOffset = getSymbolOffset(*Symbol);
252 7 : RelocationEntry RE(SectionID, Offset, RelType, TargetOffset + Addend);
253 7 : addRelocationForSection(RE, TargetSectionID);
254 : }
255 :
256 : return ++RelI;
257 : }
258 :
259 2 : void registerEHFrames() override {
260 3 : for (auto const &EHFrameSID : UnregisteredEHFrameSections) {
261 1 : uint8_t *EHFrameAddr = Sections[EHFrameSID].getAddress();
262 1 : uint64_t EHFrameLoadAddr = Sections[EHFrameSID].getLoadAddress();
263 1 : size_t EHFrameSize = Sections[EHFrameSID].getSize();
264 1 : MemMgr.registerEHFrames(EHFrameAddr, EHFrameLoadAddr, EHFrameSize);
265 1 : RegisteredEHFrameSections.push_back(EHFrameSID);
266 : }
267 : UnregisteredEHFrameSections.clear();
268 2 : }
269 :
270 2 : Error finalizeLoad(const ObjectFile &Obj,
271 : ObjSectionToIDMap &SectionMap) override {
272 : // Look for and record the EH frame section IDs.
273 12 : for (const auto &SectionPair : SectionMap) {
274 : const SectionRef &Section = SectionPair.first;
275 10 : StringRef Name;
276 10 : if (auto EC = Section.getName(Name))
277 0 : return errorCodeToError(EC);
278 :
279 : // Note unwind info is stored in .pdata but often points to .xdata
280 : // with an IMAGE_REL_AMD64_ADDR32NB relocation. Using a memory manager
281 : // that keeps sections ordered in relation to __ImageBase is necessary.
282 : if (Name == ".pdata")
283 1 : UnregisteredEHFrameSections.push_back(SectionPair.second);
284 : }
285 : return Error::success();
286 : }
287 : };
288 :
289 : } // end namespace llvm
290 :
291 : #undef DEBUG_TYPE
292 :
293 : #endif
|