]>
Commit | Line | Data |
---|---|---|
223e47cc LB |
1 | //===-- RuntimeDyldELF.cpp - Run-time dynamic linker for MC-JIT -*- 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 | // Implementation of ELF support for the MC-JIT runtime dynamic linker. | |
11 | // | |
12 | //===----------------------------------------------------------------------===// | |
13 | ||
970d7e83 LB |
14 | #include "RuntimeDyldELF.h" |
15 | #include "JITRegistrar.h" | |
16 | #include "ObjectImageCommon.h" | |
17 | #include "llvm/ADT/IntervalMap.h" | |
223e47cc | 18 | #include "llvm/ADT/STLExtras.h" |
970d7e83 | 19 | #include "llvm/ADT/StringRef.h" |
223e47cc | 20 | #include "llvm/ADT/Triple.h" |
970d7e83 LB |
21 | #include "llvm/ExecutionEngine/ObjectBuffer.h" |
22 | #include "llvm/ExecutionEngine/ObjectImage.h" | |
1a4d82fc | 23 | #include "llvm/Object/ELFObjectFile.h" |
970d7e83 LB |
24 | #include "llvm/Object/ObjectFile.h" |
25 | #include "llvm/Support/ELF.h" | |
1a4d82fc JJ |
26 | #include "llvm/Support/Endian.h" |
27 | #include "llvm/Support/MemoryBuffer.h" | |
28 | ||
223e47cc LB |
29 | using namespace llvm; |
30 | using namespace llvm::object; | |
31 | ||
1a4d82fc JJ |
32 | #define DEBUG_TYPE "dyld" |
33 | ||
223e47cc LB |
34 | namespace { |
35 | ||
1a4d82fc | 36 | static inline std::error_code check(std::error_code Err) { |
970d7e83 LB |
37 | if (Err) { |
38 | report_fatal_error(Err.message()); | |
39 | } | |
40 | return Err; | |
41 | } | |
223e47cc | 42 | |
1a4d82fc JJ |
43 | template <class ELFT> class DyldELFObject : public ELFObjectFile<ELFT> { |
44 | LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) | |
223e47cc | 45 | |
970d7e83 LB |
46 | typedef Elf_Shdr_Impl<ELFT> Elf_Shdr; |
47 | typedef Elf_Sym_Impl<ELFT> Elf_Sym; | |
1a4d82fc JJ |
48 | typedef Elf_Rel_Impl<ELFT, false> Elf_Rel; |
49 | typedef Elf_Rel_Impl<ELFT, true> Elf_Rela; | |
223e47cc | 50 | |
970d7e83 | 51 | typedef Elf_Ehdr_Impl<ELFT> Elf_Ehdr; |
223e47cc | 52 | |
1a4d82fc JJ |
53 | typedef typename ELFDataTypeTypedefHelper<ELFT>::value_type addr_type; |
54 | ||
55 | std::unique_ptr<ObjectFile> UnderlyingFile; | |
223e47cc LB |
56 | |
57 | public: | |
1a4d82fc JJ |
58 | DyldELFObject(std::unique_ptr<ObjectFile> UnderlyingFile, |
59 | MemoryBufferRef Wrapper, std::error_code &ec); | |
60 | ||
61 | DyldELFObject(MemoryBufferRef Wrapper, std::error_code &ec); | |
223e47cc LB |
62 | |
63 | void updateSectionAddress(const SectionRef &Sec, uint64_t Addr); | |
64 | void updateSymbolAddress(const SymbolRef &Sym, uint64_t Addr); | |
65 | ||
223e47cc LB |
66 | // Methods for type inquiry through isa, cast and dyn_cast |
67 | static inline bool classof(const Binary *v) { | |
1a4d82fc JJ |
68 | return (isa<ELFObjectFile<ELFT>>(v) && |
69 | classof(cast<ELFObjectFile<ELFT>>(v))); | |
223e47cc | 70 | } |
1a4d82fc | 71 | static inline bool classof(const ELFObjectFile<ELFT> *v) { |
223e47cc LB |
72 | return v->isDyldType(); |
73 | } | |
223e47cc LB |
74 | }; |
75 | ||
1a4d82fc JJ |
76 | template <class ELFT> class ELFObjectImage : public ObjectImageCommon { |
77 | bool Registered; | |
223e47cc | 78 | |
1a4d82fc JJ |
79 | public: |
80 | ELFObjectImage(std::unique_ptr<ObjectBuffer> Input, | |
81 | std::unique_ptr<DyldELFObject<ELFT>> Obj) | |
82 | : ObjectImageCommon(std::move(Input), std::move(Obj)), Registered(false) { | |
83 | } | |
223e47cc | 84 | |
1a4d82fc JJ |
85 | virtual ~ELFObjectImage() { |
86 | if (Registered) | |
87 | deregisterWithDebugger(); | |
88 | } | |
223e47cc | 89 | |
1a4d82fc JJ |
90 | // Subclasses can override these methods to update the image with loaded |
91 | // addresses for sections and common symbols | |
92 | void updateSectionAddress(const SectionRef &Sec, uint64_t Addr) override { | |
93 | static_cast<DyldELFObject<ELFT>*>(getObjectFile()) | |
94 | ->updateSectionAddress(Sec, Addr); | |
95 | } | |
96 | ||
97 | void updateSymbolAddress(const SymbolRef &Sym, uint64_t Addr) override { | |
98 | static_cast<DyldELFObject<ELFT>*>(getObjectFile()) | |
99 | ->updateSymbolAddress(Sym, Addr); | |
100 | } | |
101 | ||
102 | void registerWithDebugger() override { | |
103 | JITRegistrar::getGDBRegistrar().registerObject(*Buffer); | |
104 | Registered = true; | |
105 | } | |
106 | void deregisterWithDebugger() override { | |
107 | JITRegistrar::getGDBRegistrar().deregisterObject(*Buffer); | |
108 | } | |
223e47cc LB |
109 | }; |
110 | ||
970d7e83 LB |
111 | // The MemoryBuffer passed into this constructor is just a wrapper around the |
112 | // actual memory. Ultimately, the Binary parent class will take ownership of | |
113 | // this MemoryBuffer object but not the underlying memory. | |
1a4d82fc JJ |
114 | template <class ELFT> |
115 | DyldELFObject<ELFT>::DyldELFObject(MemoryBufferRef Wrapper, std::error_code &EC) | |
116 | : ELFObjectFile<ELFT>(Wrapper, EC) { | |
117 | this->isDyldELFObject = true; | |
118 | } | |
119 | ||
120 | template <class ELFT> | |
121 | DyldELFObject<ELFT>::DyldELFObject(std::unique_ptr<ObjectFile> UnderlyingFile, | |
122 | MemoryBufferRef Wrapper, std::error_code &EC) | |
123 | : ELFObjectFile<ELFT>(Wrapper, EC), | |
124 | UnderlyingFile(std::move(UnderlyingFile)) { | |
223e47cc LB |
125 | this->isDyldELFObject = true; |
126 | } | |
127 | ||
1a4d82fc | 128 | template <class ELFT> |
970d7e83 LB |
129 | void DyldELFObject<ELFT>::updateSectionAddress(const SectionRef &Sec, |
130 | uint64_t Addr) { | |
223e47cc | 131 | DataRefImpl ShdrRef = Sec.getRawDataRefImpl(); |
1a4d82fc JJ |
132 | Elf_Shdr *shdr = |
133 | const_cast<Elf_Shdr *>(reinterpret_cast<const Elf_Shdr *>(ShdrRef.p)); | |
223e47cc LB |
134 | |
135 | // This assumes the address passed in matches the target address bitness | |
136 | // The template-based type cast handles everything else. | |
137 | shdr->sh_addr = static_cast<addr_type>(Addr); | |
138 | } | |
139 | ||
1a4d82fc | 140 | template <class ELFT> |
970d7e83 LB |
141 | void DyldELFObject<ELFT>::updateSymbolAddress(const SymbolRef &SymRef, |
142 | uint64_t Addr) { | |
223e47cc | 143 | |
1a4d82fc JJ |
144 | Elf_Sym *sym = const_cast<Elf_Sym *>( |
145 | ELFObjectFile<ELFT>::getSymbol(SymRef.getRawDataRefImpl())); | |
223e47cc LB |
146 | |
147 | // This assumes the address passed in matches the target address bitness | |
148 | // The template-based type cast handles everything else. | |
149 | sym->st_value = static_cast<addr_type>(Addr); | |
150 | } | |
151 | ||
152 | } // namespace | |
153 | ||
223e47cc LB |
154 | namespace llvm { |
155 | ||
1a4d82fc JJ |
156 | void RuntimeDyldELF::registerEHFrames() { |
157 | if (!MemMgr) | |
158 | return; | |
159 | for (int i = 0, e = UnregisteredEHFrameSections.size(); i != e; ++i) { | |
160 | SID EHFrameSID = UnregisteredEHFrameSections[i]; | |
161 | uint8_t *EHFrameAddr = Sections[EHFrameSID].Address; | |
162 | uint64_t EHFrameLoadAddr = Sections[EHFrameSID].LoadAddress; | |
163 | size_t EHFrameSize = Sections[EHFrameSID].Size; | |
164 | MemMgr->registerEHFrames(EHFrameAddr, EHFrameLoadAddr, EHFrameSize); | |
165 | RegisteredEHFrameSections.push_back(EHFrameSID); | |
166 | } | |
167 | UnregisteredEHFrameSections.clear(); | |
168 | } | |
169 | ||
170 | void RuntimeDyldELF::deregisterEHFrames() { | |
171 | if (!MemMgr) | |
172 | return; | |
173 | for (int i = 0, e = RegisteredEHFrameSections.size(); i != e; ++i) { | |
174 | SID EHFrameSID = RegisteredEHFrameSections[i]; | |
175 | uint8_t *EHFrameAddr = Sections[EHFrameSID].Address; | |
176 | uint64_t EHFrameLoadAddr = Sections[EHFrameSID].LoadAddress; | |
177 | size_t EHFrameSize = Sections[EHFrameSID].Size; | |
178 | MemMgr->deregisterEHFrames(EHFrameAddr, EHFrameLoadAddr, EHFrameSize); | |
179 | } | |
180 | RegisteredEHFrameSections.clear(); | |
181 | } | |
182 | ||
183 | ObjectImage * | |
184 | RuntimeDyldELF::createObjectImageFromFile(std::unique_ptr<object::ObjectFile> ObjFile) { | |
185 | if (!ObjFile) | |
186 | return nullptr; | |
187 | ||
188 | std::error_code ec; | |
189 | MemoryBufferRef Buffer = ObjFile->getMemoryBufferRef(); | |
190 | ||
191 | if (ObjFile->getBytesInAddress() == 4 && ObjFile->isLittleEndian()) { | |
192 | auto Obj = | |
193 | llvm::make_unique<DyldELFObject<ELFType<support::little, 2, false>>>( | |
194 | std::move(ObjFile), Buffer, ec); | |
195 | return new ELFObjectImage<ELFType<support::little, 2, false>>( | |
196 | nullptr, std::move(Obj)); | |
197 | } else if (ObjFile->getBytesInAddress() == 4 && !ObjFile->isLittleEndian()) { | |
198 | auto Obj = | |
199 | llvm::make_unique<DyldELFObject<ELFType<support::big, 2, false>>>( | |
200 | std::move(ObjFile), Buffer, ec); | |
201 | return new ELFObjectImage<ELFType<support::big, 2, false>>(nullptr, std::move(Obj)); | |
202 | } else if (ObjFile->getBytesInAddress() == 8 && !ObjFile->isLittleEndian()) { | |
203 | auto Obj = llvm::make_unique<DyldELFObject<ELFType<support::big, 2, true>>>( | |
204 | std::move(ObjFile), Buffer, ec); | |
205 | return new ELFObjectImage<ELFType<support::big, 2, true>>(nullptr, | |
206 | std::move(Obj)); | |
207 | } else if (ObjFile->getBytesInAddress() == 8 && ObjFile->isLittleEndian()) { | |
208 | auto Obj = | |
209 | llvm::make_unique<DyldELFObject<ELFType<support::little, 2, true>>>( | |
210 | std::move(ObjFile), Buffer, ec); | |
211 | return new ELFObjectImage<ELFType<support::little, 2, true>>( | |
212 | nullptr, std::move(Obj)); | |
213 | } else | |
214 | llvm_unreachable("Unexpected ELF format"); | |
215 | } | |
216 | ||
217 | std::unique_ptr<ObjectImage> | |
218 | RuntimeDyldELF::createObjectImage(std::unique_ptr<ObjectBuffer> Buffer) { | |
970d7e83 LB |
219 | if (Buffer->getBufferSize() < ELF::EI_NIDENT) |
220 | llvm_unreachable("Unexpected ELF object size"); | |
1a4d82fc JJ |
221 | std::pair<unsigned char, unsigned char> Ident = |
222 | std::make_pair((uint8_t)Buffer->getBufferStart()[ELF::EI_CLASS], | |
223 | (uint8_t)Buffer->getBufferStart()[ELF::EI_DATA]); | |
224 | std::error_code ec; | |
225 | ||
226 | MemoryBufferRef Buf = Buffer->getMemBuffer(); | |
223e47cc LB |
227 | |
228 | if (Ident.first == ELF::ELFCLASS32 && Ident.second == ELF::ELFDATA2LSB) { | |
1a4d82fc JJ |
229 | auto Obj = |
230 | llvm::make_unique<DyldELFObject<ELFType<support::little, 4, false>>>( | |
231 | Buf, ec); | |
232 | return llvm::make_unique< | |
233 | ELFObjectImage<ELFType<support::little, 4, false>>>(std::move(Buffer), | |
234 | std::move(Obj)); | |
235 | } | |
236 | if (Ident.first == ELF::ELFCLASS32 && Ident.second == ELF::ELFDATA2MSB) { | |
237 | auto Obj = | |
238 | llvm::make_unique<DyldELFObject<ELFType<support::big, 4, false>>>(Buf, | |
239 | ec); | |
240 | return llvm::make_unique<ELFObjectImage<ELFType<support::big, 4, false>>>( | |
241 | std::move(Buffer), std::move(Obj)); | |
242 | } | |
243 | if (Ident.first == ELF::ELFCLASS64 && Ident.second == ELF::ELFDATA2MSB) { | |
244 | auto Obj = llvm::make_unique<DyldELFObject<ELFType<support::big, 8, true>>>( | |
245 | Buf, ec); | |
246 | return llvm::make_unique<ELFObjectImage<ELFType<support::big, 8, true>>>( | |
247 | std::move(Buffer), std::move(Obj)); | |
248 | } | |
249 | assert(Ident.first == ELF::ELFCLASS64 && Ident.second == ELF::ELFDATA2LSB && | |
250 | "Unexpected ELF format"); | |
251 | auto Obj = | |
252 | llvm::make_unique<DyldELFObject<ELFType<support::little, 8, true>>>(Buf, | |
253 | ec); | |
254 | return llvm::make_unique<ELFObjectImage<ELFType<support::little, 8, true>>>( | |
255 | std::move(Buffer), std::move(Obj)); | |
223e47cc LB |
256 | } |
257 | ||
1a4d82fc | 258 | RuntimeDyldELF::~RuntimeDyldELF() {} |
223e47cc | 259 | |
970d7e83 | 260 | void RuntimeDyldELF::resolveX86_64Relocation(const SectionEntry &Section, |
1a4d82fc JJ |
261 | uint64_t Offset, uint64_t Value, |
262 | uint32_t Type, int64_t Addend, | |
263 | uint64_t SymOffset) { | |
223e47cc LB |
264 | switch (Type) { |
265 | default: | |
266 | llvm_unreachable("Relocation type not implemented yet!"); | |
1a4d82fc | 267 | break; |
223e47cc | 268 | case ELF::R_X86_64_64: { |
1a4d82fc JJ |
269 | support::ulittle64_t::ref(Section.Address + Offset) = Value + Addend; |
270 | DEBUG(dbgs() << "Writing " << format("%p", (Value + Addend)) << " at " | |
271 | << format("%p\n", Section.Address + Offset)); | |
223e47cc LB |
272 | break; |
273 | } | |
274 | case ELF::R_X86_64_32: | |
275 | case ELF::R_X86_64_32S: { | |
276 | Value += Addend; | |
277 | assert((Type == ELF::R_X86_64_32 && (Value <= UINT32_MAX)) || | |
970d7e83 | 278 | (Type == ELF::R_X86_64_32S && |
1a4d82fc | 279 | ((int64_t)Value <= INT32_MAX && (int64_t)Value >= INT32_MIN))); |
223e47cc | 280 | uint32_t TruncatedAddr = (Value & 0xFFFFFFFF); |
1a4d82fc JJ |
281 | support::ulittle32_t::ref(Section.Address + Offset) = TruncatedAddr; |
282 | DEBUG(dbgs() << "Writing " << format("%p", TruncatedAddr) << " at " | |
283 | << format("%p\n", Section.Address + Offset)); | |
284 | break; | |
285 | } | |
286 | case ELF::R_X86_64_GOTPCREL: { | |
287 | // findGOTEntry returns the 'G + GOT' part of the relocation calculation | |
288 | // based on the load/target address of the GOT (not the current/local addr). | |
289 | uint64_t GOTAddr = findGOTEntry(Value, SymOffset); | |
290 | uint64_t FinalAddress = Section.LoadAddress + Offset; | |
291 | // The processRelocationRef method combines the symbol offset and the addend | |
292 | // and in most cases that's what we want. For this relocation type, we need | |
293 | // the raw addend, so we subtract the symbol offset to get it. | |
294 | int64_t RealOffset = GOTAddr + Addend - SymOffset - FinalAddress; | |
295 | assert(RealOffset <= INT32_MAX && RealOffset >= INT32_MIN); | |
296 | int32_t TruncOffset = (RealOffset & 0xFFFFFFFF); | |
297 | support::ulittle32_t::ref(Section.Address + Offset) = TruncOffset; | |
223e47cc LB |
298 | break; |
299 | } | |
300 | case ELF::R_X86_64_PC32: { | |
970d7e83 LB |
301 | // Get the placeholder value from the generated object since |
302 | // a previous relocation attempt may have overwritten the loaded version | |
1a4d82fc JJ |
303 | support::ulittle32_t::ref Placeholder( |
304 | (void *)(Section.ObjAddress + Offset)); | |
305 | uint64_t FinalAddress = Section.LoadAddress + Offset; | |
306 | int64_t RealOffset = Placeholder + Value + Addend - FinalAddress; | |
223e47cc LB |
307 | assert(RealOffset <= INT32_MAX && RealOffset >= INT32_MIN); |
308 | int32_t TruncOffset = (RealOffset & 0xFFFFFFFF); | |
1a4d82fc JJ |
309 | support::ulittle32_t::ref(Section.Address + Offset) = TruncOffset; |
310 | break; | |
311 | } | |
312 | case ELF::R_X86_64_PC64: { | |
313 | // Get the placeholder value from the generated object since | |
314 | // a previous relocation attempt may have overwritten the loaded version | |
315 | support::ulittle64_t::ref Placeholder( | |
316 | (void *)(Section.ObjAddress + Offset)); | |
317 | uint64_t FinalAddress = Section.LoadAddress + Offset; | |
318 | support::ulittle64_t::ref(Section.Address + Offset) = | |
319 | Placeholder + Value + Addend - FinalAddress; | |
223e47cc LB |
320 | break; |
321 | } | |
322 | } | |
323 | } | |
324 | ||
970d7e83 | 325 | void RuntimeDyldELF::resolveX86Relocation(const SectionEntry &Section, |
1a4d82fc JJ |
326 | uint64_t Offset, uint32_t Value, |
327 | uint32_t Type, int32_t Addend) { | |
223e47cc LB |
328 | switch (Type) { |
329 | case ELF::R_386_32: { | |
970d7e83 LB |
330 | // Get the placeholder value from the generated object since |
331 | // a previous relocation attempt may have overwritten the loaded version | |
1a4d82fc JJ |
332 | support::ulittle32_t::ref Placeholder( |
333 | (void *)(Section.ObjAddress + Offset)); | |
334 | support::ulittle32_t::ref(Section.Address + Offset) = | |
335 | Placeholder + Value + Addend; | |
223e47cc LB |
336 | break; |
337 | } | |
338 | case ELF::R_386_PC32: { | |
970d7e83 LB |
339 | // Get the placeholder value from the generated object since |
340 | // a previous relocation attempt may have overwritten the loaded version | |
1a4d82fc JJ |
341 | support::ulittle32_t::ref Placeholder( |
342 | (void *)(Section.ObjAddress + Offset)); | |
343 | uint32_t FinalAddress = ((Section.LoadAddress + Offset) & 0xFFFFFFFF); | |
344 | uint32_t RealOffset = Placeholder + Value + Addend - FinalAddress; | |
345 | support::ulittle32_t::ref(Section.Address + Offset) = RealOffset; | |
346 | break; | |
347 | } | |
348 | default: | |
349 | // There are other relocation types, but it appears these are the | |
350 | // only ones currently used by the LLVM ELF object writer | |
351 | llvm_unreachable("Relocation type not implemented yet!"); | |
223e47cc | 352 | break; |
1a4d82fc JJ |
353 | } |
354 | } | |
355 | ||
356 | void RuntimeDyldELF::resolveAArch64Relocation(const SectionEntry &Section, | |
357 | uint64_t Offset, uint64_t Value, | |
358 | uint32_t Type, int64_t Addend) { | |
359 | uint32_t *TargetPtr = reinterpret_cast<uint32_t *>(Section.Address + Offset); | |
360 | uint64_t FinalAddress = Section.LoadAddress + Offset; | |
361 | ||
362 | DEBUG(dbgs() << "resolveAArch64Relocation, LocalAddress: 0x" | |
363 | << format("%llx", Section.Address + Offset) | |
364 | << " FinalAddress: 0x" << format("%llx", FinalAddress) | |
365 | << " Value: 0x" << format("%llx", Value) << " Type: 0x" | |
366 | << format("%x", Type) << " Addend: 0x" << format("%llx", Addend) | |
367 | << "\n"); | |
368 | ||
369 | switch (Type) { | |
370 | default: | |
371 | llvm_unreachable("Relocation type not implemented yet!"); | |
372 | break; | |
373 | case ELF::R_AARCH64_ABS64: { | |
374 | uint64_t *TargetPtr = | |
375 | reinterpret_cast<uint64_t *>(Section.Address + Offset); | |
376 | *TargetPtr = Value + Addend; | |
377 | break; | |
378 | } | |
379 | case ELF::R_AARCH64_PREL32: { | |
380 | uint64_t Result = Value + Addend - FinalAddress; | |
381 | assert(static_cast<int64_t>(Result) >= INT32_MIN && | |
382 | static_cast<int64_t>(Result) <= UINT32_MAX); | |
383 | *TargetPtr = static_cast<uint32_t>(Result & 0xffffffffU); | |
384 | break; | |
385 | } | |
386 | case ELF::R_AARCH64_CALL26: // fallthrough | |
387 | case ELF::R_AARCH64_JUMP26: { | |
388 | // Operation: S+A-P. Set Call or B immediate value to bits fff_fffc of the | |
389 | // calculation. | |
390 | uint64_t BranchImm = Value + Addend - FinalAddress; | |
391 | ||
392 | // "Check that -2^27 <= result < 2^27". | |
393 | assert(-(1LL << 27) <= static_cast<int64_t>(BranchImm) && | |
394 | static_cast<int64_t>(BranchImm) < (1LL << 27)); | |
395 | ||
396 | // AArch64 code is emitted with .rela relocations. The data already in any | |
397 | // bits affected by the relocation on entry is garbage. | |
398 | *TargetPtr &= 0xfc000000U; | |
399 | // Immediate goes in bits 25:0 of B and BL. | |
400 | *TargetPtr |= static_cast<uint32_t>(BranchImm & 0xffffffcU) >> 2; | |
401 | break; | |
402 | } | |
403 | case ELF::R_AARCH64_MOVW_UABS_G3: { | |
404 | uint64_t Result = Value + Addend; | |
405 | ||
406 | // AArch64 code is emitted with .rela relocations. The data already in any | |
407 | // bits affected by the relocation on entry is garbage. | |
408 | *TargetPtr &= 0xffe0001fU; | |
409 | // Immediate goes in bits 20:5 of MOVZ/MOVK instruction | |
410 | *TargetPtr |= Result >> (48 - 5); | |
411 | // Shift must be "lsl #48", in bits 22:21 | |
412 | assert((*TargetPtr >> 21 & 0x3) == 3 && "invalid shift for relocation"); | |
413 | break; | |
414 | } | |
415 | case ELF::R_AARCH64_MOVW_UABS_G2_NC: { | |
416 | uint64_t Result = Value + Addend; | |
417 | ||
418 | // AArch64 code is emitted with .rela relocations. The data already in any | |
419 | // bits affected by the relocation on entry is garbage. | |
420 | *TargetPtr &= 0xffe0001fU; | |
421 | // Immediate goes in bits 20:5 of MOVZ/MOVK instruction | |
422 | *TargetPtr |= ((Result & 0xffff00000000ULL) >> (32 - 5)); | |
423 | // Shift must be "lsl #32", in bits 22:21 | |
424 | assert((*TargetPtr >> 21 & 0x3) == 2 && "invalid shift for relocation"); | |
425 | break; | |
426 | } | |
427 | case ELF::R_AARCH64_MOVW_UABS_G1_NC: { | |
428 | uint64_t Result = Value + Addend; | |
429 | ||
430 | // AArch64 code is emitted with .rela relocations. The data already in any | |
431 | // bits affected by the relocation on entry is garbage. | |
432 | *TargetPtr &= 0xffe0001fU; | |
433 | // Immediate goes in bits 20:5 of MOVZ/MOVK instruction | |
434 | *TargetPtr |= ((Result & 0xffff0000U) >> (16 - 5)); | |
435 | // Shift must be "lsl #16", in bits 22:2 | |
436 | assert((*TargetPtr >> 21 & 0x3) == 1 && "invalid shift for relocation"); | |
437 | break; | |
438 | } | |
439 | case ELF::R_AARCH64_MOVW_UABS_G0_NC: { | |
440 | uint64_t Result = Value + Addend; | |
441 | ||
442 | // AArch64 code is emitted with .rela relocations. The data already in any | |
443 | // bits affected by the relocation on entry is garbage. | |
444 | *TargetPtr &= 0xffe0001fU; | |
445 | // Immediate goes in bits 20:5 of MOVZ/MOVK instruction | |
446 | *TargetPtr |= ((Result & 0xffffU) << 5); | |
447 | // Shift must be "lsl #0", in bits 22:21. | |
448 | assert((*TargetPtr >> 21 & 0x3) == 0 && "invalid shift for relocation"); | |
449 | break; | |
450 | } | |
451 | case ELF::R_AARCH64_ADR_PREL_PG_HI21: { | |
452 | // Operation: Page(S+A) - Page(P) | |
453 | uint64_t Result = | |
454 | ((Value + Addend) & ~0xfffULL) - (FinalAddress & ~0xfffULL); | |
455 | ||
456 | // Check that -2^32 <= X < 2^32 | |
457 | assert(static_cast<int64_t>(Result) >= (-1LL << 32) && | |
458 | static_cast<int64_t>(Result) < (1LL << 32) && | |
459 | "overflow check failed for relocation"); | |
460 | ||
461 | // AArch64 code is emitted with .rela relocations. The data already in any | |
462 | // bits affected by the relocation on entry is garbage. | |
463 | *TargetPtr &= 0x9f00001fU; | |
464 | // Immediate goes in bits 30:29 + 5:23 of ADRP instruction, taken | |
465 | // from bits 32:12 of X. | |
466 | *TargetPtr |= ((Result & 0x3000U) << (29 - 12)); | |
467 | *TargetPtr |= ((Result & 0x1ffffc000ULL) >> (14 - 5)); | |
468 | break; | |
469 | } | |
470 | case ELF::R_AARCH64_LDST32_ABS_LO12_NC: { | |
471 | // Operation: S + A | |
472 | uint64_t Result = Value + Addend; | |
473 | ||
474 | // AArch64 code is emitted with .rela relocations. The data already in any | |
475 | // bits affected by the relocation on entry is garbage. | |
476 | *TargetPtr &= 0xffc003ffU; | |
477 | // Immediate goes in bits 21:10 of LD/ST instruction, taken | |
478 | // from bits 11:2 of X | |
479 | *TargetPtr |= ((Result & 0xffc) << (10 - 2)); | |
480 | break; | |
481 | } | |
482 | case ELF::R_AARCH64_LDST64_ABS_LO12_NC: { | |
483 | // Operation: S + A | |
484 | uint64_t Result = Value + Addend; | |
485 | ||
486 | // AArch64 code is emitted with .rela relocations. The data already in any | |
487 | // bits affected by the relocation on entry is garbage. | |
488 | *TargetPtr &= 0xffc003ffU; | |
489 | // Immediate goes in bits 21:10 of LD/ST instruction, taken | |
490 | // from bits 11:3 of X | |
491 | *TargetPtr |= ((Result & 0xff8) << (10 - 3)); | |
492 | break; | |
493 | } | |
223e47cc LB |
494 | } |
495 | } | |
496 | ||
970d7e83 | 497 | void RuntimeDyldELF::resolveARMRelocation(const SectionEntry &Section, |
1a4d82fc JJ |
498 | uint64_t Offset, uint32_t Value, |
499 | uint32_t Type, int32_t Addend) { | |
223e47cc | 500 | // TODO: Add Thumb relocations. |
1a4d82fc JJ |
501 | uint32_t *Placeholder = |
502 | reinterpret_cast<uint32_t *>(Section.ObjAddress + Offset); | |
503 | uint32_t *TargetPtr = (uint32_t *)(Section.Address + Offset); | |
970d7e83 | 504 | uint32_t FinalAddress = ((Section.LoadAddress + Offset) & 0xFFFFFFFF); |
223e47cc LB |
505 | Value += Addend; |
506 | ||
970d7e83 LB |
507 | DEBUG(dbgs() << "resolveARMRelocation, LocalAddress: " |
508 | << Section.Address + Offset | |
1a4d82fc JJ |
509 | << " FinalAddress: " << format("%p", FinalAddress) << " Value: " |
510 | << format("%x", Value) << " Type: " << format("%x", Type) | |
511 | << " Addend: " << format("%x", Addend) << "\n"); | |
223e47cc | 512 | |
1a4d82fc | 513 | switch (Type) { |
223e47cc LB |
514 | default: |
515 | llvm_unreachable("Not implemented relocation type!"); | |
516 | ||
1a4d82fc JJ |
517 | case ELF::R_ARM_NONE: |
518 | break; | |
970d7e83 LB |
519 | // Write a 32bit value to relocation address, taking into account the |
520 | // implicit addend encoded in the target. | |
1a4d82fc JJ |
521 | case ELF::R_ARM_PREL31: |
522 | case ELF::R_ARM_TARGET1: | |
523 | case ELF::R_ARM_ABS32: | |
524 | *TargetPtr = *Placeholder + Value; | |
223e47cc | 525 | break; |
223e47cc LB |
526 | // Write first 16 bit of 32 bit value to the mov instruction. |
527 | // Last 4 bit should be shifted. | |
1a4d82fc | 528 | case ELF::R_ARM_MOVW_ABS_NC: |
970d7e83 LB |
529 | // We are not expecting any other addend in the relocation address. |
530 | // Using 0x000F0FFF because MOVW has its 16 bit immediate split into 2 | |
531 | // non-contiguous fields. | |
1a4d82fc | 532 | assert((*Placeholder & 0x000F0FFF) == 0); |
223e47cc | 533 | Value = Value & 0xFFFF; |
1a4d82fc | 534 | *TargetPtr = *Placeholder | (Value & 0xFFF); |
223e47cc LB |
535 | *TargetPtr |= ((Value >> 12) & 0xF) << 16; |
536 | break; | |
223e47cc LB |
537 | // Write last 16 bit of 32 bit value to the mov instruction. |
538 | // Last 4 bit should be shifted. | |
1a4d82fc | 539 | case ELF::R_ARM_MOVT_ABS: |
970d7e83 LB |
540 | // We are not expecting any other addend in the relocation address. |
541 | // Use 0x000F0FFF for the same reason as R_ARM_MOVW_ABS_NC. | |
1a4d82fc JJ |
542 | assert((*Placeholder & 0x000F0FFF) == 0); |
543 | ||
223e47cc | 544 | Value = (Value >> 16) & 0xFFFF; |
1a4d82fc | 545 | *TargetPtr = *Placeholder | (Value & 0xFFF); |
223e47cc LB |
546 | *TargetPtr |= ((Value >> 12) & 0xF) << 16; |
547 | break; | |
223e47cc | 548 | // Write 24 bit relative value to the branch instruction. |
1a4d82fc JJ |
549 | case ELF::R_ARM_PC24: // Fall through. |
550 | case ELF::R_ARM_CALL: // Fall through. | |
551 | case ELF::R_ARM_JUMP24: { | |
223e47cc LB |
552 | int32_t RelValue = static_cast<int32_t>(Value - FinalAddress - 8); |
553 | RelValue = (RelValue & 0x03FFFFFC) >> 2; | |
1a4d82fc | 554 | assert((*TargetPtr & 0xFFFFFF) == 0xFFFFFE); |
223e47cc LB |
555 | *TargetPtr &= 0xFF000000; |
556 | *TargetPtr |= RelValue; | |
557 | break; | |
558 | } | |
1a4d82fc JJ |
559 | case ELF::R_ARM_PRIVATE_0: |
560 | // This relocation is reserved by the ARM ELF ABI for internal use. We | |
561 | // appropriate it here to act as an R_ARM_ABS32 without any addend for use | |
562 | // in the stubs created during JIT (which can't put an addend into the | |
563 | // original object file). | |
564 | *TargetPtr = Value; | |
565 | break; | |
566 | } | |
223e47cc LB |
567 | } |
568 | ||
970d7e83 | 569 | void RuntimeDyldELF::resolveMIPSRelocation(const SectionEntry &Section, |
1a4d82fc JJ |
570 | uint64_t Offset, uint32_t Value, |
571 | uint32_t Type, int32_t Addend) { | |
572 | uint32_t *Placeholder = | |
573 | reinterpret_cast<uint32_t *>(Section.ObjAddress + Offset); | |
574 | uint32_t *TargetPtr = (uint32_t *)(Section.Address + Offset); | |
223e47cc LB |
575 | Value += Addend; |
576 | ||
970d7e83 | 577 | DEBUG(dbgs() << "resolveMipselocation, LocalAddress: " |
1a4d82fc JJ |
578 | << Section.Address + Offset << " FinalAddress: " |
579 | << format("%p", Section.LoadAddress + Offset) << " Value: " | |
580 | << format("%x", Value) << " Type: " << format("%x", Type) | |
581 | << " Addend: " << format("%x", Addend) << "\n"); | |
223e47cc | 582 | |
1a4d82fc | 583 | switch (Type) { |
223e47cc LB |
584 | default: |
585 | llvm_unreachable("Not implemented relocation type!"); | |
586 | break; | |
587 | case ELF::R_MIPS_32: | |
1a4d82fc | 588 | *TargetPtr = Value + (*Placeholder); |
223e47cc LB |
589 | break; |
590 | case ELF::R_MIPS_26: | |
1a4d82fc | 591 | *TargetPtr = ((*Placeholder) & 0xfc000000) | ((Value & 0x0fffffff) >> 2); |
223e47cc LB |
592 | break; |
593 | case ELF::R_MIPS_HI16: | |
594 | // Get the higher 16-bits. Also add 1 if bit 15 is 1. | |
1a4d82fc JJ |
595 | Value += ((*Placeholder) & 0x0000ffff) << 16; |
596 | *TargetPtr = | |
597 | ((*Placeholder) & 0xffff0000) | (((Value + 0x8000) >> 16) & 0xffff); | |
598 | break; | |
599 | case ELF::R_MIPS_LO16: | |
600 | Value += ((*Placeholder) & 0x0000ffff); | |
601 | *TargetPtr = ((*Placeholder) & 0xffff0000) | (Value & 0xffff); | |
223e47cc | 602 | break; |
1a4d82fc JJ |
603 | case ELF::R_MIPS_UNUSED1: |
604 | // Similar to ELF::R_ARM_PRIVATE_0, R_MIPS_UNUSED1 and R_MIPS_UNUSED2 | |
605 | // are used for internal JIT purpose. These relocations are similar to | |
606 | // R_MIPS_HI16 and R_MIPS_LO16, but they do not take any addend into | |
607 | // account. | |
608 | *TargetPtr = | |
609 | ((*TargetPtr) & 0xffff0000) | (((Value + 0x8000) >> 16) & 0xffff); | |
610 | break; | |
611 | case ELF::R_MIPS_UNUSED2: | |
223e47cc LB |
612 | *TargetPtr = ((*TargetPtr) & 0xffff0000) | (Value & 0xffff); |
613 | break; | |
1a4d82fc | 614 | } |
223e47cc LB |
615 | } |
616 | ||
1a4d82fc JJ |
617 | // Return the .TOC. section and offset. |
618 | void RuntimeDyldELF::findPPC64TOCSection(ObjectImage &Obj, | |
619 | ObjSectionToIDMap &LocalSections, | |
620 | RelocationValueRef &Rel) { | |
621 | // Set a default SectionID in case we do not find a TOC section below. | |
622 | // This may happen for references to TOC base base (sym@toc, .odp | |
623 | // relocation) without a .toc directive. In this case just use the | |
624 | // first section (which is usually the .odp) since the code won't | |
625 | // reference the .toc base directly. | |
626 | Rel.SymbolName = NULL; | |
627 | Rel.SectionID = 0; | |
628 | ||
970d7e83 LB |
629 | // The TOC consists of sections .got, .toc, .tocbss, .plt in that |
630 | // order. The TOC starts where the first of these sections starts. | |
1a4d82fc JJ |
631 | for (section_iterator si = Obj.begin_sections(), se = Obj.end_sections(); |
632 | si != se; ++si) { | |
633 | ||
634 | StringRef SectionName; | |
635 | check(si->getName(SectionName)); | |
636 | ||
637 | if (SectionName == ".got" | |
638 | || SectionName == ".toc" | |
639 | || SectionName == ".tocbss" | |
640 | || SectionName == ".plt") { | |
641 | Rel.SectionID = findOrEmitSection(Obj, *si, false, LocalSections); | |
970d7e83 | 642 | break; |
1a4d82fc | 643 | } |
970d7e83 | 644 | } |
1a4d82fc | 645 | |
970d7e83 LB |
646 | // Per the ppc64-elf-linux ABI, The TOC base is TOC value plus 0x8000 |
647 | // thus permitting a full 64 Kbytes segment. | |
1a4d82fc | 648 | Rel.Addend = 0x8000; |
970d7e83 LB |
649 | } |
650 | ||
651 | // Returns the sections and offset associated with the ODP entry referenced | |
652 | // by Symbol. | |
653 | void RuntimeDyldELF::findOPDEntrySection(ObjectImage &Obj, | |
654 | ObjSectionToIDMap &LocalSections, | |
655 | RelocationValueRef &Rel) { | |
656 | // Get the ELF symbol value (st_value) to compare with Relocation offset in | |
657 | // .opd entries | |
1a4d82fc JJ |
658 | for (section_iterator si = Obj.begin_sections(), se = Obj.end_sections(); |
659 | si != se; ++si) { | |
660 | section_iterator RelSecI = si->getRelocatedSection(); | |
661 | if (RelSecI == Obj.end_sections()) | |
970d7e83 LB |
662 | continue; |
663 | ||
1a4d82fc JJ |
664 | StringRef RelSectionName; |
665 | check(RelSecI->getName(RelSectionName)); | |
666 | if (RelSectionName != ".opd") | |
667 | continue; | |
970d7e83 | 668 | |
1a4d82fc JJ |
669 | for (relocation_iterator i = si->relocation_begin(), |
670 | e = si->relocation_end(); | |
671 | i != e;) { | |
970d7e83 LB |
672 | // The R_PPC64_ADDR64 relocation indicates the first field |
673 | // of a .opd entry | |
674 | uint64_t TypeFunc; | |
675 | check(i->getType(TypeFunc)); | |
676 | if (TypeFunc != ELF::R_PPC64_ADDR64) { | |
1a4d82fc | 677 | ++i; |
970d7e83 LB |
678 | continue; |
679 | } | |
680 | ||
970d7e83 | 681 | uint64_t TargetSymbolOffset; |
1a4d82fc | 682 | symbol_iterator TargetSymbol = i->getSymbol(); |
970d7e83 | 683 | check(i->getOffset(TargetSymbolOffset)); |
1a4d82fc JJ |
684 | int64_t Addend; |
685 | check(getELFRelocationAddend(*i, Addend)); | |
970d7e83 | 686 | |
1a4d82fc | 687 | ++i; |
970d7e83 LB |
688 | if (i == e) |
689 | break; | |
970d7e83 LB |
690 | |
691 | // Just check if following relocation is a R_PPC64_TOC | |
692 | uint64_t TypeTOC; | |
693 | check(i->getType(TypeTOC)); | |
694 | if (TypeTOC != ELF::R_PPC64_TOC) | |
695 | continue; | |
696 | ||
697 | // Finally compares the Symbol value and the target symbol offset | |
698 | // to check if this .opd entry refers to the symbol the relocation | |
699 | // points to. | |
1a4d82fc | 700 | if (Rel.Addend != (int64_t)TargetSymbolOffset) |
970d7e83 LB |
701 | continue; |
702 | ||
703 | section_iterator tsi(Obj.end_sections()); | |
1a4d82fc JJ |
704 | check(TargetSymbol->getSection(tsi)); |
705 | bool IsCode = false; | |
706 | tsi->isText(IsCode); | |
707 | Rel.SectionID = findOrEmitSection(Obj, (*tsi), IsCode, LocalSections); | |
708 | Rel.Addend = (intptr_t)Addend; | |
970d7e83 LB |
709 | return; |
710 | } | |
711 | } | |
712 | llvm_unreachable("Attempting to get address of ODP entry!"); | |
713 | } | |
714 | ||
1a4d82fc JJ |
715 | // Relocation masks following the #lo(value), #hi(value), #ha(value), |
716 | // #higher(value), #highera(value), #highest(value), and #highesta(value) | |
717 | // macros defined in section 4.5.1. Relocation Types of the PPC-elf64abi | |
718 | // document. | |
719 | ||
720 | static inline uint16_t applyPPClo(uint64_t value) { return value & 0xffff; } | |
970d7e83 | 721 | |
1a4d82fc | 722 | static inline uint16_t applyPPChi(uint64_t value) { |
970d7e83 LB |
723 | return (value >> 16) & 0xffff; |
724 | } | |
725 | ||
1a4d82fc JJ |
726 | static inline uint16_t applyPPCha (uint64_t value) { |
727 | return ((value + 0x8000) >> 16) & 0xffff; | |
728 | } | |
729 | ||
730 | static inline uint16_t applyPPChigher(uint64_t value) { | |
970d7e83 LB |
731 | return (value >> 32) & 0xffff; |
732 | } | |
733 | ||
1a4d82fc JJ |
734 | static inline uint16_t applyPPChighera (uint64_t value) { |
735 | return ((value + 0x8000) >> 32) & 0xffff; | |
736 | } | |
737 | ||
738 | static inline uint16_t applyPPChighest(uint64_t value) { | |
970d7e83 LB |
739 | return (value >> 48) & 0xffff; |
740 | } | |
741 | ||
1a4d82fc JJ |
742 | static inline uint16_t applyPPChighesta (uint64_t value) { |
743 | return ((value + 0x8000) >> 48) & 0xffff; | |
744 | } | |
745 | ||
970d7e83 | 746 | void RuntimeDyldELF::resolvePPC64Relocation(const SectionEntry &Section, |
1a4d82fc JJ |
747 | uint64_t Offset, uint64_t Value, |
748 | uint32_t Type, int64_t Addend) { | |
749 | uint8_t *LocalAddress = Section.Address + Offset; | |
970d7e83 LB |
750 | switch (Type) { |
751 | default: | |
752 | llvm_unreachable("Relocation type not implemented yet!"); | |
970d7e83 | 753 | break; |
1a4d82fc JJ |
754 | case ELF::R_PPC64_ADDR16: |
755 | writeInt16BE(LocalAddress, applyPPClo(Value + Addend)); | |
756 | break; | |
757 | case ELF::R_PPC64_ADDR16_DS: | |
758 | writeInt16BE(LocalAddress, applyPPClo(Value + Addend) & ~3); | |
759 | break; | |
760 | case ELF::R_PPC64_ADDR16_LO: | |
761 | writeInt16BE(LocalAddress, applyPPClo(Value + Addend)); | |
970d7e83 | 762 | break; |
1a4d82fc JJ |
763 | case ELF::R_PPC64_ADDR16_LO_DS: |
764 | writeInt16BE(LocalAddress, applyPPClo(Value + Addend) & ~3); | |
970d7e83 | 765 | break; |
1a4d82fc JJ |
766 | case ELF::R_PPC64_ADDR16_HI: |
767 | writeInt16BE(LocalAddress, applyPPChi(Value + Addend)); | |
970d7e83 | 768 | break; |
1a4d82fc JJ |
769 | case ELF::R_PPC64_ADDR16_HA: |
770 | writeInt16BE(LocalAddress, applyPPCha(Value + Addend)); | |
771 | break; | |
772 | case ELF::R_PPC64_ADDR16_HIGHER: | |
773 | writeInt16BE(LocalAddress, applyPPChigher(Value + Addend)); | |
774 | break; | |
775 | case ELF::R_PPC64_ADDR16_HIGHERA: | |
776 | writeInt16BE(LocalAddress, applyPPChighera(Value + Addend)); | |
777 | break; | |
778 | case ELF::R_PPC64_ADDR16_HIGHEST: | |
779 | writeInt16BE(LocalAddress, applyPPChighest(Value + Addend)); | |
780 | break; | |
781 | case ELF::R_PPC64_ADDR16_HIGHESTA: | |
782 | writeInt16BE(LocalAddress, applyPPChighesta(Value + Addend)); | |
783 | break; | |
784 | case ELF::R_PPC64_ADDR14: { | |
970d7e83 LB |
785 | assert(((Value + Addend) & 3) == 0); |
786 | // Preserve the AA/LK bits in the branch instruction | |
1a4d82fc | 787 | uint8_t aalk = *(LocalAddress + 3); |
970d7e83 LB |
788 | writeInt16BE(LocalAddress + 2, (aalk & 3) | ((Value + Addend) & 0xfffc)); |
789 | } break; | |
1a4d82fc JJ |
790 | case ELF::R_PPC64_REL16_LO: { |
791 | uint64_t FinalAddress = (Section.LoadAddress + Offset); | |
792 | uint64_t Delta = Value - FinalAddress + Addend; | |
793 | writeInt16BE(LocalAddress, applyPPClo(Delta)); | |
794 | } break; | |
795 | case ELF::R_PPC64_REL16_HI: { | |
796 | uint64_t FinalAddress = (Section.LoadAddress + Offset); | |
797 | uint64_t Delta = Value - FinalAddress + Addend; | |
798 | writeInt16BE(LocalAddress, applyPPChi(Delta)); | |
799 | } break; | |
800 | case ELF::R_PPC64_REL16_HA: { | |
801 | uint64_t FinalAddress = (Section.LoadAddress + Offset); | |
802 | uint64_t Delta = Value - FinalAddress + Addend; | |
803 | writeInt16BE(LocalAddress, applyPPCha(Delta)); | |
804 | } break; | |
805 | case ELF::R_PPC64_ADDR32: { | |
970d7e83 LB |
806 | int32_t Result = static_cast<int32_t>(Value + Addend); |
807 | if (SignExtend32<32>(Result) != Result) | |
808 | llvm_unreachable("Relocation R_PPC64_ADDR32 overflow"); | |
809 | writeInt32BE(LocalAddress, Result); | |
810 | } break; | |
1a4d82fc | 811 | case ELF::R_PPC64_REL24: { |
970d7e83 LB |
812 | uint64_t FinalAddress = (Section.LoadAddress + Offset); |
813 | int32_t delta = static_cast<int32_t>(Value - FinalAddress + Addend); | |
814 | if (SignExtend32<24>(delta) != delta) | |
815 | llvm_unreachable("Relocation R_PPC64_REL24 overflow"); | |
816 | // Generates a 'bl <address>' instruction | |
817 | writeInt32BE(LocalAddress, 0x48000001 | (delta & 0x03FFFFFC)); | |
818 | } break; | |
1a4d82fc | 819 | case ELF::R_PPC64_REL32: { |
970d7e83 LB |
820 | uint64_t FinalAddress = (Section.LoadAddress + Offset); |
821 | int32_t delta = static_cast<int32_t>(Value - FinalAddress + Addend); | |
822 | if (SignExtend32<32>(delta) != delta) | |
823 | llvm_unreachable("Relocation R_PPC64_REL32 overflow"); | |
824 | writeInt32BE(LocalAddress, delta); | |
825 | } break; | |
1a4d82fc JJ |
826 | case ELF::R_PPC64_REL64: { |
827 | uint64_t FinalAddress = (Section.LoadAddress + Offset); | |
828 | uint64_t Delta = Value - FinalAddress + Addend; | |
829 | writeInt64BE(LocalAddress, Delta); | |
830 | } break; | |
831 | case ELF::R_PPC64_ADDR64: | |
970d7e83 LB |
832 | writeInt64BE(LocalAddress, Value + Addend); |
833 | break; | |
1a4d82fc JJ |
834 | } |
835 | } | |
836 | ||
837 | void RuntimeDyldELF::resolveSystemZRelocation(const SectionEntry &Section, | |
838 | uint64_t Offset, uint64_t Value, | |
839 | uint32_t Type, int64_t Addend) { | |
840 | uint8_t *LocalAddress = Section.Address + Offset; | |
841 | switch (Type) { | |
842 | default: | |
843 | llvm_unreachable("Relocation type not implemented yet!"); | |
844 | break; | |
845 | case ELF::R_390_PC16DBL: | |
846 | case ELF::R_390_PLT16DBL: { | |
847 | int64_t Delta = (Value + Addend) - (Section.LoadAddress + Offset); | |
848 | assert(int16_t(Delta / 2) * 2 == Delta && "R_390_PC16DBL overflow"); | |
849 | writeInt16BE(LocalAddress, Delta / 2); | |
850 | break; | |
851 | } | |
852 | case ELF::R_390_PC32DBL: | |
853 | case ELF::R_390_PLT32DBL: { | |
854 | int64_t Delta = (Value + Addend) - (Section.LoadAddress + Offset); | |
855 | assert(int32_t(Delta / 2) * 2 == Delta && "R_390_PC32DBL overflow"); | |
856 | writeInt32BE(LocalAddress, Delta / 2); | |
857 | break; | |
858 | } | |
859 | case ELF::R_390_PC32: { | |
860 | int64_t Delta = (Value + Addend) - (Section.LoadAddress + Offset); | |
861 | assert(int32_t(Delta) == Delta && "R_390_PC32 overflow"); | |
862 | writeInt32BE(LocalAddress, Delta); | |
863 | break; | |
864 | } | |
865 | case ELF::R_390_64: | |
866 | writeInt64BE(LocalAddress, Value + Addend); | |
970d7e83 | 867 | break; |
970d7e83 LB |
868 | } |
869 | } | |
870 | ||
1a4d82fc JJ |
871 | // The target location for the relocation is described by RE.SectionID and |
872 | // RE.Offset. RE.SectionID can be used to find the SectionEntry. Each | |
873 | // SectionEntry has three members describing its location. | |
874 | // SectionEntry::Address is the address at which the section has been loaded | |
875 | // into memory in the current (host) process. SectionEntry::LoadAddress is the | |
876 | // address that the section will have in the target process. | |
877 | // SectionEntry::ObjAddress is the address of the bits for this section in the | |
878 | // original emitted object image (also in the current address space). | |
879 | // | |
880 | // Relocations will be applied as if the section were loaded at | |
881 | // SectionEntry::LoadAddress, but they will be applied at an address based | |
882 | // on SectionEntry::Address. SectionEntry::ObjAddress will be used to refer to | |
883 | // Target memory contents if they are required for value calculations. | |
884 | // | |
885 | // The Value parameter here is the load address of the symbol for the | |
886 | // relocation to be applied. For relocations which refer to symbols in the | |
887 | // current object Value will be the LoadAddress of the section in which | |
888 | // the symbol resides (RE.Addend provides additional information about the | |
889 | // symbol location). For external symbols, Value will be the address of the | |
890 | // symbol in the target address space. | |
891 | void RuntimeDyldELF::resolveRelocation(const RelocationEntry &RE, | |
892 | uint64_t Value) { | |
893 | const SectionEntry &Section = Sections[RE.SectionID]; | |
894 | return resolveRelocation(Section, RE.Offset, Value, RE.RelType, RE.Addend, | |
895 | RE.SymOffset); | |
896 | } | |
897 | ||
970d7e83 | 898 | void RuntimeDyldELF::resolveRelocation(const SectionEntry &Section, |
1a4d82fc JJ |
899 | uint64_t Offset, uint64_t Value, |
900 | uint32_t Type, int64_t Addend, | |
901 | uint64_t SymOffset) { | |
223e47cc LB |
902 | switch (Arch) { |
903 | case Triple::x86_64: | |
1a4d82fc | 904 | resolveX86_64Relocation(Section, Offset, Value, Type, Addend, SymOffset); |
223e47cc LB |
905 | break; |
906 | case Triple::x86: | |
1a4d82fc | 907 | resolveX86Relocation(Section, Offset, (uint32_t)(Value & 0xffffffffL), Type, |
223e47cc LB |
908 | (uint32_t)(Addend & 0xffffffffL)); |
909 | break; | |
1a4d82fc JJ |
910 | case Triple::aarch64: |
911 | case Triple::aarch64_be: | |
912 | resolveAArch64Relocation(Section, Offset, Value, Type, Addend); | |
913 | break; | |
914 | case Triple::arm: // Fall through. | |
915 | case Triple::armeb: | |
223e47cc | 916 | case Triple::thumb: |
1a4d82fc JJ |
917 | case Triple::thumbeb: |
918 | resolveARMRelocation(Section, Offset, (uint32_t)(Value & 0xffffffffL), Type, | |
223e47cc LB |
919 | (uint32_t)(Addend & 0xffffffffL)); |
920 | break; | |
1a4d82fc | 921 | case Triple::mips: // Fall through. |
223e47cc | 922 | case Triple::mipsel: |
1a4d82fc JJ |
923 | resolveMIPSRelocation(Section, Offset, (uint32_t)(Value & 0xffffffffL), |
924 | Type, (uint32_t)(Addend & 0xffffffffL)); | |
223e47cc | 925 | break; |
1a4d82fc JJ |
926 | case Triple::ppc64: // Fall through. |
927 | case Triple::ppc64le: | |
970d7e83 LB |
928 | resolvePPC64Relocation(Section, Offset, Value, Type, Addend); |
929 | break; | |
1a4d82fc JJ |
930 | case Triple::systemz: |
931 | resolveSystemZRelocation(Section, Offset, Value, Type, Addend); | |
932 | break; | |
933 | default: | |
934 | llvm_unreachable("Unsupported CPU type!"); | |
223e47cc LB |
935 | } |
936 | } | |
937 | ||
1a4d82fc JJ |
938 | relocation_iterator RuntimeDyldELF::processRelocationRef( |
939 | unsigned SectionID, relocation_iterator RelI, ObjectImage &Obj, | |
940 | ObjSectionToIDMap &ObjSectionToID, const SymbolTableMap &Symbols, | |
941 | StubMap &Stubs) { | |
942 | uint64_t RelType; | |
943 | Check(RelI->getType(RelType)); | |
944 | int64_t Addend; | |
945 | Check(getELFRelocationAddend(*RelI, Addend)); | |
946 | symbol_iterator Symbol = RelI->getSymbol(); | |
223e47cc LB |
947 | |
948 | // Obtain the symbol name which is referenced in the relocation | |
949 | StringRef TargetName; | |
1a4d82fc JJ |
950 | if (Symbol != Obj.end_symbols()) |
951 | Symbol->getName(TargetName); | |
952 | DEBUG(dbgs() << "\t\tRelType: " << RelType << " Addend: " << Addend | |
953 | << " TargetName: " << TargetName << "\n"); | |
223e47cc LB |
954 | RelocationValueRef Value; |
955 | // First search for the symbol in the local symbol table | |
1a4d82fc JJ |
956 | SymbolTableMap::const_iterator lsi = Symbols.end(); |
957 | SymbolRef::Type SymType = SymbolRef::ST_Unknown; | |
958 | if (Symbol != Obj.end_symbols()) { | |
959 | lsi = Symbols.find(TargetName.data()); | |
960 | Symbol->getType(SymType); | |
961 | } | |
223e47cc LB |
962 | if (lsi != Symbols.end()) { |
963 | Value.SectionID = lsi->second.first; | |
1a4d82fc JJ |
964 | Value.Offset = lsi->second.second; |
965 | Value.Addend = lsi->second.second + Addend; | |
223e47cc LB |
966 | } else { |
967 | // Search for the symbol in the global symbol table | |
1a4d82fc JJ |
968 | SymbolTableMap::const_iterator gsi = GlobalSymbolTable.end(); |
969 | if (Symbol != Obj.end_symbols()) | |
970 | gsi = GlobalSymbolTable.find(TargetName.data()); | |
223e47cc LB |
971 | if (gsi != GlobalSymbolTable.end()) { |
972 | Value.SectionID = gsi->second.first; | |
1a4d82fc JJ |
973 | Value.Offset = gsi->second.second; |
974 | Value.Addend = gsi->second.second + Addend; | |
223e47cc | 975 | } else { |
223e47cc | 976 | switch (SymType) { |
1a4d82fc JJ |
977 | case SymbolRef::ST_Debug: { |
978 | // TODO: Now ELF SymbolRef::ST_Debug = STT_SECTION, it's not obviously | |
979 | // and can be changed by another developers. Maybe best way is add | |
980 | // a new symbol type ST_Section to SymbolRef and use it. | |
981 | section_iterator si(Obj.end_sections()); | |
982 | Symbol->getSection(si); | |
983 | if (si == Obj.end_sections()) | |
984 | llvm_unreachable("Symbol section not found, bad object file format!"); | |
985 | DEBUG(dbgs() << "\t\tThis is section symbol\n"); | |
986 | // Default to 'true' in case isText fails (though it never does). | |
987 | bool isCode = true; | |
988 | si->isText(isCode); | |
989 | Value.SectionID = findOrEmitSection(Obj, (*si), isCode, ObjSectionToID); | |
990 | Value.Addend = Addend; | |
991 | break; | |
992 | } | |
993 | case SymbolRef::ST_Data: | |
994 | case SymbolRef::ST_Unknown: { | |
995 | Value.SymbolName = TargetName.data(); | |
996 | Value.Addend = Addend; | |
997 | ||
998 | // Absolute relocations will have a zero symbol ID (STN_UNDEF), which | |
999 | // will manifest here as a NULL symbol name. | |
1000 | // We can set this as a valid (but empty) symbol name, and rely | |
1001 | // on addRelocationForSymbol to handle this. | |
1002 | if (!Value.SymbolName) | |
1003 | Value.SymbolName = ""; | |
1004 | break; | |
1005 | } | |
1006 | default: | |
1007 | llvm_unreachable("Unresolved symbol type!"); | |
1008 | break; | |
223e47cc LB |
1009 | } |
1010 | } | |
1011 | } | |
1a4d82fc JJ |
1012 | uint64_t Offset; |
1013 | Check(RelI->getOffset(Offset)); | |
1014 | ||
1015 | DEBUG(dbgs() << "\t\tSectionID: " << SectionID << " Offset: " << Offset | |
223e47cc | 1016 | << "\n"); |
1a4d82fc JJ |
1017 | if ((Arch == Triple::aarch64 || Arch == Triple::aarch64_be) && |
1018 | (RelType == ELF::R_AARCH64_CALL26 || RelType == ELF::R_AARCH64_JUMP26)) { | |
1019 | // This is an AArch64 branch relocation, need to use a stub function. | |
1020 | DEBUG(dbgs() << "\t\tThis is an AArch64 branch relocation."); | |
1021 | SectionEntry &Section = Sections[SectionID]; | |
1022 | ||
1023 | // Look for an existing stub. | |
1024 | StubMap::const_iterator i = Stubs.find(Value); | |
1025 | if (i != Stubs.end()) { | |
1026 | resolveRelocation(Section, Offset, (uint64_t)Section.Address + i->second, | |
1027 | RelType, 0); | |
1028 | DEBUG(dbgs() << " Stub function found\n"); | |
1029 | } else { | |
1030 | // Create a new stub function. | |
1031 | DEBUG(dbgs() << " Create a new stub function\n"); | |
1032 | Stubs[Value] = Section.StubOffset; | |
1033 | uint8_t *StubTargetAddr = | |
1034 | createStubFunction(Section.Address + Section.StubOffset); | |
1035 | ||
1036 | RelocationEntry REmovz_g3(SectionID, StubTargetAddr - Section.Address, | |
1037 | ELF::R_AARCH64_MOVW_UABS_G3, Value.Addend); | |
1038 | RelocationEntry REmovk_g2(SectionID, StubTargetAddr - Section.Address + 4, | |
1039 | ELF::R_AARCH64_MOVW_UABS_G2_NC, Value.Addend); | |
1040 | RelocationEntry REmovk_g1(SectionID, StubTargetAddr - Section.Address + 8, | |
1041 | ELF::R_AARCH64_MOVW_UABS_G1_NC, Value.Addend); | |
1042 | RelocationEntry REmovk_g0(SectionID, | |
1043 | StubTargetAddr - Section.Address + 12, | |
1044 | ELF::R_AARCH64_MOVW_UABS_G0_NC, Value.Addend); | |
1045 | ||
1046 | if (Value.SymbolName) { | |
1047 | addRelocationForSymbol(REmovz_g3, Value.SymbolName); | |
1048 | addRelocationForSymbol(REmovk_g2, Value.SymbolName); | |
1049 | addRelocationForSymbol(REmovk_g1, Value.SymbolName); | |
1050 | addRelocationForSymbol(REmovk_g0, Value.SymbolName); | |
1051 | } else { | |
1052 | addRelocationForSection(REmovz_g3, Value.SectionID); | |
1053 | addRelocationForSection(REmovk_g2, Value.SectionID); | |
1054 | addRelocationForSection(REmovk_g1, Value.SectionID); | |
1055 | addRelocationForSection(REmovk_g0, Value.SectionID); | |
1056 | } | |
1057 | resolveRelocation(Section, Offset, | |
1058 | (uint64_t)Section.Address + Section.StubOffset, RelType, | |
1059 | 0); | |
1060 | Section.StubOffset += getMaxStubSize(); | |
1061 | } | |
1062 | } else if (Arch == Triple::arm && | |
1063 | (RelType == ELF::R_ARM_PC24 || RelType == ELF::R_ARM_CALL || | |
1064 | RelType == ELF::R_ARM_JUMP24)) { | |
223e47cc LB |
1065 | // This is an ARM branch relocation, need to use a stub function. |
1066 | DEBUG(dbgs() << "\t\tThis is an ARM branch relocation."); | |
1a4d82fc | 1067 | SectionEntry &Section = Sections[SectionID]; |
223e47cc | 1068 | |
970d7e83 | 1069 | // Look for an existing stub. |
223e47cc LB |
1070 | StubMap::const_iterator i = Stubs.find(Value); |
1071 | if (i != Stubs.end()) { | |
1a4d82fc JJ |
1072 | resolveRelocation(Section, Offset, (uint64_t)Section.Address + i->second, |
1073 | RelType, 0); | |
223e47cc LB |
1074 | DEBUG(dbgs() << " Stub function found\n"); |
1075 | } else { | |
1076 | // Create a new stub function. | |
1077 | DEBUG(dbgs() << " Create a new stub function\n"); | |
1078 | Stubs[Value] = Section.StubOffset; | |
1a4d82fc JJ |
1079 | uint8_t *StubTargetAddr = |
1080 | createStubFunction(Section.Address + Section.StubOffset); | |
1081 | RelocationEntry RE(SectionID, StubTargetAddr - Section.Address, | |
1082 | ELF::R_ARM_PRIVATE_0, Value.Addend); | |
223e47cc LB |
1083 | if (Value.SymbolName) |
1084 | addRelocationForSymbol(RE, Value.SymbolName); | |
1085 | else | |
1086 | addRelocationForSection(RE, Value.SectionID); | |
1087 | ||
1a4d82fc JJ |
1088 | resolveRelocation(Section, Offset, |
1089 | (uint64_t)Section.Address + Section.StubOffset, RelType, | |
1090 | 0); | |
223e47cc LB |
1091 | Section.StubOffset += getMaxStubSize(); |
1092 | } | |
970d7e83 LB |
1093 | } else if ((Arch == Triple::mipsel || Arch == Triple::mips) && |
1094 | RelType == ELF::R_MIPS_26) { | |
223e47cc LB |
1095 | // This is an Mips branch relocation, need to use a stub function. |
1096 | DEBUG(dbgs() << "\t\tThis is a Mips branch relocation."); | |
1a4d82fc JJ |
1097 | SectionEntry &Section = Sections[SectionID]; |
1098 | uint8_t *Target = Section.Address + Offset; | |
223e47cc LB |
1099 | uint32_t *TargetAddress = (uint32_t *)Target; |
1100 | ||
1101 | // Extract the addend from the instruction. | |
1102 | uint32_t Addend = ((*TargetAddress) & 0x03ffffff) << 2; | |
1103 | ||
1104 | Value.Addend += Addend; | |
1105 | ||
1106 | // Look up for existing stub. | |
1107 | StubMap::const_iterator i = Stubs.find(Value); | |
1108 | if (i != Stubs.end()) { | |
1a4d82fc JJ |
1109 | RelocationEntry RE(SectionID, Offset, RelType, i->second); |
1110 | addRelocationForSection(RE, SectionID); | |
223e47cc LB |
1111 | DEBUG(dbgs() << " Stub function found\n"); |
1112 | } else { | |
1113 | // Create a new stub function. | |
1114 | DEBUG(dbgs() << " Create a new stub function\n"); | |
1115 | Stubs[Value] = Section.StubOffset; | |
1a4d82fc JJ |
1116 | uint8_t *StubTargetAddr = |
1117 | createStubFunction(Section.Address + Section.StubOffset); | |
223e47cc LB |
1118 | |
1119 | // Creating Hi and Lo relocations for the filled stub instructions. | |
1a4d82fc JJ |
1120 | RelocationEntry REHi(SectionID, StubTargetAddr - Section.Address, |
1121 | ELF::R_MIPS_UNUSED1, Value.Addend); | |
1122 | RelocationEntry RELo(SectionID, StubTargetAddr - Section.Address + 4, | |
1123 | ELF::R_MIPS_UNUSED2, Value.Addend); | |
223e47cc LB |
1124 | |
1125 | if (Value.SymbolName) { | |
1126 | addRelocationForSymbol(REHi, Value.SymbolName); | |
1127 | addRelocationForSymbol(RELo, Value.SymbolName); | |
1128 | } else { | |
1129 | addRelocationForSection(REHi, Value.SectionID); | |
1130 | addRelocationForSection(RELo, Value.SectionID); | |
1131 | } | |
1132 | ||
1a4d82fc JJ |
1133 | RelocationEntry RE(SectionID, Offset, RelType, Section.StubOffset); |
1134 | addRelocationForSection(RE, SectionID); | |
223e47cc LB |
1135 | Section.StubOffset += getMaxStubSize(); |
1136 | } | |
1a4d82fc | 1137 | } else if (Arch == Triple::ppc64 || Arch == Triple::ppc64le) { |
970d7e83 | 1138 | if (RelType == ELF::R_PPC64_REL24) { |
1a4d82fc JJ |
1139 | // Determine ABI variant in use for this object. |
1140 | unsigned AbiVariant; | |
1141 | Obj.getObjectFile()->getPlatformFlags(AbiVariant); | |
1142 | AbiVariant &= ELF::EF_PPC64_ABI; | |
970d7e83 LB |
1143 | // A PPC branch relocation will need a stub function if the target is |
1144 | // an external symbol (Symbol::ST_Unknown) or if the target address | |
1145 | // is not within the signed 24-bits branch address. | |
1a4d82fc JJ |
1146 | SectionEntry &Section = Sections[SectionID]; |
1147 | uint8_t *Target = Section.Address + Offset; | |
970d7e83 LB |
1148 | bool RangeOverflow = false; |
1149 | if (SymType != SymbolRef::ST_Unknown) { | |
1a4d82fc JJ |
1150 | if (AbiVariant != 2) { |
1151 | // In the ELFv1 ABI, a function call may point to the .opd entry, | |
1152 | // so the final symbol value is calculated based on the relocation | |
1153 | // values in the .opd section. | |
1154 | findOPDEntrySection(Obj, ObjSectionToID, Value); | |
1155 | } else { | |
1156 | // In the ELFv2 ABI, a function symbol may provide a local entry | |
1157 | // point, which must be used for direct calls. | |
1158 | uint8_t SymOther; | |
1159 | Symbol->getOther(SymOther); | |
1160 | Value.Addend += ELF::decodePPC64LocalEntryOffset(SymOther); | |
1161 | } | |
970d7e83 LB |
1162 | uint8_t *RelocTarget = Sections[Value.SectionID].Address + Value.Addend; |
1163 | int32_t delta = static_cast<int32_t>(Target - RelocTarget); | |
1164 | // If it is within 24-bits branch range, just set the branch target | |
1165 | if (SignExtend32<24>(delta) == delta) { | |
1a4d82fc | 1166 | RelocationEntry RE(SectionID, Offset, RelType, Value.Addend); |
970d7e83 LB |
1167 | if (Value.SymbolName) |
1168 | addRelocationForSymbol(RE, Value.SymbolName); | |
1169 | else | |
1170 | addRelocationForSection(RE, Value.SectionID); | |
1171 | } else { | |
1172 | RangeOverflow = true; | |
1173 | } | |
1174 | } | |
1175 | if (SymType == SymbolRef::ST_Unknown || RangeOverflow == true) { | |
1176 | // It is an external symbol (SymbolRef::ST_Unknown) or within a range | |
1177 | // larger than 24-bits. | |
1178 | StubMap::const_iterator i = Stubs.find(Value); | |
1179 | if (i != Stubs.end()) { | |
1180 | // Symbol function stub already created, just relocate to it | |
1a4d82fc | 1181 | resolveRelocation(Section, Offset, |
970d7e83 LB |
1182 | (uint64_t)Section.Address + i->second, RelType, 0); |
1183 | DEBUG(dbgs() << " Stub function found\n"); | |
1184 | } else { | |
1185 | // Create a new stub function. | |
1186 | DEBUG(dbgs() << " Create a new stub function\n"); | |
1187 | Stubs[Value] = Section.StubOffset; | |
1a4d82fc JJ |
1188 | uint8_t *StubTargetAddr = |
1189 | createStubFunction(Section.Address + Section.StubOffset, | |
1190 | AbiVariant); | |
1191 | RelocationEntry RE(SectionID, StubTargetAddr - Section.Address, | |
970d7e83 LB |
1192 | ELF::R_PPC64_ADDR64, Value.Addend); |
1193 | ||
1194 | // Generates the 64-bits address loads as exemplified in section | |
1a4d82fc JJ |
1195 | // 4.5.1 in PPC64 ELF ABI. Note that the relocations need to |
1196 | // apply to the low part of the instructions, so we have to update | |
1197 | // the offset according to the target endianness. | |
1198 | uint64_t StubRelocOffset = StubTargetAddr - Section.Address; | |
1199 | if (!IsTargetLittleEndian) | |
1200 | StubRelocOffset += 2; | |
1201 | ||
1202 | RelocationEntry REhst(SectionID, StubRelocOffset + 0, | |
970d7e83 | 1203 | ELF::R_PPC64_ADDR16_HIGHEST, Value.Addend); |
1a4d82fc | 1204 | RelocationEntry REhr(SectionID, StubRelocOffset + 4, |
970d7e83 | 1205 | ELF::R_PPC64_ADDR16_HIGHER, Value.Addend); |
1a4d82fc | 1206 | RelocationEntry REh(SectionID, StubRelocOffset + 12, |
970d7e83 | 1207 | ELF::R_PPC64_ADDR16_HI, Value.Addend); |
1a4d82fc | 1208 | RelocationEntry REl(SectionID, StubRelocOffset + 16, |
970d7e83 LB |
1209 | ELF::R_PPC64_ADDR16_LO, Value.Addend); |
1210 | ||
1211 | if (Value.SymbolName) { | |
1212 | addRelocationForSymbol(REhst, Value.SymbolName); | |
1a4d82fc JJ |
1213 | addRelocationForSymbol(REhr, Value.SymbolName); |
1214 | addRelocationForSymbol(REh, Value.SymbolName); | |
1215 | addRelocationForSymbol(REl, Value.SymbolName); | |
970d7e83 LB |
1216 | } else { |
1217 | addRelocationForSection(REhst, Value.SectionID); | |
1a4d82fc JJ |
1218 | addRelocationForSection(REhr, Value.SectionID); |
1219 | addRelocationForSection(REh, Value.SectionID); | |
1220 | addRelocationForSection(REl, Value.SectionID); | |
970d7e83 LB |
1221 | } |
1222 | ||
1a4d82fc | 1223 | resolveRelocation(Section, Offset, |
970d7e83 LB |
1224 | (uint64_t)Section.Address + Section.StubOffset, |
1225 | RelType, 0); | |
970d7e83 LB |
1226 | Section.StubOffset += getMaxStubSize(); |
1227 | } | |
1a4d82fc JJ |
1228 | if (SymType == SymbolRef::ST_Unknown) { |
1229 | // Restore the TOC for external calls | |
1230 | if (AbiVariant == 2) | |
1231 | writeInt32BE(Target + 4, 0xE8410018); // ld r2,28(r1) | |
1232 | else | |
1233 | writeInt32BE(Target + 4, 0xE8410028); // ld r2,40(r1) | |
1234 | } | |
1235 | } | |
1236 | } else if (RelType == ELF::R_PPC64_TOC16 || | |
1237 | RelType == ELF::R_PPC64_TOC16_DS || | |
1238 | RelType == ELF::R_PPC64_TOC16_LO || | |
1239 | RelType == ELF::R_PPC64_TOC16_LO_DS || | |
1240 | RelType == ELF::R_PPC64_TOC16_HI || | |
1241 | RelType == ELF::R_PPC64_TOC16_HA) { | |
1242 | // These relocations are supposed to subtract the TOC address from | |
1243 | // the final value. This does not fit cleanly into the RuntimeDyld | |
1244 | // scheme, since there may be *two* sections involved in determining | |
1245 | // the relocation value (the section of the symbol refered to by the | |
1246 | // relocation, and the TOC section associated with the current module). | |
1247 | // | |
1248 | // Fortunately, these relocations are currently only ever generated | |
1249 | // refering to symbols that themselves reside in the TOC, which means | |
1250 | // that the two sections are actually the same. Thus they cancel out | |
1251 | // and we can immediately resolve the relocation right now. | |
1252 | switch (RelType) { | |
1253 | case ELF::R_PPC64_TOC16: RelType = ELF::R_PPC64_ADDR16; break; | |
1254 | case ELF::R_PPC64_TOC16_DS: RelType = ELF::R_PPC64_ADDR16_DS; break; | |
1255 | case ELF::R_PPC64_TOC16_LO: RelType = ELF::R_PPC64_ADDR16_LO; break; | |
1256 | case ELF::R_PPC64_TOC16_LO_DS: RelType = ELF::R_PPC64_ADDR16_LO_DS; break; | |
1257 | case ELF::R_PPC64_TOC16_HI: RelType = ELF::R_PPC64_ADDR16_HI; break; | |
1258 | case ELF::R_PPC64_TOC16_HA: RelType = ELF::R_PPC64_ADDR16_HA; break; | |
1259 | default: llvm_unreachable("Wrong relocation type."); | |
1260 | } | |
1261 | ||
1262 | RelocationValueRef TOCValue; | |
1263 | findPPC64TOCSection(Obj, ObjSectionToID, TOCValue); | |
1264 | if (Value.SymbolName || Value.SectionID != TOCValue.SectionID) | |
1265 | llvm_unreachable("Unsupported TOC relocation."); | |
1266 | Value.Addend -= TOCValue.Addend; | |
1267 | resolveRelocation(Sections[SectionID], Offset, Value.Addend, RelType, 0); | |
1268 | } else { | |
1269 | // There are two ways to refer to the TOC address directly: either | |
1270 | // via a ELF::R_PPC64_TOC relocation (where both symbol and addend are | |
1271 | // ignored), or via any relocation that refers to the magic ".TOC." | |
1272 | // symbols (in which case the addend is respected). | |
1273 | if (RelType == ELF::R_PPC64_TOC) { | |
1274 | RelType = ELF::R_PPC64_ADDR64; | |
1275 | findPPC64TOCSection(Obj, ObjSectionToID, Value); | |
1276 | } else if (TargetName == ".TOC.") { | |
1277 | findPPC64TOCSection(Obj, ObjSectionToID, Value); | |
1278 | Value.Addend += Addend; | |
970d7e83 | 1279 | } |
1a4d82fc JJ |
1280 | |
1281 | RelocationEntry RE(SectionID, Offset, RelType, Value.Addend); | |
1282 | ||
1283 | if (Value.SymbolName) | |
1284 | addRelocationForSymbol(RE, Value.SymbolName); | |
1285 | else | |
1286 | addRelocationForSection(RE, Value.SectionID); | |
1287 | } | |
1288 | } else if (Arch == Triple::systemz && | |
1289 | (RelType == ELF::R_390_PLT32DBL || RelType == ELF::R_390_GOTENT)) { | |
1290 | // Create function stubs for both PLT and GOT references, regardless of | |
1291 | // whether the GOT reference is to data or code. The stub contains the | |
1292 | // full address of the symbol, as needed by GOT references, and the | |
1293 | // executable part only adds an overhead of 8 bytes. | |
1294 | // | |
1295 | // We could try to conserve space by allocating the code and data | |
1296 | // parts of the stub separately. However, as things stand, we allocate | |
1297 | // a stub for every relocation, so using a GOT in JIT code should be | |
1298 | // no less space efficient than using an explicit constant pool. | |
1299 | DEBUG(dbgs() << "\t\tThis is a SystemZ indirect relocation."); | |
1300 | SectionEntry &Section = Sections[SectionID]; | |
1301 | ||
1302 | // Look for an existing stub. | |
1303 | StubMap::const_iterator i = Stubs.find(Value); | |
1304 | uintptr_t StubAddress; | |
1305 | if (i != Stubs.end()) { | |
1306 | StubAddress = uintptr_t(Section.Address) + i->second; | |
1307 | DEBUG(dbgs() << " Stub function found\n"); | |
970d7e83 | 1308 | } else { |
1a4d82fc JJ |
1309 | // Create a new stub function. |
1310 | DEBUG(dbgs() << " Create a new stub function\n"); | |
1311 | ||
1312 | uintptr_t BaseAddress = uintptr_t(Section.Address); | |
1313 | uintptr_t StubAlignment = getStubAlignment(); | |
1314 | StubAddress = (BaseAddress + Section.StubOffset + StubAlignment - 1) & | |
1315 | -StubAlignment; | |
1316 | unsigned StubOffset = StubAddress - BaseAddress; | |
1317 | ||
1318 | Stubs[Value] = StubOffset; | |
1319 | createStubFunction((uint8_t *)StubAddress); | |
1320 | RelocationEntry RE(SectionID, StubOffset + 8, ELF::R_390_64, | |
1321 | Value.Offset); | |
1322 | if (Value.SymbolName) | |
970d7e83 LB |
1323 | addRelocationForSymbol(RE, Value.SymbolName); |
1324 | else | |
1325 | addRelocationForSection(RE, Value.SectionID); | |
1a4d82fc JJ |
1326 | Section.StubOffset = StubOffset + getMaxStubSize(); |
1327 | } | |
1328 | ||
1329 | if (RelType == ELF::R_390_GOTENT) | |
1330 | resolveRelocation(Section, Offset, StubAddress + 8, ELF::R_390_PC32DBL, | |
1331 | Addend); | |
1332 | else | |
1333 | resolveRelocation(Section, Offset, StubAddress, RelType, Addend); | |
1334 | } else if (Arch == Triple::x86_64 && RelType == ELF::R_X86_64_PLT32) { | |
1335 | // The way the PLT relocations normally work is that the linker allocates | |
1336 | // the | |
1337 | // PLT and this relocation makes a PC-relative call into the PLT. The PLT | |
1338 | // entry will then jump to an address provided by the GOT. On first call, | |
1339 | // the | |
1340 | // GOT address will point back into PLT code that resolves the symbol. After | |
1341 | // the first call, the GOT entry points to the actual function. | |
1342 | // | |
1343 | // For local functions we're ignoring all of that here and just replacing | |
1344 | // the PLT32 relocation type with PC32, which will translate the relocation | |
1345 | // into a PC-relative call directly to the function. For external symbols we | |
1346 | // can't be sure the function will be within 2^32 bytes of the call site, so | |
1347 | // we need to create a stub, which calls into the GOT. This case is | |
1348 | // equivalent to the usual PLT implementation except that we use the stub | |
1349 | // mechanism in RuntimeDyld (which puts stubs at the end of the section) | |
1350 | // rather than allocating a PLT section. | |
1351 | if (Value.SymbolName) { | |
1352 | // This is a call to an external function. | |
1353 | // Look for an existing stub. | |
1354 | SectionEntry &Section = Sections[SectionID]; | |
1355 | StubMap::const_iterator i = Stubs.find(Value); | |
1356 | uintptr_t StubAddress; | |
1357 | if (i != Stubs.end()) { | |
1358 | StubAddress = uintptr_t(Section.Address) + i->second; | |
1359 | DEBUG(dbgs() << " Stub function found\n"); | |
1360 | } else { | |
1361 | // Create a new stub function (equivalent to a PLT entry). | |
1362 | DEBUG(dbgs() << " Create a new stub function\n"); | |
1363 | ||
1364 | uintptr_t BaseAddress = uintptr_t(Section.Address); | |
1365 | uintptr_t StubAlignment = getStubAlignment(); | |
1366 | StubAddress = (BaseAddress + Section.StubOffset + StubAlignment - 1) & | |
1367 | -StubAlignment; | |
1368 | unsigned StubOffset = StubAddress - BaseAddress; | |
1369 | Stubs[Value] = StubOffset; | |
1370 | createStubFunction((uint8_t *)StubAddress); | |
1371 | ||
1372 | // Create a GOT entry for the external function. | |
1373 | GOTEntries.push_back(Value); | |
1374 | ||
1375 | // Make our stub function a relative call to the GOT entry. | |
1376 | RelocationEntry RE(SectionID, StubOffset + 2, ELF::R_X86_64_GOTPCREL, | |
1377 | -4); | |
1378 | addRelocationForSymbol(RE, Value.SymbolName); | |
1379 | ||
1380 | // Bump our stub offset counter | |
1381 | Section.StubOffset = StubOffset + getMaxStubSize(); | |
1382 | } | |
1383 | ||
1384 | // Make the target call a call into the stub table. | |
1385 | resolveRelocation(Section, Offset, StubAddress, ELF::R_X86_64_PC32, | |
1386 | Addend); | |
1387 | } else { | |
1388 | RelocationEntry RE(SectionID, Offset, ELF::R_X86_64_PC32, Value.Addend, | |
1389 | Value.Offset); | |
1390 | addRelocationForSection(RE, Value.SectionID); | |
970d7e83 | 1391 | } |
223e47cc | 1392 | } else { |
1a4d82fc JJ |
1393 | if (Arch == Triple::x86_64 && RelType == ELF::R_X86_64_GOTPCREL) { |
1394 | GOTEntries.push_back(Value); | |
1395 | } | |
1396 | RelocationEntry RE(SectionID, Offset, RelType, Value.Addend, Value.Offset); | |
223e47cc LB |
1397 | if (Value.SymbolName) |
1398 | addRelocationForSymbol(RE, Value.SymbolName); | |
1399 | else | |
1400 | addRelocationForSection(RE, Value.SectionID); | |
1401 | } | |
1a4d82fc | 1402 | return ++RelI; |
223e47cc LB |
1403 | } |
1404 | ||
1a4d82fc JJ |
1405 | void RuntimeDyldELF::updateGOTEntries(StringRef Name, uint64_t Addr) { |
1406 | ||
1407 | SmallVectorImpl<std::pair<SID, GOTRelocations>>::iterator it; | |
1408 | SmallVectorImpl<std::pair<SID, GOTRelocations>>::iterator end = GOTs.end(); | |
1409 | ||
1410 | for (it = GOTs.begin(); it != end; ++it) { | |
1411 | GOTRelocations &GOTEntries = it->second; | |
1412 | for (int i = 0, e = GOTEntries.size(); i != e; ++i) { | |
1413 | if (GOTEntries[i].SymbolName != nullptr && | |
1414 | GOTEntries[i].SymbolName == Name) { | |
1415 | GOTEntries[i].Offset = Addr; | |
1416 | } | |
1417 | } | |
1418 | } | |
1419 | } | |
1420 | ||
1421 | size_t RuntimeDyldELF::getGOTEntrySize() { | |
1422 | // We don't use the GOT in all of these cases, but it's essentially free | |
1423 | // to put them all here. | |
1424 | size_t Result = 0; | |
1425 | switch (Arch) { | |
1426 | case Triple::x86_64: | |
1427 | case Triple::aarch64: | |
1428 | case Triple::aarch64_be: | |
1429 | case Triple::ppc64: | |
1430 | case Triple::ppc64le: | |
1431 | case Triple::systemz: | |
1432 | Result = sizeof(uint64_t); | |
1433 | break; | |
1434 | case Triple::x86: | |
1435 | case Triple::arm: | |
1436 | case Triple::thumb: | |
1437 | case Triple::mips: | |
1438 | case Triple::mipsel: | |
1439 | Result = sizeof(uint32_t); | |
1440 | break; | |
1441 | default: | |
1442 | llvm_unreachable("Unsupported CPU type!"); | |
1443 | } | |
1444 | return Result; | |
1445 | } | |
1446 | ||
1447 | uint64_t RuntimeDyldELF::findGOTEntry(uint64_t LoadAddress, uint64_t Offset) { | |
1448 | ||
1449 | const size_t GOTEntrySize = getGOTEntrySize(); | |
1450 | ||
1451 | SmallVectorImpl<std::pair<SID, GOTRelocations>>::const_iterator it; | |
1452 | SmallVectorImpl<std::pair<SID, GOTRelocations>>::const_iterator end = | |
1453 | GOTs.end(); | |
1454 | ||
1455 | int GOTIndex = -1; | |
1456 | for (it = GOTs.begin(); it != end; ++it) { | |
1457 | SID GOTSectionID = it->first; | |
1458 | const GOTRelocations &GOTEntries = it->second; | |
1459 | ||
1460 | // Find the matching entry in our vector. | |
1461 | uint64_t SymbolOffset = 0; | |
1462 | for (int i = 0, e = GOTEntries.size(); i != e; ++i) { | |
1463 | if (!GOTEntries[i].SymbolName) { | |
1464 | if (getSectionLoadAddress(GOTEntries[i].SectionID) == LoadAddress && | |
1465 | GOTEntries[i].Offset == Offset) { | |
1466 | GOTIndex = i; | |
1467 | SymbolOffset = GOTEntries[i].Offset; | |
1468 | break; | |
1469 | } | |
1470 | } else { | |
1471 | // GOT entries for external symbols use the addend as the address when | |
1472 | // the external symbol has been resolved. | |
1473 | if (GOTEntries[i].Offset == LoadAddress) { | |
1474 | GOTIndex = i; | |
1475 | // Don't use the Addend here. The relocation handler will use it. | |
1476 | break; | |
1477 | } | |
1478 | } | |
1479 | } | |
1480 | ||
1481 | if (GOTIndex != -1) { | |
1482 | if (GOTEntrySize == sizeof(uint64_t)) { | |
1483 | uint64_t *LocalGOTAddr = (uint64_t *)getSectionAddress(GOTSectionID); | |
1484 | // Fill in this entry with the address of the symbol being referenced. | |
1485 | LocalGOTAddr[GOTIndex] = LoadAddress + SymbolOffset; | |
1486 | } else { | |
1487 | uint32_t *LocalGOTAddr = (uint32_t *)getSectionAddress(GOTSectionID); | |
1488 | // Fill in this entry with the address of the symbol being referenced. | |
1489 | LocalGOTAddr[GOTIndex] = (uint32_t)(LoadAddress + SymbolOffset); | |
1490 | } | |
1491 | ||
1492 | // Calculate the load address of this entry | |
1493 | return getSectionLoadAddress(GOTSectionID) + (GOTIndex * GOTEntrySize); | |
1494 | } | |
1495 | } | |
1496 | ||
1497 | assert(GOTIndex != -1 && "Unable to find requested GOT entry."); | |
1498 | return 0; | |
1499 | } | |
1500 | ||
1501 | void RuntimeDyldELF::finalizeLoad(ObjectImage &ObjImg, | |
1502 | ObjSectionToIDMap &SectionMap) { | |
1503 | // If necessary, allocate the global offset table | |
1504 | if (MemMgr) { | |
1505 | // Allocate the GOT if necessary | |
1506 | size_t numGOTEntries = GOTEntries.size(); | |
1507 | if (numGOTEntries != 0) { | |
1508 | // Allocate memory for the section | |
1509 | unsigned SectionID = Sections.size(); | |
1510 | size_t TotalSize = numGOTEntries * getGOTEntrySize(); | |
1511 | uint8_t *Addr = MemMgr->allocateDataSection(TotalSize, getGOTEntrySize(), | |
1512 | SectionID, ".got", false); | |
1513 | if (!Addr) | |
1514 | report_fatal_error("Unable to allocate memory for GOT!"); | |
1515 | ||
1516 | GOTs.push_back(std::make_pair(SectionID, GOTEntries)); | |
1517 | Sections.push_back(SectionEntry(".got", Addr, TotalSize, 0)); | |
1518 | // For now, initialize all GOT entries to zero. We'll fill them in as | |
1519 | // needed when GOT-based relocations are applied. | |
1520 | memset(Addr, 0, TotalSize); | |
1521 | } | |
1522 | } else { | |
1523 | report_fatal_error("Unable to allocate memory for GOT!"); | |
1524 | } | |
1525 | ||
1526 | // Look for and record the EH frame section. | |
1527 | ObjSectionToIDMap::iterator i, e; | |
1528 | for (i = SectionMap.begin(), e = SectionMap.end(); i != e; ++i) { | |
1529 | const SectionRef &Section = i->first; | |
1530 | StringRef Name; | |
1531 | Section.getName(Name); | |
1532 | if (Name == ".eh_frame") { | |
1533 | UnregisteredEHFrameSections.push_back(i->second); | |
1534 | break; | |
1535 | } | |
1536 | } | |
970d7e83 LB |
1537 | } |
1538 | ||
1539 | bool RuntimeDyldELF::isCompatibleFormat(const ObjectBuffer *Buffer) const { | |
1540 | if (Buffer->getBufferSize() < strlen(ELF::ElfMagic)) | |
1541 | return false; | |
1a4d82fc JJ |
1542 | return (memcmp(Buffer->getBufferStart(), ELF::ElfMagic, |
1543 | strlen(ELF::ElfMagic))) == 0; | |
1544 | } | |
1545 | ||
1546 | bool RuntimeDyldELF::isCompatibleFile(const object::ObjectFile *Obj) const { | |
1547 | return Obj->isELF(); | |
223e47cc | 1548 | } |
1a4d82fc | 1549 | |
223e47cc | 1550 | } // namespace llvm |