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
), ImageBase(0) {}
61 unsigned getStubAlignment() override
{ return 1; }
63 // 2-byte jmp instruction + 32-bit relative address + 64-bit absolute jump
64 unsigned getMaxStubSize() const override
{ return 14; }
66 // The target location for the relocation is described by RE.SectionID and
67 // RE.Offset. RE.SectionID can be used to find the SectionEntry. Each
68 // SectionEntry has three members describing its location.
69 // SectionEntry::Address is the address at which the section has been loaded
70 // into memory in the current (host) process. SectionEntry::LoadAddress is
71 // the address that the section will have in the target process.
72 // SectionEntry::ObjAddress is the address of the bits for this section in the
73 // original emitted object image (also in the current address space).
75 // Relocations will be applied as if the section were loaded at
76 // SectionEntry::LoadAddress, but they will be applied at an address based
77 // on SectionEntry::Address. SectionEntry::ObjAddress will be used to refer
78 // to Target memory contents if they are required for value calculations.
80 // The Value parameter here is the load address of the symbol for the
81 // relocation to be applied. For relocations which refer to symbols in the
82 // current object Value will be the LoadAddress of the section in which
83 // the symbol resides (RE.Addend provides additional information about the
84 // symbol location). For external symbols, Value will be the address of the
85 // symbol in the target address space.
86 void resolveRelocation(const RelocationEntry
&RE
, uint64_t Value
) override
{
87 const SectionEntry
&Section
= Sections
[RE
.SectionID
];
88 uint8_t *Target
= Section
.getAddressWithOffset(RE
.Offset
);
92 case COFF::IMAGE_REL_AMD64_REL32
:
93 case COFF::IMAGE_REL_AMD64_REL32_1
:
94 case COFF::IMAGE_REL_AMD64_REL32_2
:
95 case COFF::IMAGE_REL_AMD64_REL32_3
:
96 case COFF::IMAGE_REL_AMD64_REL32_4
:
97 case COFF::IMAGE_REL_AMD64_REL32_5
: {
98 uint64_t FinalAddress
= Section
.getLoadAddressWithOffset(RE
.Offset
);
99 // Delta is the distance from the start of the reloc to the end of the
100 // instruction with the reloc.
101 uint64_t Delta
= 4 + (RE
.RelType
- COFF::IMAGE_REL_AMD64_REL32
);
102 Value
-= FinalAddress
+ Delta
;
103 uint64_t Result
= Value
+ RE
.Addend
;
104 assert(((int64_t)Result
<= INT32_MAX
) && "Relocation overflow");
105 assert(((int64_t)Result
>= INT32_MIN
) && "Relocation underflow");
106 writeBytesUnaligned(Result
, Target
, 4);
110 case COFF::IMAGE_REL_AMD64_ADDR32NB
: {
111 // ADDR32NB requires an offset less than 2GB from 'ImageBase'.
112 // The MemoryManager can make sure this is always true by forcing the
113 // memory layout to be: CodeSection < ReadOnlySection < ReadWriteSection.
114 const uint64_t ImageBase
= getImageBase();
115 if (Value
< ImageBase
|| ((Value
- ImageBase
) > UINT32_MAX
)) {
116 llvm::errs() << "IMAGE_REL_AMD64_ADDR32NB relocation requires an"
117 << "ordered section layout.\n";
118 write32BitOffset(Target
, 0, 0);
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 const 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();
217 StringRef TargetName
= *TargetNameOrErr
;
221 case COFF::IMAGE_REL_AMD64_REL32
:
222 case COFF::IMAGE_REL_AMD64_REL32_1
:
223 case COFF::IMAGE_REL_AMD64_REL32_2
:
224 case COFF::IMAGE_REL_AMD64_REL32_3
:
225 case COFF::IMAGE_REL_AMD64_REL32_4
:
226 case COFF::IMAGE_REL_AMD64_REL32_5
:
227 case COFF::IMAGE_REL_AMD64_ADDR32NB
: {
228 uint8_t *Displacement
= (uint8_t *)ObjTarget
;
229 Addend
= readBytesUnaligned(Displacement
, 4);
232 std::tie(Offset
, RelType
, Addend
) = generateRelocationStub(
233 SectionID
, TargetName
, Offset
, RelType
, Addend
, Stubs
);
238 case COFF::IMAGE_REL_AMD64_ADDR64
: {
239 uint8_t *Displacement
= (uint8_t *)ObjTarget
;
240 Addend
= readBytesUnaligned(Displacement
, 8);
248 LLVM_DEBUG(dbgs() << "\t\tIn Section " << SectionID
<< " Offset " << Offset
249 << " RelType: " << RelType
<< " TargetName: "
250 << TargetName
<< " Addend " << Addend
<< "\n");
253 RelocationEntry
RE(SectionID
, Offset
, RelType
, Addend
);
254 addRelocationForSymbol(RE
, TargetName
);
256 bool IsCode
= SecI
->isText();
257 unsigned TargetSectionID
;
258 if (auto TargetSectionIDOrErr
=
259 findOrEmitSection(Obj
, *SecI
, IsCode
, ObjSectionToID
))
260 TargetSectionID
= *TargetSectionIDOrErr
;
262 return TargetSectionIDOrErr
.takeError();
263 uint64_t TargetOffset
= getSymbolOffset(*Symbol
);
264 RelocationEntry
RE(SectionID
, Offset
, RelType
, TargetOffset
+ Addend
);
265 addRelocationForSection(RE
, TargetSectionID
);
271 void registerEHFrames() override
{
272 for (auto const &EHFrameSID
: UnregisteredEHFrameSections
) {
273 uint8_t *EHFrameAddr
= Sections
[EHFrameSID
].getAddress();
274 uint64_t EHFrameLoadAddr
= Sections
[EHFrameSID
].getLoadAddress();
275 size_t EHFrameSize
= Sections
[EHFrameSID
].getSize();
276 MemMgr
.registerEHFrames(EHFrameAddr
, EHFrameLoadAddr
, EHFrameSize
);
277 RegisteredEHFrameSections
.push_back(EHFrameSID
);
279 UnregisteredEHFrameSections
.clear();
282 Error
finalizeLoad(const object::ObjectFile
&Obj
,
283 ObjSectionToIDMap
&SectionMap
) override
{
284 // Look for and record the EH frame section IDs.
285 for (const auto &SectionPair
: SectionMap
) {
286 const object::SectionRef
&Section
= SectionPair
.first
;
288 if (auto EC
= Section
.getName(Name
))
289 return errorCodeToError(EC
);
291 // Note unwind info is stored in .pdata but often points to .xdata
292 // with an IMAGE_REL_AMD64_ADDR32NB relocation. Using a memory manager
293 // that keeps sections ordered in relation to __ImageBase is necessary.
294 if (Name
== ".pdata")
295 UnregisteredEHFrameSections
.push_back(SectionPair
.second
);
297 return Error::success();
301 } // end namespace llvm