llvm.org GIT mirror llvm / 34ea0a1
Fix unaligned reads/writes in X86JIT and RuntimeDyldELF. Summary: Introduce support::ulittleX_t::ref type to Support/Endian.h and use it in x86 JIT to enforce correct endianness and fix unaligned accesses. Test Plan: regression test suite Reviewers: lhames Subscribers: ributzka, llvm-commits Differential Revision: http://reviews.llvm.org/D5011 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@216631 91177308-0d34-0410-b5e6-96231b3b80d8 Alexey Samsonov 5 years ago
3 changed file(s) with 83 addition(s) and 54 deletion(s). Raw diff Collapse all Expand all
9595 private:
9696 AlignedCharArray::value,
9797 sizeof(value_type)> Value;
98
99 public:
100 struct ref {
101 explicit ref(void *Ptr) : Ptr(Ptr) {}
102
103 operator value_type() const {
104 return endian::read(Ptr);
105 }
106
107 void operator=(value_type NewValue) {
108 endian::write(Ptr, NewValue);
109 }
110
111 private:
112 void *Ptr;
113 };
98114 };
115
99116 } // end namespace detail
100117
101118 typedef detail::packed_endian_specific_integral
2222 #include "llvm/Object/ELFObjectFile.h"
2323 #include "llvm/Object/ObjectFile.h"
2424 #include "llvm/Support/ELF.h"
25 #include "llvm/Support/Endian.h"
2526 #include "llvm/Support/MemoryBuffer.h"
2627
2728 using namespace llvm;
259260 llvm_unreachable("Relocation type not implemented yet!");
260261 break;
261262 case ELF::R_X86_64_64: {
262 uint64_t *Target = reinterpret_cast(Section.Address + Offset);
263 *Target = Value + Addend;
263 support::ulittle64_t::ref(Section.Address + Offset) = Value + Addend;
264264 DEBUG(dbgs() << "Writing " << format("%p", (Value + Addend)) << " at "
265 << format("%p\n", Target));
265 << format("%p\n", Section.Address + Offset));
266266 break;
267267 }
268268 case ELF::R_X86_64_32:
272272 (Type == ELF::R_X86_64_32S &&
273273 ((int64_t)Value <= INT32_MAX && (int64_t)Value >= INT32_MIN)));
274274 uint32_t TruncatedAddr = (Value & 0xFFFFFFFF);
275 uint32_t *Target = reinterpret_cast(Section.Address + Offset);
276 *Target = TruncatedAddr;
275 support::ulittle32_t::ref(Section.Address + Offset) = TruncatedAddr;
277276 DEBUG(dbgs() << "Writing " << format("%p", TruncatedAddr) << " at "
278 << format("%p\n", Target));
277 << format("%p\n", Section.Address + Offset));
279278 break;
280279 }
281280 case ELF::R_X86_64_GOTPCREL: {
282281 // findGOTEntry returns the 'G + GOT' part of the relocation calculation
283282 // based on the load/target address of the GOT (not the current/local addr).
284283 uint64_t GOTAddr = findGOTEntry(Value, SymOffset);
285 uint32_t *Target = reinterpret_cast(Section.Address + Offset);
286284 uint64_t FinalAddress = Section.LoadAddress + Offset;
287285 // The processRelocationRef method combines the symbol offset and the addend
288286 // and in most cases that's what we want. For this relocation type, we need
290288 int64_t RealOffset = GOTAddr + Addend - SymOffset - FinalAddress;
291289 assert(RealOffset <= INT32_MAX && RealOffset >= INT32_MIN);
292290 int32_t TruncOffset = (RealOffset & 0xFFFFFFFF);
293 *Target = TruncOffset;
291 support::ulittle32_t::ref(Section.Address + Offset) = TruncOffset;
294292 break;
295293 }
296294 case ELF::R_X86_64_PC32: {
297295 // Get the placeholder value from the generated object since
298296 // a previous relocation attempt may have overwritten the loaded version
299 uint32_t *Placeholder =
300 reinterpret_cast(Section.ObjAddress + Offset);
301 uint32_t *Target = reinterpret_cast(Section.Address + Offset);
297 support::ulittle32_t::ref Placeholder(
298 (void *)(Section.ObjAddress + Offset));
302299 uint64_t FinalAddress = Section.LoadAddress + Offset;
303 int64_t RealOffset = *Placeholder + Value + Addend - FinalAddress;
300 int64_t RealOffset = Placeholder + Value + Addend - FinalAddress;
304301 assert(RealOffset <= INT32_MAX && RealOffset >= INT32_MIN);
305302 int32_t TruncOffset = (RealOffset & 0xFFFFFFFF);
306 *Target = TruncOffset;
303 support::ulittle32_t::ref(Section.Address + Offset) = TruncOffset;
307304 break;
308305 }
309306 case ELF::R_X86_64_PC64: {
310307 // Get the placeholder value from the generated object since
311308 // a previous relocation attempt may have overwritten the loaded version
312 uint64_t *Placeholder =
313 reinterpret_cast(Section.ObjAddress + Offset);
314 uint64_t *Target = reinterpret_cast(Section.Address + Offset);
309 support::ulittle64_t::ref Placeholder(
310 (void *)(Section.ObjAddress + Offset));
315311 uint64_t FinalAddress = Section.LoadAddress + Offset;
316 *Target = *Placeholder + Value + Addend - FinalAddress;
312 support::ulittle64_t::ref(Section.Address + Offset) =
313 Placeholder + Value + Addend - FinalAddress;
317314 break;
318315 }
319316 }
326323 case ELF::R_386_32: {
327324 // Get the placeholder value from the generated object since
328325 // a previous relocation attempt may have overwritten the loaded version
329 uint32_t *Placeholder =
330 reinterpret_cast(Section.ObjAddress + Offset);
331 uint32_t *Target = reinterpret_cast(Section.Address + Offset);
332 *Target = *Placeholder + Value + Addend;
326 support::ulittle32_t::ref Placeholder(
327 (void *)(Section.ObjAddress + Offset));
328 support::ulittle32_t::ref(Section.Address + Offset) =
329 Placeholder + Value + Addend;
333330 break;
334331 }
335332 case ELF::R_386_PC32: {
336333 // Get the placeholder value from the generated object since
337334 // a previous relocation attempt may have overwritten the loaded version
338 uint32_t *Placeholder =
339 reinterpret_cast(Section.ObjAddress + Offset);
340 uint32_t *Target = reinterpret_cast(Section.Address + Offset);
335 support::ulittle32_t::ref Placeholder(
336 (void *)(Section.ObjAddress + Offset));
341337 uint32_t FinalAddress = ((Section.LoadAddress + Offset) & 0xFFFFFFFF);
342 uint32_t RealOffset = *Placeholder + Value + Addend - FinalAddress;
343 *Target = RealOffset;
338 uint32_t RealOffset = Placeholder + Value + Addend - FinalAddress;
339 support::ulittle32_t::ref(Section.Address + Offset) = RealOffset;
344340 break;
345341 }
346342 default:
1616 #include "X86TargetMachine.h"
1717 #include "llvm/IR/Function.h"
1818 #include "llvm/Support/Compiler.h"
19 #include "llvm/Support/Endian.h"
1920 #include "llvm/Support/ErrorHandling.h"
2021 #include "llvm/Support/Valgrind.h"
2122 #include
3132 # define X86_32_JIT
3233 #endif
3334
35 // x86 is little-endian, and we can do unaligned memory accesses.
36 template
37 static value_type read_x86(const void *memory) {
38 return support::endian::read(memory);
39 }
40
41 template
42 static void write_x86(void *memory, value_type value) {
43 support::endian::write(memory, value);
44 }
45
3446 void X86JITInfo::replaceMachineCodeForFunction(void *Old, void *New) {
35 unsigned char *OldByte = (unsigned char *)Old;
36 *OldByte++ = 0xE9; // Emit JMP opcode.
37 unsigned *OldWord = (unsigned *)OldByte;
47 unsigned char *OldPtr = static_cast(Old);
48 write_x86(OldPtr++, 0xE9); // Emit JMP opcode.
3849 unsigned NewAddr = (intptr_t)New;
39 unsigned OldAddr = (intptr_t)OldWord;
40 *OldWord = NewAddr - OldAddr - 4; // Emit PC-relative addr of New code.
50 unsigned OldAddr = (intptr_t)OldPtr;
51 write_x86(
52 OldPtr, NewAddr - OldAddr - 4); // Emit PC-relative addr of New code.
4153
4254 // X86 doesn't need to invalidate the processor cache, so just invalidate
4355 // Valgrind's cache directly.
350362 "Could not find return address on the stack!");
351363
352364 // It's a stub if there is an interrupt marker after the call.
353 bool isStub = ((unsigned char*)RetAddr)[0] == 0xCE;
365 unsigned char *RetAddrPtr = (unsigned char*)RetAddr;
366 bool isStub = read_x86(RetAddrPtr) == 0xCE;
354367
355368 // The call instruction should have pushed the return value onto the stack...
356369 #if defined (X86_64_JIT)
357 RetAddr--; // Backtrack to the reference itself...
358 #else
359 RetAddr -= 4; // Backtrack to the reference itself...
370 RetAddrPtr--; // Backtrack to the reference itself...
371 #else
372 RetAddrPtr -= 4; // Backtrack to the reference itself...
360373 #endif
361374
362375 #if 0
363 DEBUG(dbgs() << "In callback! Addr=" << (void*)RetAddr
376 DEBUG(dbgs() << "In callback! Addr=" << RetAddrPtr
364377 << " ESP=" << (void*)StackPtr
365378 << ": Resolving call to function: "
366 << TheVM->getFunctionReferencedName((void*)RetAddr) << "\n");
379 << TheVM->getFunctionReferencedName(RetAddrPtr) << "\n");
367380 #endif
368381
369382 // Sanity check to make sure this really is a call instruction.
370383 #if defined (X86_64_JIT)
371 assert(((unsigned char*)RetAddr)[-2] == 0x41 &&"Not a call instr!");
372 assert(((unsigned char*)RetAddr)[-1] == 0xFF &&"Not a call instr!");
373 #else
374 assert(((unsigned char*)RetAddr)[-1] == 0xE8 &&"Not a call instr!");
375 #endif
376
377 intptr_t NewVal = (intptr_t)JITCompilerFunction((void*)RetAddr);
384 assert(read_x86(RetAddrPtr - 2) == 0x41 &&
385 "Not a call instr!");
386 assert(read_x86(RetAddrPtr - 1) == 0xFF &&
387 "Not a call instr!");
388 #else
389 assert(read_x86(RetAddrPtr - 1) == 0xE8 &&
390 "Not a call instr!");
391 #endif
392
393 intptr_t NewVal = (intptr_t)JITCompilerFunction(RetAddrPtr);
378394
379395 // Rewrite the call target... so that we don't end up here every time we
380396 // execute the call.
383399 "X86-64 doesn't support rewriting non-stub lazy compilation calls:"
384400 " the call instruction varies too much.");
385401 #else
386 *(intptr_t *)RetAddr = (intptr_t)(NewVal-RetAddr-4);
402 write_x86(RetAddrPtr, NewVal - (intptr_t)RetAddrPtr - 4);
387403 #endif
388404
389405 if (isStub) {
396412 // PC-relative branch instead of loading the actual address. (This is
397413 // considerably shorter than the 64-bit immediate load already there.)
398414 // We assume here intptr_t is 64 bits.
399 intptr_t diff = NewVal-RetAddr+7;
415 intptr_t diff = NewVal - (intptr_t)RetAddrPtr + 7;
400416 if (diff >= -2147483648LL && diff <= 2147483647LL) {
401 *(unsigned char*)(RetAddr-0xc) = 0xE9;
402 *(intptr_t *)(RetAddr-0xb) = diff & 0xffffffff;
417 write_x86(RetAddrPtr - 0xC, 0xE9);
418 write_x86(RetAddrPtr - 0xB, diff & 0xffffffff);
403419 } else {
404 *(intptr_t *)(RetAddr - 0xa) = NewVal;
405 ((unsigned char*)RetAddr)[0] = (2 | (4 << 3) | (3 << 6));
420 write_x86(RetAddrPtr - 0xA, NewVal);
421 write_x86(RetAddrPtr, (2 | (4 << 3) | (3 << 6)));
406422 }
407 sys::ValgrindDiscardTranslations((void*)(RetAddr-0xc), 0xd);
408 #else
409 ((unsigned char*)RetAddr)[-1] = 0xE9;
410 sys::ValgrindDiscardTranslations((void*)(RetAddr-1), 5);
423 sys::ValgrindDiscardTranslations(RetAddrPtr - 0xC, 0xd);
424 #else
425 write_x86(RetAddrPtr - 1, 0xE9);
426 sys::ValgrindDiscardTranslations(RetAddrPtr - 1, 5);
411427 #endif
412428 }
413429