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 unsigned getStubAlignment() override
{ return 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);
138 llvm_unreachable("Relocation type not implemented yet!");
143 std::tuple
<uint64_t, uint64_t, uint64_t>
144 generateRelocationStub(unsigned SectionID
, StringRef TargetName
,
145 uint64_t Offset
, uint64_t RelType
, uint64_t Addend
,
147 uintptr_t StubOffset
;
148 SectionEntry
&Section
= Sections
[SectionID
];
150 RelocationValueRef OriginalRelValueRef
;
151 OriginalRelValueRef
.SectionID
= SectionID
;
152 OriginalRelValueRef
.Offset
= Offset
;
153 OriginalRelValueRef
.Addend
= Addend
;
154 OriginalRelValueRef
.SymbolName
= TargetName
.data();
156 auto Stub
= Stubs
.find(OriginalRelValueRef
);
157 if (Stub
== Stubs
.end()) {
158 LLVM_DEBUG(dbgs() << " Create a new stub function for "
159 << TargetName
.data() << "\n");
161 StubOffset
= Section
.getStubOffset();
162 Stubs
[OriginalRelValueRef
] = StubOffset
;
163 createStubFunction(Section
.getAddressWithOffset(StubOffset
));
164 Section
.advanceStubOffset(getMaxStubSize());
166 LLVM_DEBUG(dbgs() << " Stub function found for " << TargetName
.data()
168 StubOffset
= Stub
->second
;
171 // FIXME: If RelType == COFF::IMAGE_REL_AMD64_ADDR32NB we should be able
172 // to ignore the __ImageBase requirement and just forward to the stub
173 // directly as an offset of this section:
174 // write32BitOffset(Section.getAddressWithOffset(Offset), 0, StubOffset);
175 // .xdata exception handler's aren't having this though.
177 // Resolve original relocation to stub function.
178 const RelocationEntry
RE(SectionID
, Offset
, RelType
, Addend
);
179 resolveRelocation(RE
, Section
.getLoadAddressWithOffset(StubOffset
));
181 // adjust relocation info so resolution writes to the stub function
183 Offset
= StubOffset
+ 6;
184 RelType
= COFF::IMAGE_REL_AMD64_ADDR64
;
186 return std::make_tuple(Offset
, RelType
, Addend
);
189 Expected
<object::relocation_iterator
>
190 processRelocationRef(unsigned SectionID
,
191 object::relocation_iterator RelI
,
192 const object::ObjectFile
&Obj
,
193 ObjSectionToIDMap
&ObjSectionToID
,
194 StubMap
&Stubs
) override
{
195 // If possible, find the symbol referred to in the relocation,
196 // and the section that contains it.
197 object::symbol_iterator Symbol
= RelI
->getSymbol();
198 if (Symbol
== Obj
.symbol_end())
199 report_fatal_error("Unknown symbol in relocation");
200 auto SectionOrError
= Symbol
->getSection();
202 return SectionOrError
.takeError();
203 object::section_iterator SecI
= *SectionOrError
;
204 // If there is no section, this must be an external reference.
205 bool IsExtern
= SecI
== Obj
.section_end();
207 // Determine the Addend used to adjust the relocation value.
208 uint64_t RelType
= RelI
->getType();
209 uint64_t Offset
= RelI
->getOffset();
211 SectionEntry
&Section
= Sections
[SectionID
];
212 uintptr_t ObjTarget
= Section
.getObjAddress() + Offset
;
214 Expected
<StringRef
> TargetNameOrErr
= Symbol
->getName();
215 if (!TargetNameOrErr
)
216 return TargetNameOrErr
.takeError();
218 StringRef TargetName
= *TargetNameOrErr
;
219 unsigned TargetSectionID
= 0;
220 uint64_t TargetOffset
= 0;
222 if (TargetName
.startswith(getImportSymbolPrefix())) {
223 assert(IsExtern
&& "DLLImport not marked extern?");
224 TargetSectionID
= SectionID
;
225 TargetOffset
= getDLLImportOffset(SectionID
, Stubs
, TargetName
);
226 TargetName
= StringRef();
228 } else if (!IsExtern
) {
229 if (auto TargetSectionIDOrErr
=
230 findOrEmitSection(Obj
, *SecI
, SecI
->isText(), ObjSectionToID
))
231 TargetSectionID
= *TargetSectionIDOrErr
;
233 return TargetSectionIDOrErr
.takeError();
234 TargetOffset
= getSymbolOffset(*Symbol
);
239 case COFF::IMAGE_REL_AMD64_REL32
:
240 case COFF::IMAGE_REL_AMD64_REL32_1
:
241 case COFF::IMAGE_REL_AMD64_REL32_2
:
242 case COFF::IMAGE_REL_AMD64_REL32_3
:
243 case COFF::IMAGE_REL_AMD64_REL32_4
:
244 case COFF::IMAGE_REL_AMD64_REL32_5
:
245 case COFF::IMAGE_REL_AMD64_ADDR32NB
: {
246 uint8_t *Displacement
= (uint8_t *)ObjTarget
;
247 Addend
= readBytesUnaligned(Displacement
, 4);
250 std::tie(Offset
, RelType
, Addend
) = generateRelocationStub(
251 SectionID
, TargetName
, Offset
, RelType
, Addend
, Stubs
);
256 case COFF::IMAGE_REL_AMD64_ADDR64
: {
257 uint8_t *Displacement
= (uint8_t *)ObjTarget
;
258 Addend
= readBytesUnaligned(Displacement
, 8);
266 LLVM_DEBUG(dbgs() << "\t\tIn Section " << SectionID
<< " Offset " << Offset
267 << " RelType: " << RelType
<< " TargetName: "
268 << TargetName
<< " Addend " << Addend
<< "\n");
271 RelocationEntry
RE(SectionID
, Offset
, RelType
, Addend
);
272 addRelocationForSymbol(RE
, TargetName
);
274 RelocationEntry
RE(SectionID
, Offset
, RelType
, TargetOffset
+ Addend
);
275 addRelocationForSection(RE
, TargetSectionID
);
281 void registerEHFrames() override
{
282 for (auto const &EHFrameSID
: UnregisteredEHFrameSections
) {
283 uint8_t *EHFrameAddr
= Sections
[EHFrameSID
].getAddress();
284 uint64_t EHFrameLoadAddr
= Sections
[EHFrameSID
].getLoadAddress();
285 size_t EHFrameSize
= Sections
[EHFrameSID
].getSize();
286 MemMgr
.registerEHFrames(EHFrameAddr
, EHFrameLoadAddr
, EHFrameSize
);
287 RegisteredEHFrameSections
.push_back(EHFrameSID
);
289 UnregisteredEHFrameSections
.clear();
292 Error
finalizeLoad(const object::ObjectFile
&Obj
,
293 ObjSectionToIDMap
&SectionMap
) override
{
294 // Look for and record the EH frame section IDs.
295 for (const auto &SectionPair
: SectionMap
) {
296 const object::SectionRef
&Section
= SectionPair
.first
;
297 Expected
<StringRef
> NameOrErr
= Section
.getName();
299 return NameOrErr
.takeError();
301 // Note unwind info is stored in .pdata but often points to .xdata
302 // with an IMAGE_REL_AMD64_ADDR32NB relocation. Using a memory manager
303 // that keeps sections ordered in relation to __ImageBase is necessary.
304 if ((*NameOrErr
) == ".pdata")
305 UnregisteredEHFrameSections
.push_back(SectionPair
.second
);
307 return Error::success();
311 } // end namespace llvm