Index: llvm/trunk/include/llvm/Support/Endian.h =================================================================== --- llvm/trunk/include/llvm/Support/Endian.h +++ llvm/trunk/include/llvm/Support/Endian.h @@ -96,7 +96,24 @@ private: AlignedCharArray::value, sizeof(value_type)> Value; + +public: + struct ref { + explicit ref(void *Ptr) : Ptr(Ptr) {} + + operator value_type() const { + return endian::read(Ptr); + } + + void operator=(value_type NewValue) { + endian::write(Ptr, NewValue); + } + + private: + void *Ptr; + }; }; + } // end namespace detail typedef detail::packed_endian_specific_integral Index: llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp =================================================================== --- llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp +++ llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp @@ -23,6 +23,7 @@ #include "llvm/Object/ELFObjectFile.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/ELF.h" +#include "llvm/Support/Endian.h" #include "llvm/Support/MemoryBuffer.h" using namespace llvm; @@ -260,10 +261,9 @@ llvm_unreachable("Relocation type not implemented yet!"); break; case ELF::R_X86_64_64: { - uint64_t *Target = reinterpret_cast(Section.Address + Offset); - *Target = Value + Addend; + support::ulittle64_t::ref(Section.Address + Offset) = Value + Addend; DEBUG(dbgs() << "Writing " << format("%p", (Value + Addend)) << " at " - << format("%p\n", Target)); + << format("%p\n", Section.Address + Offset)); break; } case ELF::R_X86_64_32: @@ -273,17 +273,15 @@ (Type == ELF::R_X86_64_32S && ((int64_t)Value <= INT32_MAX && (int64_t)Value >= INT32_MIN))); uint32_t TruncatedAddr = (Value & 0xFFFFFFFF); - uint32_t *Target = reinterpret_cast(Section.Address + Offset); - *Target = TruncatedAddr; + support::ulittle32_t::ref(Section.Address + Offset) = TruncatedAddr; DEBUG(dbgs() << "Writing " << format("%p", TruncatedAddr) << " at " - << format("%p\n", Target)); + << format("%p\n", Section.Address + Offset)); break; } case ELF::R_X86_64_GOTPCREL: { // findGOTEntry returns the 'G + GOT' part of the relocation calculation // based on the load/target address of the GOT (not the current/local addr). uint64_t GOTAddr = findGOTEntry(Value, SymOffset); - uint32_t *Target = reinterpret_cast(Section.Address + Offset); uint64_t FinalAddress = Section.LoadAddress + Offset; // The processRelocationRef method combines the symbol offset and the addend // and in most cases that's what we want. For this relocation type, we need @@ -291,30 +289,29 @@ int64_t RealOffset = GOTAddr + Addend - SymOffset - FinalAddress; assert(RealOffset <= INT32_MAX && RealOffset >= INT32_MIN); int32_t TruncOffset = (RealOffset & 0xFFFFFFFF); - *Target = TruncOffset; + support::ulittle32_t::ref(Section.Address + Offset) = TruncOffset; break; } case ELF::R_X86_64_PC32: { // Get the placeholder value from the generated object since // a previous relocation attempt may have overwritten the loaded version - uint32_t *Placeholder = - reinterpret_cast(Section.ObjAddress + Offset); - uint32_t *Target = reinterpret_cast(Section.Address + Offset); + support::ulittle32_t::ref Placeholder( + (void *)(Section.ObjAddress + Offset)); uint64_t FinalAddress = Section.LoadAddress + Offset; - int64_t RealOffset = *Placeholder + Value + Addend - FinalAddress; + int64_t RealOffset = Placeholder + Value + Addend - FinalAddress; assert(RealOffset <= INT32_MAX && RealOffset >= INT32_MIN); int32_t TruncOffset = (RealOffset & 0xFFFFFFFF); - *Target = TruncOffset; + support::ulittle32_t::ref(Section.Address + Offset) = TruncOffset; break; } case ELF::R_X86_64_PC64: { // Get the placeholder value from the generated object since // a previous relocation attempt may have overwritten the loaded version - uint64_t *Placeholder = - reinterpret_cast(Section.ObjAddress + Offset); - uint64_t *Target = reinterpret_cast(Section.Address + Offset); + support::ulittle64_t::ref Placeholder( + (void *)(Section.ObjAddress + Offset)); uint64_t FinalAddress = Section.LoadAddress + Offset; - *Target = *Placeholder + Value + Addend - FinalAddress; + support::ulittle64_t::ref(Section.Address + Offset) = + Placeholder + Value + Addend - FinalAddress; break; } } @@ -327,21 +324,20 @@ case ELF::R_386_32: { // Get the placeholder value from the generated object since // a previous relocation attempt may have overwritten the loaded version - uint32_t *Placeholder = - reinterpret_cast(Section.ObjAddress + Offset); - uint32_t *Target = reinterpret_cast(Section.Address + Offset); - *Target = *Placeholder + Value + Addend; + support::ulittle32_t::ref Placeholder( + (void *)(Section.ObjAddress + Offset)); + support::ulittle32_t::ref(Section.Address + Offset) = + Placeholder + Value + Addend; break; } case ELF::R_386_PC32: { // Get the placeholder value from the generated object since // a previous relocation attempt may have overwritten the loaded version - uint32_t *Placeholder = - reinterpret_cast(Section.ObjAddress + Offset); - uint32_t *Target = reinterpret_cast(Section.Address + Offset); + support::ulittle32_t::ref Placeholder( + (void *)(Section.ObjAddress + Offset)); uint32_t FinalAddress = ((Section.LoadAddress + Offset) & 0xFFFFFFFF); - uint32_t RealOffset = *Placeholder + Value + Addend - FinalAddress; - *Target = RealOffset; + uint32_t RealOffset = Placeholder + Value + Addend - FinalAddress; + support::ulittle32_t::ref(Section.Address + Offset) = RealOffset; break; } default: Index: llvm/trunk/lib/Target/X86/X86JITInfo.cpp =================================================================== --- llvm/trunk/lib/Target/X86/X86JITInfo.cpp +++ llvm/trunk/lib/Target/X86/X86JITInfo.cpp @@ -17,6 +17,7 @@ #include "X86TargetMachine.h" #include "llvm/IR/Function.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/Endian.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Valgrind.h" #include @@ -32,13 +33,24 @@ # define X86_32_JIT #endif +// x86 is little-endian, and we can do unaligned memory accesses. +template +static value_type read_x86(const void *memory) { + return support::endian::read(memory); +} + +template +static void write_x86(void *memory, value_type value) { + support::endian::write(memory, value); +} + void X86JITInfo::replaceMachineCodeForFunction(void *Old, void *New) { - unsigned char *OldByte = (unsigned char *)Old; - *OldByte++ = 0xE9; // Emit JMP opcode. - unsigned *OldWord = (unsigned *)OldByte; + unsigned char *OldPtr = static_cast(Old); + write_x86(OldPtr++, 0xE9); // Emit JMP opcode. unsigned NewAddr = (intptr_t)New; - unsigned OldAddr = (intptr_t)OldWord; - *OldWord = NewAddr - OldAddr - 4; // Emit PC-relative addr of New code. + unsigned OldAddr = (intptr_t)OldPtr; + write_x86( + OldPtr, NewAddr - OldAddr - 4); // Emit PC-relative addr of New code. // X86 doesn't need to invalidate the processor cache, so just invalidate // Valgrind's cache directly. @@ -351,31 +363,35 @@ "Could not find return address on the stack!"); // It's a stub if there is an interrupt marker after the call. - bool isStub = ((unsigned char*)RetAddr)[0] == 0xCE; + unsigned char *RetAddrPtr = (unsigned char*)RetAddr; + bool isStub = read_x86(RetAddrPtr) == 0xCE; // The call instruction should have pushed the return value onto the stack... #if defined (X86_64_JIT) - RetAddr--; // Backtrack to the reference itself... + RetAddrPtr--; // Backtrack to the reference itself... #else - RetAddr -= 4; // Backtrack to the reference itself... + RetAddrPtr -= 4; // Backtrack to the reference itself... #endif #if 0 - DEBUG(dbgs() << "In callback! Addr=" << (void*)RetAddr + DEBUG(dbgs() << "In callback! Addr=" << RetAddrPtr << " ESP=" << (void*)StackPtr << ": Resolving call to function: " - << TheVM->getFunctionReferencedName((void*)RetAddr) << "\n"); + << TheVM->getFunctionReferencedName(RetAddrPtr) << "\n"); #endif // Sanity check to make sure this really is a call instruction. #if defined (X86_64_JIT) - assert(((unsigned char*)RetAddr)[-2] == 0x41 &&"Not a call instr!"); - assert(((unsigned char*)RetAddr)[-1] == 0xFF &&"Not a call instr!"); + assert(read_x86(RetAddrPtr - 2) == 0x41 && + "Not a call instr!"); + assert(read_x86(RetAddrPtr - 1) == 0xFF && + "Not a call instr!"); #else - assert(((unsigned char*)RetAddr)[-1] == 0xE8 &&"Not a call instr!"); + assert(read_x86(RetAddrPtr - 1) == 0xE8 && + "Not a call instr!"); #endif - intptr_t NewVal = (intptr_t)JITCompilerFunction((void*)RetAddr); + intptr_t NewVal = (intptr_t)JITCompilerFunction(RetAddrPtr); // Rewrite the call target... so that we don't end up here every time we // execute the call. @@ -384,7 +400,7 @@ "X86-64 doesn't support rewriting non-stub lazy compilation calls:" " the call instruction varies too much."); #else - *(intptr_t *)RetAddr = (intptr_t)(NewVal-RetAddr-4); + write_x86(RetAddrPtr, NewVal - (intptr_t)RetAddrPtr - 4); #endif if (isStub) { @@ -397,18 +413,18 @@ // PC-relative branch instead of loading the actual address. (This is // considerably shorter than the 64-bit immediate load already there.) // We assume here intptr_t is 64 bits. - intptr_t diff = NewVal-RetAddr+7; + intptr_t diff = NewVal - (intptr_t)RetAddrPtr + 7; if (diff >= -2147483648LL && diff <= 2147483647LL) { - *(unsigned char*)(RetAddr-0xc) = 0xE9; - *(intptr_t *)(RetAddr-0xb) = diff & 0xffffffff; + write_x86(RetAddrPtr - 0xC, 0xE9); + write_x86(RetAddrPtr - 0xB, diff & 0xffffffff); } else { - *(intptr_t *)(RetAddr - 0xa) = NewVal; - ((unsigned char*)RetAddr)[0] = (2 | (4 << 3) | (3 << 6)); + write_x86(RetAddrPtr - 0xA, NewVal); + write_x86(RetAddrPtr, (2 | (4 << 3) | (3 << 6))); } - sys::ValgrindDiscardTranslations((void*)(RetAddr-0xc), 0xd); + sys::ValgrindDiscardTranslations(RetAddrPtr - 0xC, 0xd); #else - ((unsigned char*)RetAddr)[-1] = 0xE9; - sys::ValgrindDiscardTranslations((void*)(RetAddr-1), 5); + write_x86(RetAddrPtr - 1, 0xE9); + sys::ValgrindDiscardTranslations(RetAddrPtr - 1, 5); #endif }