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 using namespace llvm; 00020 00021 void X86JITInfo::replaceMachineCodeForFunction(void *Old, void *New) { 00022 unsigned char *OldByte = (unsigned char *)Old; 00023 *OldByte++ = 0xE9; // Emit JMP opcode. 00024 unsigned *OldWord = (unsigned *)OldByte; 00025 unsigned NewAddr = (intptr_t)New; 00026 unsigned OldAddr = (intptr_t)OldWord; 00027 *OldWord = NewAddr - OldAddr - 4; // Emit PC-relative addr of New code. 00028 } 00029 00030 00031 #ifdef _MSC_VER 00032 #pragma optimize("y", off) 00033 #endif 00034 00035 /// JITCompilerFunction - This contains the address of the JIT function used to 00036 /// compile a function lazily. 00037 static TargetJITInfo::JITCompilerFn JITCompilerFunction; 00038 00039 /// CompilationCallback - This is the target-specific function invoked by the 00040 /// function stub when we did not know the real target of a call. This function 00041 /// must locate the start of the stub or call site and pass it into the JIT 00042 /// compiler function. 00043 static void CompilationCallback() { 00044 #ifdef _MSC_VER 00045 unsigned *StackPtr, RetAddr; 00046 __asm mov StackPtr, ebp; 00047 __asm mov eax, DWORD PTR [ebp + 4]; 00048 __asm mov RetAddr, eax; 00049 #else 00050 unsigned *StackPtr = (unsigned*)__builtin_frame_address(0); 00051 unsigned RetAddr = (unsigned)(intptr_t)__builtin_return_address(0); 00052 00053 // NOTE: __builtin_frame_address doesn't work if frame pointer elimination has 00054 // been performed. Having a variable sized alloca disables frame pointer 00055 // elimination currently, even if it's dead. This is a gross hack. 00056 alloca(10+(RetAddr >> 31)); 00057 00058 #endif 00059 assert(StackPtr[1] == RetAddr && 00060 "Could not find return address on the stack!"); 00061 00062 // It's a stub if there is an interrupt marker after the call. 00063 bool isStub = ((unsigned char*)(intptr_t)RetAddr)[0] == 0xCD; 00064 00065 // The call instruction should have pushed the return value onto the stack... 00066 RetAddr -= 4; // Backtrack to the reference itself... 00067 00068 #if 0 00069 DEBUG(std::cerr << "In callback! Addr=" << (void*)RetAddr 00070 << " ESP=" << (void*)StackPtr 00071 << ": Resolving call to function: " 00072 << TheVM->getFunctionReferencedName((void*)RetAddr) << "\n"); 00073 #endif 00074 00075 // Sanity check to make sure this really is a call instruction. 00076 assert(((unsigned char*)(intptr_t)RetAddr)[-1] == 0xE8 &&"Not a call instr!"); 00077 00078 unsigned NewVal = (intptr_t)JITCompilerFunction((void*)(intptr_t)RetAddr); 00079 00080 // Rewrite the call target... so that we don't end up here every time we 00081 // execute the call. 00082 *(unsigned*)(intptr_t)RetAddr = NewVal-RetAddr-4; 00083 00084 if (isStub) { 00085 // If this is a stub, rewrite the call into an unconditional branch 00086 // instruction so that two return addresses are not pushed onto the stack 00087 // when the requested function finally gets called. This also makes the 00088 // 0xCD byte (interrupt) dead, so the marker doesn't effect anything. 00089 ((unsigned char*)(intptr_t)RetAddr)[-1] = 0xE9; 00090 } 00091 00092 // Change the return address to reexecute the call instruction... 00093 StackPtr[1] -= 5; 00094 } 00095 00096 #ifdef _MSC_VER 00097 #pragma optimize( "", on ) 00098 #endif 00099 00100 TargetJITInfo::LazyResolverFn 00101 X86JITInfo::getLazyResolverFunction(JITCompilerFn F) { 00102 JITCompilerFunction = F; 00103 return CompilationCallback; 00104 } 00105 00106 void *X86JITInfo::emitFunctionStub(void *Fn, MachineCodeEmitter &MCE) { 00107 if (Fn != CompilationCallback) { 00108 MCE.startFunctionStub(5); 00109 MCE.emitByte(0xE9); 00110 MCE.emitWord((intptr_t)Fn-MCE.getCurrentPCValue()-4); 00111 return MCE.finishFunctionStub(0); 00112 } 00113 00114 MCE.startFunctionStub(6); 00115 MCE.emitByte(0xE8); // Call with 32 bit pc-rel destination... 00116 00117 MCE.emitWord((intptr_t)Fn-MCE.getCurrentPCValue()-4); 00118 00119 MCE.emitByte(0xCD); // Interrupt - Just a marker identifying the stub! 00120 return MCE.finishFunctionStub(0); 00121 } 00122 00123 /// relocate - Before the JIT can run a block of code that has been emitted, 00124 /// it must rewrite the code to contain the actual addresses of any 00125 /// referenced global symbols. 00126 void X86JITInfo::relocate(void *Function, MachineRelocation *MR, 00127 unsigned NumRelocs) { 00128 for (unsigned i = 0; i != NumRelocs; ++i, ++MR) { 00129 void *RelocPos = (char*)Function + MR->getMachineCodeOffset(); 00130 intptr_t ResultPtr = (intptr_t)MR->getResultPointer(); 00131 switch ((X86::RelocationType)MR->getRelocationType()) { 00132 case X86::reloc_pcrel_word: 00133 // PC relative relocation, add the relocated value to the value already in 00134 // memory, after we adjust it for where the PC is. 00135 ResultPtr = ResultPtr-(intptr_t)RelocPos-4; 00136 *((intptr_t*)RelocPos) += ResultPtr; 00137 break; 00138 case X86::reloc_absolute_word: 00139 // Absolute relocation, just add the relocated value to the value already 00140 // in memory. 00141 *((intptr_t*)RelocPos) += ResultPtr; 00142 break; 00143 } 00144 } 00145 }