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