Chris Lattner | 7ddde32 | 2004-11-20 23:54:33 +0000 | [diff] [blame] | 1 | //===-- X86JITInfo.cpp - Implement the JIT interfaces for the X86 target --===// |
Misha Brukman | 0e0a7a45 | 2005-04-21 23:38:14 +0000 | [diff] [blame] | 2 | // |
Chris Lattner | 7ddde32 | 2004-11-20 23:54:33 +0000 | [diff] [blame] | 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file was developed by the LLVM research group and is distributed under |
| 6 | // the University of Illinois Open Source License. See LICENSE.TXT for details. |
Misha Brukman | 0e0a7a45 | 2005-04-21 23:38:14 +0000 | [diff] [blame] | 7 | // |
Chris Lattner | 7ddde32 | 2004-11-20 23:54:33 +0000 | [diff] [blame] | 8 | //===----------------------------------------------------------------------===// |
| 9 | // |
| 10 | // This file implements the JIT interfaces for the X86 target. |
| 11 | // |
| 12 | //===----------------------------------------------------------------------===// |
| 13 | |
| 14 | #define DEBUG_TYPE "jit" |
| 15 | #include "X86JITInfo.h" |
| 16 | #include "X86Relocations.h" |
| 17 | #include "llvm/CodeGen/MachineCodeEmitter.h" |
| 18 | #include "llvm/Config/alloca.h" |
| 19 | using namespace llvm; |
| 20 | |
Chris Lattner | 7ddde32 | 2004-11-20 23:54:33 +0000 | [diff] [blame] | 21 | void X86JITInfo::replaceMachineCodeForFunction(void *Old, void *New) { |
| 22 | unsigned char *OldByte = (unsigned char *)Old; |
| 23 | *OldByte++ = 0xE9; // Emit JMP opcode. |
| 24 | unsigned *OldWord = (unsigned *)OldByte; |
| 25 | unsigned NewAddr = (intptr_t)New; |
| 26 | unsigned OldAddr = (intptr_t)OldWord; |
| 27 | *OldWord = NewAddr - OldAddr - 4; // Emit PC-relative addr of New code. |
| 28 | } |
| 29 | |
| 30 | |
| 31 | #ifdef _MSC_VER |
| 32 | #pragma optimize("y", off) |
| 33 | #endif |
| 34 | |
| 35 | /// JITCompilerFunction - This contains the address of the JIT function used to |
| 36 | /// compile a function lazily. |
| 37 | static TargetJITInfo::JITCompilerFn JITCompilerFunction; |
| 38 | |
Chris Lattner | 1030f72 | 2005-05-19 06:49:17 +0000 | [diff] [blame^] | 39 | // Provide a wrapper for X86CompilationCallback2 that saves non-traditional |
| 40 | // callee saved registers, for the fastcc calling convention. |
| 41 | extern "C" void X86CompilationCallback(void); |
| 42 | |
| 43 | #if defined(__i386__) || defined(i386) |
| 44 | #ifndef _MSC_VER |
| 45 | asm( |
| 46 | ".text\n" |
| 47 | ".align 8\n" |
| 48 | ".globl X86CompilationCallback\n" |
| 49 | "X86CompilationCallback:\n" |
| 50 | "pushl %ebp\n" |
| 51 | "movl %esp, %ebp\n" // Standard prologue |
| 52 | "pushl %eax\n" |
| 53 | "pushl %edx\n" // save EAX/EDX |
| 54 | "call X86CompilationCallback2\n" |
| 55 | "popl %edx\n" |
| 56 | "popl %eax\n" |
| 57 | "popl %ebp\n" |
| 58 | "ret\n"); |
| 59 | #else |
| 60 | // FIXME: implement this for VC++ |
| 61 | #endif |
| 62 | |
| 63 | #else |
| 64 | // Not an i386 host |
| 65 | void X86CompilationCallback() { |
| 66 | assert(0 && "This is not a X86, you can't execute this!"); |
| 67 | abort(); |
| 68 | } |
| 69 | #endif |
| 70 | |
| 71 | /// X86CompilationCallback - This is the target-specific function invoked by the |
Chris Lattner | 7ddde32 | 2004-11-20 23:54:33 +0000 | [diff] [blame] | 72 | /// function stub when we did not know the real target of a call. This function |
| 73 | /// must locate the start of the stub or call site and pass it into the JIT |
| 74 | /// compiler function. |
Chris Lattner | 1030f72 | 2005-05-19 06:49:17 +0000 | [diff] [blame^] | 75 | extern "C" void X86CompilationCallback2() { |
Chris Lattner | 7ddde32 | 2004-11-20 23:54:33 +0000 | [diff] [blame] | 76 | #ifdef _MSC_VER |
Chris Lattner | 1030f72 | 2005-05-19 06:49:17 +0000 | [diff] [blame^] | 77 | // FIXME: This needs to go up one more level! |
Chris Lattner | 7ddde32 | 2004-11-20 23:54:33 +0000 | [diff] [blame] | 78 | unsigned *StackPtr, RetAddr; |
| 79 | __asm mov StackPtr, ebp; |
| 80 | __asm mov eax, DWORD PTR [ebp + 4]; |
| 81 | __asm mov RetAddr, eax; |
| 82 | #else |
Chris Lattner | 1030f72 | 2005-05-19 06:49:17 +0000 | [diff] [blame^] | 83 | unsigned *StackPtr = (unsigned*)__builtin_frame_address(1); |
| 84 | unsigned RetAddr = (unsigned)(intptr_t)__builtin_return_address(1); |
Chris Lattner | 7ddde32 | 2004-11-20 23:54:33 +0000 | [diff] [blame] | 85 | |
| 86 | // NOTE: __builtin_frame_address doesn't work if frame pointer elimination has |
| 87 | // been performed. Having a variable sized alloca disables frame pointer |
| 88 | // elimination currently, even if it's dead. This is a gross hack. |
| 89 | alloca(10+(RetAddr >> 31)); |
Misha Brukman | 0e0a7a45 | 2005-04-21 23:38:14 +0000 | [diff] [blame] | 90 | |
Chris Lattner | 7ddde32 | 2004-11-20 23:54:33 +0000 | [diff] [blame] | 91 | #endif |
| 92 | assert(StackPtr[1] == RetAddr && |
| 93 | "Could not find return address on the stack!"); |
| 94 | |
| 95 | // It's a stub if there is an interrupt marker after the call. |
| 96 | bool isStub = ((unsigned char*)(intptr_t)RetAddr)[0] == 0xCD; |
| 97 | |
| 98 | // The call instruction should have pushed the return value onto the stack... |
| 99 | RetAddr -= 4; // Backtrack to the reference itself... |
| 100 | |
| 101 | #if 0 |
| 102 | DEBUG(std::cerr << "In callback! Addr=" << (void*)RetAddr |
| 103 | << " ESP=" << (void*)StackPtr |
| 104 | << ": Resolving call to function: " |
| 105 | << TheVM->getFunctionReferencedName((void*)RetAddr) << "\n"); |
| 106 | #endif |
| 107 | |
| 108 | // Sanity check to make sure this really is a call instruction. |
| 109 | assert(((unsigned char*)(intptr_t)RetAddr)[-1] == 0xE8 &&"Not a call instr!"); |
Misha Brukman | 0e0a7a45 | 2005-04-21 23:38:14 +0000 | [diff] [blame] | 110 | |
Chris Lattner | 7ddde32 | 2004-11-20 23:54:33 +0000 | [diff] [blame] | 111 | unsigned NewVal = (intptr_t)JITCompilerFunction((void*)(intptr_t)RetAddr); |
| 112 | |
| 113 | // Rewrite the call target... so that we don't end up here every time we |
| 114 | // execute the call. |
| 115 | *(unsigned*)(intptr_t)RetAddr = NewVal-RetAddr-4; |
| 116 | |
| 117 | if (isStub) { |
| 118 | // If this is a stub, rewrite the call into an unconditional branch |
| 119 | // instruction so that two return addresses are not pushed onto the stack |
| 120 | // when the requested function finally gets called. This also makes the |
| 121 | // 0xCD byte (interrupt) dead, so the marker doesn't effect anything. |
| 122 | ((unsigned char*)(intptr_t)RetAddr)[-1] = 0xE9; |
| 123 | } |
| 124 | |
| 125 | // Change the return address to reexecute the call instruction... |
| 126 | StackPtr[1] -= 5; |
| 127 | } |
| 128 | |
| 129 | #ifdef _MSC_VER |
| 130 | #pragma optimize( "", on ) |
| 131 | #endif |
| 132 | |
| 133 | TargetJITInfo::LazyResolverFn |
| 134 | X86JITInfo::getLazyResolverFunction(JITCompilerFn F) { |
| 135 | JITCompilerFunction = F; |
Chris Lattner | 1030f72 | 2005-05-19 06:49:17 +0000 | [diff] [blame^] | 136 | return X86CompilationCallback; |
Chris Lattner | 7ddde32 | 2004-11-20 23:54:33 +0000 | [diff] [blame] | 137 | } |
| 138 | |
Chris Lattner | 90b1b45 | 2004-11-22 22:25:30 +0000 | [diff] [blame] | 139 | void *X86JITInfo::emitFunctionStub(void *Fn, MachineCodeEmitter &MCE) { |
Chris Lattner | 1030f72 | 2005-05-19 06:49:17 +0000 | [diff] [blame^] | 140 | if (Fn != X86CompilationCallback) { |
Chris Lattner | 90b1b45 | 2004-11-22 22:25:30 +0000 | [diff] [blame] | 141 | MCE.startFunctionStub(5); |
| 142 | MCE.emitByte(0xE9); |
| 143 | MCE.emitWord((intptr_t)Fn-MCE.getCurrentPCValue()-4); |
| 144 | return MCE.finishFunctionStub(0); |
| 145 | } |
Misha Brukman | 0e0a7a45 | 2005-04-21 23:38:14 +0000 | [diff] [blame] | 146 | |
Chris Lattner | 90b1b45 | 2004-11-22 22:25:30 +0000 | [diff] [blame] | 147 | MCE.startFunctionStub(6); |
| 148 | MCE.emitByte(0xE8); // Call with 32 bit pc-rel destination... |
| 149 | |
| 150 | MCE.emitWord((intptr_t)Fn-MCE.getCurrentPCValue()-4); |
| 151 | |
| 152 | MCE.emitByte(0xCD); // Interrupt - Just a marker identifying the stub! |
| 153 | return MCE.finishFunctionStub(0); |
| 154 | } |
Chris Lattner | 7ddde32 | 2004-11-20 23:54:33 +0000 | [diff] [blame] | 155 | |
| 156 | /// relocate - Before the JIT can run a block of code that has been emitted, |
| 157 | /// it must rewrite the code to contain the actual addresses of any |
| 158 | /// referenced global symbols. |
| 159 | void X86JITInfo::relocate(void *Function, MachineRelocation *MR, |
| 160 | unsigned NumRelocs) { |
| 161 | for (unsigned i = 0; i != NumRelocs; ++i, ++MR) { |
| 162 | void *RelocPos = (char*)Function + MR->getMachineCodeOffset(); |
| 163 | intptr_t ResultPtr = (intptr_t)MR->getResultPointer(); |
| 164 | switch ((X86::RelocationType)MR->getRelocationType()) { |
| 165 | case X86::reloc_pcrel_word: |
| 166 | // PC relative relocation, add the relocated value to the value already in |
| 167 | // memory, after we adjust it for where the PC is. |
| 168 | ResultPtr = ResultPtr-(intptr_t)RelocPos-4; |
| 169 | *((intptr_t*)RelocPos) += ResultPtr; |
| 170 | break; |
| 171 | case X86::reloc_absolute_word: |
| 172 | // Absolute relocation, just add the relocated value to the value already |
| 173 | // in memory. |
| 174 | *((intptr_t*)RelocPos) += ResultPtr; |
| 175 | break; |
| 176 | } |
| 177 | } |
| 178 | } |