1 //===-- RuntimeDyldCOFFX86_64.h --- COFF/X86_64 specific code ---*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // COFF x86_x64 support for MC-JIT runtime dynamic linker.
11 //===----------------------------------------------------------------------===//
13 #ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFF86_64_H
14 #define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFF86_64_H
16 #include "../RuntimeDyldCOFF.h"
17 #include "llvm/BinaryFormat/COFF.h"
18 #include "llvm/Object/COFF.h"
20 #define DEBUG_TYPE "dyld"
24 class RuntimeDyldCOFFX86_64
: public RuntimeDyldCOFF
{
27 // When a module is loaded we save the SectionID of the unwind
28 // sections in a table until we receive a request to register all
29 // unregisteredEH frame sections with the memory manager.
30 SmallVector
<SID
, 2> UnregisteredEHFrameSections
;
31 SmallVector
<SID
, 2> RegisteredEHFrameSections
;
34 // Fake an __ImageBase pointer by returning the section with the lowest adress
35 uint64_t getImageBase() {
37 ImageBase
= std::numeric_limits
<uint64_t>::max();
38 for (const SectionEntry
&Section
: Sections
)
39 // The Sections list may contain sections that weren't loaded for
40 // whatever reason: they may be debug sections, and ProcessAllSections
41 // is false, or they may be sections that contain 0 bytes. If the
42 // section isn't loaded, the load address will be 0, and it should not
43 // be included in the ImageBase calculation.
44 if (Section
.getLoadAddress() != 0)
45 ImageBase
= std::min(ImageBase
, Section
.getLoadAddress());
50 void write32BitOffset(uint8_t *Target
, int64_t Addend
, uint64_t Delta
) {
51 uint64_t Result
= Addend
+ Delta
;
52 assert(Result
<= UINT32_MAX
&& "Relocation overflow");
53 writeBytesUnaligned(Result
, Target
, 4);
57 RuntimeDyldCOFFX86_64(RuntimeDyld::MemoryManager
&MM
,
58 JITSymbolResolver
&Resolver
)
59 : RuntimeDyldCOFF(MM
, Resolver
, 8, COFF::IMAGE_REL_AMD64_ADDR64
),
62 Align
getStubAlignment() override
{ return Align(1); }
64 // 2-byte jmp instruction + 32-bit relative address + 64-bit absolute jump
65 unsigned getMaxStubSize() const override
{ return 14; }
67 // The target location for the relocation is described by RE.SectionID and
68 // RE.Offset. RE.SectionID can be used to find the SectionEntry. Each
69 // SectionEntry has three members describing its location.
70 // SectionEntry::Address is the address at which the section has been loaded
71 // into memory in the current (host) process. SectionEntry::LoadAddress is
72 // the address that the section will have in the target process.
73 // SectionEntry::ObjAddress is the address of the bits for this section in the
74 // original emitted object image (also in the current address space).
76 // Relocations will be applied as if the section were loaded at
77 // SectionEntry::LoadAddress, but they will be applied at an address based
78 // on SectionEntry::Address. SectionEntry::ObjAddress will be used to refer
79 // to Target memory contents if they are required for value calculations.
81 // The Value parameter here is the load address of the symbol for the
82 // relocation to be applied. For relocations which refer to symbols in the
83 // current object Value will be the LoadAddress of the section in which
84 // the symbol resides (RE.Addend provides additional information about the
85 // symbol location). For external symbols, Value will be the address of the
86 // symbol in the target address space.
87 void resolveRelocation(const RelocationEntry
&RE
, uint64_t Value
) override
{
88 const SectionEntry
&Section
= Sections
[RE
.SectionID
];
89 uint8_t *Target
= Section
.getAddressWithOffset(RE
.Offset
);
93 case COFF::IMAGE_REL_AMD64_REL32
:
94 case COFF::IMAGE_REL_AMD64_REL32_1
:
95 case COFF::IMAGE_REL_AMD64_REL32_2
:
96 case COFF::IMAGE_REL_AMD64_REL32_3
:
97 case COFF::IMAGE_REL_AMD64_REL32_4
:
98 case COFF::IMAGE_REL_AMD64_REL32_5
: {
99 uint64_t FinalAddress
= Section
.getLoadAddressWithOffset(RE
.Offset
);
100 // Delta is the distance from the start of the reloc to the end of the
101 // instruction with the reloc.
102 uint64_t Delta
= 4 + (RE
.RelType
- COFF::IMAGE_REL_AMD64_REL32
);
103 Value
-= FinalAddress
+ Delta
;
104 uint64_t Result
= Value
+ RE
.Addend
;
105 assert(((int64_t)Result
<= INT32_MAX
) && "Relocation overflow");
106 assert(((int64_t)Result
>= INT32_MIN
) && "Relocation underflow");
107 writeBytesUnaligned(Result
, Target
, 4);
111 case COFF::IMAGE_REL_AMD64_ADDR32NB
: {
112 // ADDR32NB requires an offset less than 2GB from 'ImageBase'.
113 // The MemoryManager can make sure this is always true by forcing the
114 // memory layout to be: CodeSection < ReadOnlySection < ReadWriteSection.
115 const uint64_t ImageBase
= getImageBase();
116 if (Value
< ImageBase
|| ((Value
- ImageBase
) > UINT32_MAX
))
117 report_fatal_error("IMAGE_REL_AMD64_ADDR32NB relocation requires an "
118 "ordered section layout");
120 write32BitOffset(Target
, RE
.Addend
, Value
- ImageBase
);
125 case COFF::IMAGE_REL_AMD64_ADDR64
: {
126 writeBytesUnaligned(Value
+ RE
.Addend
, Target
, 8);
130 case COFF::IMAGE_REL_AMD64_SECREL
: {
131 assert(static_cast<int64_t>(RE
.Addend
) <= INT32_MAX
&& "Relocation overflow");
132 assert(static_cast<int64_t>(RE
.Addend
) >= INT32_MIN
&& "Relocation underflow");
133 writeBytesUnaligned(RE
.Addend
, Target
, 4);
137 case COFF::IMAGE_REL_AMD64_SECTION
: {
138 assert(static_cast<int16_t>(RE
.SectionID
) <= INT16_MAX
&& "Relocation overflow");
139 assert(static_cast<int16_t>(RE
.SectionID
) >= INT16_MIN
&& "Relocation underflow");
140 writeBytesUnaligned(RE
.SectionID
, Target
, 2);
145 llvm_unreachable("Relocation type not implemented yet!");
150 std::tuple
<uint64_t, uint64_t, uint64_t>
151 generateRelocationStub(unsigned SectionID
, StringRef TargetName
,
152 uint64_t Offset
, uint64_t RelType
, uint64_t Addend
,
154 uintptr_t StubOffset
;
155 SectionEntry
&Section
= Sections
[SectionID
];
157 RelocationValueRef OriginalRelValueRef
;
158 OriginalRelValueRef
.SectionID
= SectionID
;
159 OriginalRelValueRef
.Offset
= Offset
;
160 OriginalRelValueRef
.Addend
= Addend
;
161 OriginalRelValueRef
.SymbolName
= TargetName
.data();
163 auto Stub
= Stubs
.find(OriginalRelValueRef
);
164 if (Stub
== Stubs
.end()) {
165 LLVM_DEBUG(dbgs() << " Create a new stub function for "
166 << TargetName
.data() << "\n");
168 StubOffset
= Section
.getStubOffset();
169 Stubs
[OriginalRelValueRef
] = StubOffset
;
170 createStubFunction(Section
.getAddressWithOffset(StubOffset
));
171 Section
.advanceStubOffset(getMaxStubSize());
173 LLVM_DEBUG(dbgs() << " Stub function found for " << TargetName
.data()
175 StubOffset
= Stub
->second
;
178 // FIXME: If RelType == COFF::IMAGE_REL_AMD64_ADDR32NB we should be able
179 // to ignore the __ImageBase requirement and just forward to the stub
180 // directly as an offset of this section:
181 // write32BitOffset(Section.getAddressWithOffset(Offset), 0, StubOffset);
182 // .xdata exception handler's aren't having this though.
184 // Resolve original relocation to stub function.
185 const RelocationEntry
RE(SectionID
, Offset
, RelType
, Addend
);
186 resolveRelocation(RE
, Section
.getLoadAddressWithOffset(StubOffset
));
188 // adjust relocation info so resolution writes to the stub function
190 Offset
= StubOffset
+ 6;
191 RelType
= COFF::IMAGE_REL_AMD64_ADDR64
;
193 return std::make_tuple(Offset
, RelType
, Addend
);
196 Expected
<object::relocation_iterator
>
197 processRelocationRef(unsigned SectionID
,
198 object::relocation_iterator RelI
,
199 const object::ObjectFile
&Obj
,
200 ObjSectionToIDMap
&ObjSectionToID
,
201 StubMap
&Stubs
) override
{
202 // If possible, find the symbol referred to in the relocation,
203 // and the section that contains it.
204 object::symbol_iterator Symbol
= RelI
->getSymbol();
205 if (Symbol
== Obj
.symbol_end())
206 report_fatal_error("Unknown symbol in relocation");
207 auto SectionOrError
= Symbol
->getSection();
209 return SectionOrError
.takeError();
210 object::section_iterator SecI
= *SectionOrError
;
211 // If there is no section, this must be an external reference.
212 bool IsExtern
= SecI
== Obj
.section_end();
214 // Determine the Addend used to adjust the relocation value.
215 uint64_t RelType
= RelI
->getType();
216 uint64_t Offset
= RelI
->getOffset();
218 SectionEntry
&Section
= Sections
[SectionID
];
219 uintptr_t ObjTarget
= Section
.getObjAddress() + Offset
;
221 Expected
<StringRef
> TargetNameOrErr
= Symbol
->getName();
222 if (!TargetNameOrErr
)
223 return TargetNameOrErr
.takeError();
225 StringRef TargetName
= *TargetNameOrErr
;
226 unsigned TargetSectionID
= 0;
227 uint64_t TargetOffset
= 0;
229 if (TargetName
.startswith(getImportSymbolPrefix())) {
230 assert(IsExtern
&& "DLLImport not marked extern?");
231 TargetSectionID
= SectionID
;
232 TargetOffset
= getDLLImportOffset(SectionID
, Stubs
, TargetName
);
233 TargetName
= StringRef();
235 } else if (!IsExtern
) {
236 if (auto TargetSectionIDOrErr
=
237 findOrEmitSection(Obj
, *SecI
, SecI
->isText(), ObjSectionToID
))
238 TargetSectionID
= *TargetSectionIDOrErr
;
240 return TargetSectionIDOrErr
.takeError();
241 TargetOffset
= getSymbolOffset(*Symbol
);
246 case COFF::IMAGE_REL_AMD64_REL32
:
247 case COFF::IMAGE_REL_AMD64_REL32_1
:
248 case COFF::IMAGE_REL_AMD64_REL32_2
:
249 case COFF::IMAGE_REL_AMD64_REL32_3
:
250 case COFF::IMAGE_REL_AMD64_REL32_4
:
251 case COFF::IMAGE_REL_AMD64_REL32_5
:
252 case COFF::IMAGE_REL_AMD64_ADDR32NB
: {
253 uint8_t *Displacement
= (uint8_t *)ObjTarget
;
254 Addend
= readBytesUnaligned(Displacement
, 4);
257 std::tie(Offset
, RelType
, Addend
) = generateRelocationStub(
258 SectionID
, TargetName
, Offset
, RelType
, Addend
, Stubs
);
263 case COFF::IMAGE_REL_AMD64_ADDR64
: {
264 uint8_t *Displacement
= (uint8_t *)ObjTarget
;
265 Addend
= readBytesUnaligned(Displacement
, 8);
273 LLVM_DEBUG(dbgs() << "\t\tIn Section " << SectionID
<< " Offset " << Offset
274 << " RelType: " << RelType
<< " TargetName: "
275 << TargetName
<< " Addend " << Addend
<< "\n");
278 RelocationEntry
RE(SectionID
, Offset
, RelType
, Addend
);
279 addRelocationForSymbol(RE
, TargetName
);
281 RelocationEntry
RE(SectionID
, Offset
, RelType
, TargetOffset
+ Addend
);
282 addRelocationForSection(RE
, TargetSectionID
);
288 void registerEHFrames() override
{
289 for (auto const &EHFrameSID
: UnregisteredEHFrameSections
) {
290 uint8_t *EHFrameAddr
= Sections
[EHFrameSID
].getAddress();
291 uint64_t EHFrameLoadAddr
= Sections
[EHFrameSID
].getLoadAddress();
292 size_t EHFrameSize
= Sections
[EHFrameSID
].getSize();
293 MemMgr
.registerEHFrames(EHFrameAddr
, EHFrameLoadAddr
, EHFrameSize
);
294 RegisteredEHFrameSections
.push_back(EHFrameSID
);
296 UnregisteredEHFrameSections
.clear();
299 Error
finalizeLoad(const object::ObjectFile
&Obj
,
300 ObjSectionToIDMap
&SectionMap
) override
{
301 // Look for and record the EH frame section IDs.
302 for (const auto &SectionPair
: SectionMap
) {
303 const object::SectionRef
&Section
= SectionPair
.first
;
304 Expected
<StringRef
> NameOrErr
= Section
.getName();
306 return NameOrErr
.takeError();
308 // Note unwind info is stored in .pdata but often points to .xdata
309 // with an IMAGE_REL_AMD64_ADDR32NB relocation. Using a memory manager
310 // that keeps sections ordered in relation to __ImageBase is necessary.
311 if ((*NameOrErr
) == ".pdata")
312 UnregisteredEHFrameSections
.push_back(SectionPair
.second
);
314 return Error::success();
318 } // end namespace llvm