1 //===-- RuntimeDyldMachO.cpp - Run-time dynamic linker for MC-JIT -*- 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 // Implementation of the MC-JIT runtime dynamic linker.
11 //===----------------------------------------------------------------------===//
13 #include "RuntimeDyldMachO.h"
14 #include "Targets/RuntimeDyldMachOAArch64.h"
15 #include "Targets/RuntimeDyldMachOARM.h"
16 #include "Targets/RuntimeDyldMachOI386.h"
17 #include "Targets/RuntimeDyldMachOX86_64.h"
18 #include "llvm/ADT/STLExtras.h"
19 #include "llvm/ADT/StringRef.h"
22 using namespace llvm::object
;
24 #define DEBUG_TYPE "dyld"
28 class LoadedMachOObjectInfo final
29 : public LoadedObjectInfoHelper
<LoadedMachOObjectInfo
,
30 RuntimeDyld::LoadedObjectInfo
> {
32 LoadedMachOObjectInfo(RuntimeDyldImpl
&RTDyld
,
33 ObjSectionToIDMap ObjSecToIDMap
)
34 : LoadedObjectInfoHelper(RTDyld
, std::move(ObjSecToIDMap
)) {}
36 OwningBinary
<ObjectFile
>
37 getObjectForDebug(const ObjectFile
&Obj
) const override
{
38 return OwningBinary
<ObjectFile
>();
46 int64_t RuntimeDyldMachO::memcpyAddend(const RelocationEntry
&RE
) const {
47 unsigned NumBytes
= 1 << RE
.Size
;
48 uint8_t *Src
= Sections
[RE
.SectionID
].getAddress() + RE
.Offset
;
50 return static_cast<int64_t>(readBytesUnaligned(Src
, NumBytes
));
53 Expected
<relocation_iterator
>
54 RuntimeDyldMachO::processScatteredVANILLA(
55 unsigned SectionID
, relocation_iterator RelI
,
56 const ObjectFile
&BaseObjT
,
57 RuntimeDyldMachO::ObjSectionToIDMap
&ObjSectionToID
,
58 bool TargetIsLocalThumbFunc
) {
59 const MachOObjectFile
&Obj
=
60 static_cast<const MachOObjectFile
&>(BaseObjT
);
61 MachO::any_relocation_info RE
=
62 Obj
.getRelocation(RelI
->getRawDataRefImpl());
64 SectionEntry
&Section
= Sections
[SectionID
];
65 uint32_t RelocType
= Obj
.getAnyRelocationType(RE
);
66 bool IsPCRel
= Obj
.getAnyRelocationPCRel(RE
);
67 unsigned Size
= Obj
.getAnyRelocationLength(RE
);
68 uint64_t Offset
= RelI
->getOffset();
69 uint8_t *LocalAddress
= Section
.getAddressWithOffset(Offset
);
70 unsigned NumBytes
= 1 << Size
;
71 int64_t Addend
= readBytesUnaligned(LocalAddress
, NumBytes
);
73 unsigned SymbolBaseAddr
= Obj
.getScatteredRelocationValue(RE
);
74 section_iterator TargetSI
= getSectionByAddress(Obj
, SymbolBaseAddr
);
75 assert(TargetSI
!= Obj
.section_end() && "Can't find section for symbol");
76 uint64_t SectionBaseAddr
= TargetSI
->getAddress();
77 SectionRef TargetSection
= *TargetSI
;
78 bool IsCode
= TargetSection
.isText();
79 uint32_t TargetSectionID
= ~0U;
80 if (auto TargetSectionIDOrErr
=
81 findOrEmitSection(Obj
, TargetSection
, IsCode
, ObjSectionToID
))
82 TargetSectionID
= *TargetSectionIDOrErr
;
84 return TargetSectionIDOrErr
.takeError();
86 Addend
-= SectionBaseAddr
;
87 RelocationEntry
R(SectionID
, Offset
, RelocType
, Addend
, IsPCRel
, Size
);
88 R
.IsTargetThumbFunc
= TargetIsLocalThumbFunc
;
90 addRelocationForSection(R
, TargetSectionID
);
96 Expected
<RelocationValueRef
>
97 RuntimeDyldMachO::getRelocationValueRef(
98 const ObjectFile
&BaseTObj
, const relocation_iterator
&RI
,
99 const RelocationEntry
&RE
, ObjSectionToIDMap
&ObjSectionToID
) {
101 const MachOObjectFile
&Obj
=
102 static_cast<const MachOObjectFile
&>(BaseTObj
);
103 MachO::any_relocation_info RelInfo
=
104 Obj
.getRelocation(RI
->getRawDataRefImpl());
105 RelocationValueRef Value
;
107 bool IsExternal
= Obj
.getPlainRelocationExternal(RelInfo
);
109 symbol_iterator Symbol
= RI
->getSymbol();
110 StringRef TargetName
;
111 if (auto TargetNameOrErr
= Symbol
->getName())
112 TargetName
= *TargetNameOrErr
;
114 return TargetNameOrErr
.takeError();
115 RTDyldSymbolTable::const_iterator SI
=
116 GlobalSymbolTable
.find(TargetName
.data());
117 if (SI
!= GlobalSymbolTable
.end()) {
118 const auto &SymInfo
= SI
->second
;
119 Value
.SectionID
= SymInfo
.getSectionID();
120 Value
.Offset
= SymInfo
.getOffset() + RE
.Addend
;
122 Value
.SymbolName
= TargetName
.data();
123 Value
.Offset
= RE
.Addend
;
126 SectionRef Sec
= Obj
.getAnyRelocationSection(RelInfo
);
127 bool IsCode
= Sec
.isText();
128 if (auto SectionIDOrErr
= findOrEmitSection(Obj
, Sec
, IsCode
,
130 Value
.SectionID
= *SectionIDOrErr
;
132 return SectionIDOrErr
.takeError();
133 uint64_t Addr
= Sec
.getAddress();
134 Value
.Offset
= RE
.Addend
- Addr
;
140 void RuntimeDyldMachO::makeValueAddendPCRel(RelocationValueRef
&Value
,
141 const relocation_iterator
&RI
,
142 unsigned OffsetToNextPC
) {
143 auto &O
= *cast
<MachOObjectFile
>(RI
->getObject());
144 section_iterator SecI
= O
.getRelocationRelocatedSection(RI
);
145 Value
.Offset
+= RI
->getOffset() + OffsetToNextPC
+ SecI
->getAddress();
148 void RuntimeDyldMachO::dumpRelocationToResolve(const RelocationEntry
&RE
,
149 uint64_t Value
) const {
150 const SectionEntry
&Section
= Sections
[RE
.SectionID
];
151 uint8_t *LocalAddress
= Section
.getAddress() + RE
.Offset
;
152 uint64_t FinalAddress
= Section
.getLoadAddress() + RE
.Offset
;
154 dbgs() << "resolveRelocation Section: " << RE
.SectionID
155 << " LocalAddress: " << format("%p", LocalAddress
)
156 << " FinalAddress: " << format("0x%016" PRIx64
, FinalAddress
)
157 << " Value: " << format("0x%016" PRIx64
, Value
) << " Addend: " << RE
.Addend
158 << " isPCRel: " << RE
.IsPCRel
<< " MachoType: " << RE
.RelType
159 << " Size: " << (1 << RE
.Size
) << "\n";
163 RuntimeDyldMachO::getSectionByAddress(const MachOObjectFile
&Obj
,
165 section_iterator SI
= Obj
.section_begin();
166 section_iterator SE
= Obj
.section_end();
168 for (; SI
!= SE
; ++SI
) {
169 uint64_t SAddr
= SI
->getAddress();
170 uint64_t SSize
= SI
->getSize();
171 if ((Addr
>= SAddr
) && (Addr
< SAddr
+ SSize
))
179 // Populate __pointers section.
180 Error
RuntimeDyldMachO::populateIndirectSymbolPointersSection(
181 const MachOObjectFile
&Obj
,
182 const SectionRef
&PTSection
,
183 unsigned PTSectionID
) {
184 assert(!Obj
.is64Bit() &&
185 "Pointer table section not supported in 64-bit MachO.");
187 MachO::dysymtab_command DySymTabCmd
= Obj
.getDysymtabLoadCommand();
188 MachO::section Sec32
= Obj
.getSection(PTSection
.getRawDataRefImpl());
189 uint32_t PTSectionSize
= Sec32
.size
;
190 unsigned FirstIndirectSymbol
= Sec32
.reserved1
;
191 const unsigned PTEntrySize
= 4;
192 unsigned NumPTEntries
= PTSectionSize
/ PTEntrySize
;
193 unsigned PTEntryOffset
= 0;
195 assert((PTSectionSize
% PTEntrySize
) == 0 &&
196 "Pointers section does not contain a whole number of stubs?");
198 LLVM_DEBUG(dbgs() << "Populating pointer table section "
199 << Sections
[PTSectionID
].getName() << ", Section ID "
200 << PTSectionID
<< ", " << NumPTEntries
<< " entries, "
201 << PTEntrySize
<< " bytes each:\n");
203 for (unsigned i
= 0; i
< NumPTEntries
; ++i
) {
204 unsigned SymbolIndex
=
205 Obj
.getIndirectSymbolTableEntry(DySymTabCmd
, FirstIndirectSymbol
+ i
);
206 symbol_iterator SI
= Obj
.getSymbolByIndex(SymbolIndex
);
207 StringRef IndirectSymbolName
;
208 if (auto IndirectSymbolNameOrErr
= SI
->getName())
209 IndirectSymbolName
= *IndirectSymbolNameOrErr
;
211 return IndirectSymbolNameOrErr
.takeError();
212 LLVM_DEBUG(dbgs() << " " << IndirectSymbolName
<< ": index " << SymbolIndex
213 << ", PT offset: " << PTEntryOffset
<< "\n");
214 RelocationEntry
RE(PTSectionID
, PTEntryOffset
,
215 MachO::GENERIC_RELOC_VANILLA
, 0, false, 2);
216 addRelocationForSymbol(RE
, IndirectSymbolName
);
217 PTEntryOffset
+= PTEntrySize
;
219 return Error::success();
222 bool RuntimeDyldMachO::isCompatibleFile(const object::ObjectFile
&Obj
) const {
223 return Obj
.isMachO();
226 template <typename Impl
>
228 RuntimeDyldMachOCRTPBase
<Impl
>::finalizeLoad(const ObjectFile
&Obj
,
229 ObjSectionToIDMap
&SectionMap
) {
230 unsigned EHFrameSID
= RTDYLD_INVALID_SECTION_ID
;
231 unsigned TextSID
= RTDYLD_INVALID_SECTION_ID
;
232 unsigned ExceptTabSID
= RTDYLD_INVALID_SECTION_ID
;
234 for (const auto &Section
: Obj
.sections()) {
236 Section
.getName(Name
);
238 // Force emission of the __text, __eh_frame, and __gcc_except_tab sections
239 // if they're present. Otherwise call down to the impl to handle other
240 // sections that have already been emitted.
241 if (Name
== "__text") {
242 if (auto TextSIDOrErr
= findOrEmitSection(Obj
, Section
, true, SectionMap
))
243 TextSID
= *TextSIDOrErr
;
245 return TextSIDOrErr
.takeError();
246 } else if (Name
== "__eh_frame") {
247 if (auto EHFrameSIDOrErr
= findOrEmitSection(Obj
, Section
, false,
249 EHFrameSID
= *EHFrameSIDOrErr
;
251 return EHFrameSIDOrErr
.takeError();
252 } else if (Name
== "__gcc_except_tab") {
253 if (auto ExceptTabSIDOrErr
= findOrEmitSection(Obj
, Section
, true,
255 ExceptTabSID
= *ExceptTabSIDOrErr
;
257 return ExceptTabSIDOrErr
.takeError();
259 auto I
= SectionMap
.find(Section
);
260 if (I
!= SectionMap
.end())
261 if (auto Err
= impl().finalizeSection(Obj
, I
->second
, Section
))
265 UnregisteredEHFrameSections
.push_back(
266 EHFrameRelatedSections(EHFrameSID
, TextSID
, ExceptTabSID
));
268 return Error::success();
271 template <typename Impl
>
272 unsigned char *RuntimeDyldMachOCRTPBase
<Impl
>::processFDE(uint8_t *P
,
273 int64_t DeltaForText
,
274 int64_t DeltaForEH
) {
275 typedef typename
Impl::TargetPtrT TargetPtrT
;
277 LLVM_DEBUG(dbgs() << "Processing FDE: Delta for text: " << DeltaForText
278 << ", Delta for EH: " << DeltaForEH
<< "\n");
279 uint32_t Length
= readBytesUnaligned(P
, 4);
281 uint8_t *Ret
= P
+ Length
;
282 uint32_t Offset
= readBytesUnaligned(P
, 4);
283 if (Offset
== 0) // is a CIE
287 TargetPtrT FDELocation
= readBytesUnaligned(P
, sizeof(TargetPtrT
));
288 TargetPtrT NewLocation
= FDELocation
- DeltaForText
;
289 writeBytesUnaligned(NewLocation
, P
, sizeof(TargetPtrT
));
291 P
+= sizeof(TargetPtrT
);
293 // Skip the FDE address range
294 P
+= sizeof(TargetPtrT
);
296 uint8_t Augmentationsize
= *P
;
298 if (Augmentationsize
!= 0) {
299 TargetPtrT LSDA
= readBytesUnaligned(P
, sizeof(TargetPtrT
));
300 TargetPtrT NewLSDA
= LSDA
- DeltaForEH
;
301 writeBytesUnaligned(NewLSDA
, P
, sizeof(TargetPtrT
));
307 static int64_t computeDelta(SectionEntry
*A
, SectionEntry
*B
) {
308 int64_t ObjDistance
= static_cast<int64_t>(A
->getObjAddress()) -
309 static_cast<int64_t>(B
->getObjAddress());
310 int64_t MemDistance
= A
->getLoadAddress() - B
->getLoadAddress();
311 return ObjDistance
- MemDistance
;
314 template <typename Impl
>
315 void RuntimeDyldMachOCRTPBase
<Impl
>::registerEHFrames() {
317 for (int i
= 0, e
= UnregisteredEHFrameSections
.size(); i
!= e
; ++i
) {
318 EHFrameRelatedSections
&SectionInfo
= UnregisteredEHFrameSections
[i
];
319 if (SectionInfo
.EHFrameSID
== RTDYLD_INVALID_SECTION_ID
||
320 SectionInfo
.TextSID
== RTDYLD_INVALID_SECTION_ID
)
322 SectionEntry
*Text
= &Sections
[SectionInfo
.TextSID
];
323 SectionEntry
*EHFrame
= &Sections
[SectionInfo
.EHFrameSID
];
324 SectionEntry
*ExceptTab
= nullptr;
325 if (SectionInfo
.ExceptTabSID
!= RTDYLD_INVALID_SECTION_ID
)
326 ExceptTab
= &Sections
[SectionInfo
.ExceptTabSID
];
328 int64_t DeltaForText
= computeDelta(Text
, EHFrame
);
329 int64_t DeltaForEH
= 0;
331 DeltaForEH
= computeDelta(ExceptTab
, EHFrame
);
333 uint8_t *P
= EHFrame
->getAddress();
334 uint8_t *End
= P
+ EHFrame
->getSize();
336 P
= processFDE(P
, DeltaForText
, DeltaForEH
);
339 MemMgr
.registerEHFrames(EHFrame
->getAddress(), EHFrame
->getLoadAddress(),
342 UnregisteredEHFrameSections
.clear();
345 std::unique_ptr
<RuntimeDyldMachO
>
346 RuntimeDyldMachO::create(Triple::ArchType Arch
,
347 RuntimeDyld::MemoryManager
&MemMgr
,
348 JITSymbolResolver
&Resolver
) {
351 llvm_unreachable("Unsupported target for RuntimeDyldMachO.");
354 return make_unique
<RuntimeDyldMachOARM
>(MemMgr
, Resolver
);
355 case Triple::aarch64
:
356 return make_unique
<RuntimeDyldMachOAArch64
>(MemMgr
, Resolver
);
358 return make_unique
<RuntimeDyldMachOI386
>(MemMgr
, Resolver
);
360 return make_unique
<RuntimeDyldMachOX86_64
>(MemMgr
, Resolver
);
364 std::unique_ptr
<RuntimeDyld::LoadedObjectInfo
>
365 RuntimeDyldMachO::loadObject(const object::ObjectFile
&O
) {
366 if (auto ObjSectionToIDOrErr
= loadObjectImpl(O
))
367 return llvm::make_unique
<LoadedMachOObjectInfo
>(*this,
368 *ObjSectionToIDOrErr
);
371 raw_string_ostream
ErrStream(ErrorStr
);
372 logAllUnhandledErrors(ObjSectionToIDOrErr
.takeError(), ErrStream
);
377 } // end namespace llvm