LLVM API Documentation
00001 //===-- X86JITInfo.cpp - Implement the JIT interfaces for the X86 target --===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file was developed by the LLVM research group and is distributed under 00006 // the University of Illinois Open Source License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This file implements the JIT interfaces for the X86 target. 00011 // 00012 //===----------------------------------------------------------------------===// 00013 00014 #define DEBUG_TYPE "jit" 00015 #include "X86JITInfo.h" 00016 #include "X86Relocations.h" 00017 #include "llvm/CodeGen/MachineCodeEmitter.h" 00018 #include "llvm/Config/alloca.h" 00019 #include <cstdlib> 00020 #include <iostream> 00021 using namespace llvm; 00022 00023 #ifdef _MSC_VER 00024 extern "C" void *_AddressOfReturnAddress(void); 00025 #pragma intrinsic(_AddressOfReturnAddress) 00026 #endif 00027 00028 void X86JITInfo::replaceMachineCodeForFunction(void *Old, void *New) { 00029 unsigned char *OldByte = (unsigned char *)Old; 00030 *OldByte++ = 0xE9; // Emit JMP opcode. 00031 unsigned *OldWord = (unsigned *)OldByte; 00032 unsigned NewAddr = (intptr_t)New; 00033 unsigned OldAddr = (intptr_t)OldWord; 00034 *OldWord = NewAddr - OldAddr - 4; // Emit PC-relative addr of New code. 00035 } 00036 00037 00038 /// JITCompilerFunction - This contains the address of the JIT function used to 00039 /// compile a function lazily. 00040 static TargetJITInfo::JITCompilerFn JITCompilerFunction; 00041 00042 // Provide a wrapper for X86CompilationCallback2 that saves non-traditional 00043 // callee saved registers, for the fastcc calling convention. 00044 extern "C" { 00045 #if defined(__i386__) || defined(i386) || defined(_M_IX86) 00046 #ifndef _MSC_VER 00047 void X86CompilationCallback(void); 00048 asm( 00049 ".text\n" 00050 ".align 8\n" 00051 #if defined(__CYGWIN__) || defined(__APPLE__) 00052 ".globl _X86CompilationCallback\n" 00053 "_X86CompilationCallback:\n" 00054 #else 00055 ".globl X86CompilationCallback\n" 00056 "X86CompilationCallback:\n" 00057 #endif 00058 "pushl %ebp\n" 00059 "movl %esp, %ebp\n" // Standard prologue 00060 "pushl %eax\n" 00061 "pushl %edx\n" // save EAX/EDX 00062 #if defined(__CYGWIN__) || defined(__APPLE__) 00063 "call _X86CompilationCallback2\n" 00064 #else 00065 "call X86CompilationCallback2\n" 00066 #endif 00067 "popl %edx\n" 00068 "popl %eax\n" 00069 "popl %ebp\n" 00070 "ret\n"); 00071 #else 00072 void X86CompilationCallback2(void); 00073 00074 _declspec(naked) void X86CompilationCallback(void) { 00075 __asm { 00076 push eax 00077 push edx 00078 call X86CompilationCallback2 00079 pop edx 00080 pop eax 00081 ret 00082 } 00083 } 00084 #endif // _MSC_VER 00085 00086 #else // Not an i386 host 00087 void X86CompilationCallback() { 00088 std::cerr << "Cannot call X86CompilationCallback() on a non-x86 arch!\n"; 00089 abort(); 00090 } 00091 #endif 00092 } 00093 00094 /// X86CompilationCallback - This is the target-specific function invoked by the 00095 /// function stub when we did not know the real target of a call. This function 00096 /// must locate the start of the stub or call site and pass it into the JIT 00097 /// compiler function. 00098 extern "C" void X86CompilationCallback2() { 00099 #ifdef _MSC_VER 00100 assert(sizeof(size_t) == 4); // FIXME: handle Win64 00101 unsigned *RetAddrLoc = (unsigned *)_AddressOfReturnAddress(); 00102 RetAddrLoc += 3; // skip over ret addr, edx, eax 00103 unsigned RetAddr = *RetAddrLoc; 00104 #else 00105 unsigned *StackPtr = (unsigned*)__builtin_frame_address(1); 00106 unsigned RetAddr = (unsigned)(intptr_t)__builtin_return_address(1); 00107 unsigned *RetAddrLoc = &StackPtr[1]; 00108 00109 // NOTE: __builtin_frame_address doesn't work if frame pointer elimination has 00110 // been performed. Having a variable sized alloca disables frame pointer 00111 // elimination currently, even if it's dead. This is a gross hack. 00112 alloca(10+(RetAddr >> 31)); 00113 00114 #endif 00115 assert(*RetAddrLoc == RetAddr && 00116 "Could not find return address on the stack!"); 00117 00118 // It's a stub if there is an interrupt marker after the call. 00119 bool isStub = ((unsigned char*)(intptr_t)RetAddr)[0] == 0xCD; 00120 00121 // The call instruction should have pushed the return value onto the stack... 00122 RetAddr -= 4; // Backtrack to the reference itself... 00123 00124 #if 0 00125 DEBUG(std::cerr << "In callback! Addr=" << (void*)RetAddr 00126 << " ESP=" << (void*)StackPtr 00127 << ": Resolving call to function: " 00128 << TheVM->getFunctionReferencedName((void*)RetAddr) << "\n"); 00129 #endif 00130 00131 // Sanity check to make sure this really is a call instruction. 00132 assert(((unsigned char*)(intptr_t)RetAddr)[-1] == 0xE8 &&"Not a call instr!"); 00133 00134 unsigned NewVal = (intptr_t)JITCompilerFunction((void*)(intptr_t)RetAddr); 00135 00136 // Rewrite the call target... so that we don't end up here every time we 00137 // execute the call. 00138 *(unsigned*)(intptr_t)RetAddr = NewVal-RetAddr-4; 00139 00140 if (isStub) { 00141 // If this is a stub, rewrite the call into an unconditional branch 00142 // instruction so that two return addresses are not pushed onto the stack 00143 // when the requested function finally gets called. This also makes the 00144 // 0xCD byte (interrupt) dead, so the marker doesn't effect anything. 00145 ((unsigned char*)(intptr_t)RetAddr)[-1] = 0xE9; 00146 } 00147 00148 // Change the return address to reexecute the call instruction... 00149 *RetAddrLoc -= 5; 00150 } 00151 00152 TargetJITInfo::LazyResolverFn 00153 X86JITInfo::getLazyResolverFunction(JITCompilerFn F) { 00154 JITCompilerFunction = F; 00155 return X86CompilationCallback; 00156 } 00157 00158 void *X86JITInfo::emitFunctionStub(void *Fn, MachineCodeEmitter &MCE) { 00159 if (Fn != X86CompilationCallback) { 00160 MCE.startFunctionStub(5); 00161 MCE.emitByte(0xE9); 00162 MCE.emitWord((intptr_t)Fn-MCE.getCurrentPCValue()-4); 00163 return MCE.finishFunctionStub(0); 00164 } 00165 00166 MCE.startFunctionStub(6); 00167 MCE.emitByte(0xE8); // Call with 32 bit pc-rel destination... 00168 00169 MCE.emitWord((intptr_t)Fn-MCE.getCurrentPCValue()-4); 00170 00171 MCE.emitByte(0xCD); // Interrupt - Just a marker identifying the stub! 00172 return MCE.finishFunctionStub(0); 00173 } 00174 00175 /// relocate - Before the JIT can run a block of code that has been emitted, 00176 /// it must rewrite the code to contain the actual addresses of any 00177 /// referenced global symbols. 00178 void X86JITInfo::relocate(void *Function, MachineRelocation *MR, 00179 unsigned NumRelocs, unsigned char* GOTBase) { 00180 for (unsigned i = 0; i != NumRelocs; ++i, ++MR) { 00181 void *RelocPos = (char*)Function + MR->getMachineCodeOffset(); 00182 intptr_t ResultPtr = (intptr_t)MR->getResultPointer(); 00183 switch ((X86::RelocationType)MR->getRelocationType()) { 00184 case X86::reloc_pcrel_word: 00185 // PC relative relocation, add the relocated value to the value already in 00186 // memory, after we adjust it for where the PC is. 00187 ResultPtr = ResultPtr-(intptr_t)RelocPos-4; 00188 *((intptr_t*)RelocPos) += ResultPtr; 00189 break; 00190 case X86::reloc_absolute_word: 00191 // Absolute relocation, just add the relocated value to the value already 00192 // in memory. 00193 *((intptr_t*)RelocPos) += ResultPtr; 00194 break; 00195 } 00196 } 00197 }