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" |
Nate Begeman | be13634 | 2005-05-20 21:29:24 +0000 | [diff] [blame] | 19 | #include <cstdlib> |
| 20 | #include <iostream> |
Chris Lattner | 7ddde32 | 2004-11-20 23:54:33 +0000 | [diff] [blame] | 21 | using namespace llvm; |
| 22 | |
Chris Lattner | 38f7373 | 2006-01-26 19:55:20 +0000 | [diff] [blame] | 23 | #ifdef _MSC_VER |
| 24 | extern "C" void *_AddressOfReturnAddress(void); |
| 25 | #pragma intrinsic(_AddressOfReturnAddress) |
| 26 | #endif |
| 27 | |
Chris Lattner | 7ddde32 | 2004-11-20 23:54:33 +0000 | [diff] [blame] | 28 | void X86JITInfo::replaceMachineCodeForFunction(void *Old, void *New) { |
| 29 | unsigned char *OldByte = (unsigned char *)Old; |
| 30 | *OldByte++ = 0xE9; // Emit JMP opcode. |
| 31 | unsigned *OldWord = (unsigned *)OldByte; |
| 32 | unsigned NewAddr = (intptr_t)New; |
| 33 | unsigned OldAddr = (intptr_t)OldWord; |
| 34 | *OldWord = NewAddr - OldAddr - 4; // Emit PC-relative addr of New code. |
| 35 | } |
| 36 | |
| 37 | |
Chris Lattner | 7ddde32 | 2004-11-20 23:54:33 +0000 | [diff] [blame] | 38 | /// JITCompilerFunction - This contains the address of the JIT function used to |
| 39 | /// compile a function lazily. |
| 40 | static TargetJITInfo::JITCompilerFn JITCompilerFunction; |
| 41 | |
Chris Lattner | 1030f72 | 2005-05-19 06:49:17 +0000 | [diff] [blame] | 42 | // Provide a wrapper for X86CompilationCallback2 that saves non-traditional |
| 43 | // callee saved registers, for the fastcc calling convention. |
Jeff Cohen | 8bc6f93 | 2005-05-20 01:35:39 +0000 | [diff] [blame] | 44 | extern "C" { |
| 45 | #if defined(__i386__) || defined(i386) || defined(_M_IX86) |
Chris Lattner | 1030f72 | 2005-05-19 06:49:17 +0000 | [diff] [blame] | 46 | #ifndef _MSC_VER |
Jeff Cohen | 8bc6f93 | 2005-05-20 01:35:39 +0000 | [diff] [blame] | 47 | void X86CompilationCallback(void); |
| 48 | asm( |
| 49 | ".text\n" |
| 50 | ".align 8\n" |
Jeff Cohen | 10a59ce | 2006-04-29 18:41:44 +0000 | [diff] [blame] | 51 | #if defined(__CYGWIN__) || defined(__APPLE__) || defined(__MINGW32__) |
Reid Spencer | 628214e | 2005-06-02 21:33:19 +0000 | [diff] [blame] | 52 | ".globl _X86CompilationCallback\n" |
| 53 | "_X86CompilationCallback:\n" |
| 54 | #else |
Jeff Cohen | 8bc6f93 | 2005-05-20 01:35:39 +0000 | [diff] [blame] | 55 | ".globl X86CompilationCallback\n" |
| 56 | "X86CompilationCallback:\n" |
Reid Spencer | 628214e | 2005-06-02 21:33:19 +0000 | [diff] [blame] | 57 | #endif |
Jeff Cohen | 8bc6f93 | 2005-05-20 01:35:39 +0000 | [diff] [blame] | 58 | "pushl %ebp\n" |
| 59 | "movl %esp, %ebp\n" // Standard prologue |
| 60 | "pushl %eax\n" |
| 61 | "pushl %edx\n" // save EAX/EDX |
Jeff Cohen | 10a59ce | 2006-04-29 18:41:44 +0000 | [diff] [blame] | 62 | #if defined(__CYGWIN__) || defined(__MINGW32__) |
Nate Begeman | add19dc | 2006-04-25 20:54:26 +0000 | [diff] [blame] | 63 | "call _X86CompilationCallback2\n" |
| 64 | #elif defined(__APPLE__) |
| 65 | "movl 4(%ebp), %eax\n" // load the address of return address |
| 66 | "movl $24, %edx\n" // if the opcode of the instruction at the |
| 67 | "cmpb $-51, (%eax)\n" // return address is our 0xCD marker, then |
| 68 | "movl $12, %eax\n" // subtract 24 from %esp to realign it to 16 |
| 69 | "cmovne %eax, %edx\n" // bytes after the push of edx, the amount to. |
| 70 | "subl %edx, %esp\n" // the push of edx to keep it aligned. |
| 71 | "pushl %edx\n" // subtract. Otherwise, subtract 12 bytes after |
| 72 | "call _X86CompilationCallback2\n" |
| 73 | "popl %edx\n" |
| 74 | "addl %edx, %esp\n" |
Reid Spencer | 628214e | 2005-06-02 21:33:19 +0000 | [diff] [blame] | 75 | #else |
Jeff Cohen | 8bc6f93 | 2005-05-20 01:35:39 +0000 | [diff] [blame] | 76 | "call X86CompilationCallback2\n" |
Reid Spencer | 628214e | 2005-06-02 21:33:19 +0000 | [diff] [blame] | 77 | #endif |
Jeff Cohen | 8bc6f93 | 2005-05-20 01:35:39 +0000 | [diff] [blame] | 78 | "popl %edx\n" |
| 79 | "popl %eax\n" |
| 80 | "popl %ebp\n" |
| 81 | "ret\n"); |
Chris Lattner | 1030f72 | 2005-05-19 06:49:17 +0000 | [diff] [blame] | 82 | #else |
Jeff Cohen | 8bc6f93 | 2005-05-20 01:35:39 +0000 | [diff] [blame] | 83 | void X86CompilationCallback2(void); |
| 84 | |
| 85 | _declspec(naked) void X86CompilationCallback(void) { |
| 86 | __asm { |
| 87 | push eax |
| 88 | push edx |
| 89 | call X86CompilationCallback2 |
| 90 | pop edx |
| 91 | pop eax |
| 92 | ret |
| 93 | } |
| 94 | } |
Misha Brukman | 57ebf3d | 2005-05-20 19:46:50 +0000 | [diff] [blame] | 95 | #endif // _MSC_VER |
Chris Lattner | 1030f72 | 2005-05-19 06:49:17 +0000 | [diff] [blame] | 96 | |
Misha Brukman | 57ebf3d | 2005-05-20 19:46:50 +0000 | [diff] [blame] | 97 | #else // Not an i386 host |
Jeff Cohen | 8bc6f93 | 2005-05-20 01:35:39 +0000 | [diff] [blame] | 98 | void X86CompilationCallback() { |
Misha Brukman | 57ebf3d | 2005-05-20 19:46:50 +0000 | [diff] [blame] | 99 | std::cerr << "Cannot call X86CompilationCallback() on a non-x86 arch!\n"; |
Chris Lattner | 170fbcb | 2005-05-20 17:00:21 +0000 | [diff] [blame] | 100 | abort(); |
Jeff Cohen | 8bc6f93 | 2005-05-20 01:35:39 +0000 | [diff] [blame] | 101 | } |
Chris Lattner | 1030f72 | 2005-05-19 06:49:17 +0000 | [diff] [blame] | 102 | #endif |
Jeff Cohen | 8bc6f93 | 2005-05-20 01:35:39 +0000 | [diff] [blame] | 103 | } |
Chris Lattner | 1030f72 | 2005-05-19 06:49:17 +0000 | [diff] [blame] | 104 | |
| 105 | /// X86CompilationCallback - This is the target-specific function invoked by the |
Chris Lattner | 7ddde32 | 2004-11-20 23:54:33 +0000 | [diff] [blame] | 106 | /// function stub when we did not know the real target of a call. This function |
| 107 | /// must locate the start of the stub or call site and pass it into the JIT |
| 108 | /// compiler function. |
Chris Lattner | 1030f72 | 2005-05-19 06:49:17 +0000 | [diff] [blame] | 109 | extern "C" void X86CompilationCallback2() { |
Chris Lattner | 7ddde32 | 2004-11-20 23:54:33 +0000 | [diff] [blame] | 110 | #ifdef _MSC_VER |
Jeff Cohen | 8bc6f93 | 2005-05-20 01:35:39 +0000 | [diff] [blame] | 111 | assert(sizeof(size_t) == 4); // FIXME: handle Win64 |
| 112 | unsigned *RetAddrLoc = (unsigned *)_AddressOfReturnAddress(); |
| 113 | RetAddrLoc += 3; // skip over ret addr, edx, eax |
| 114 | unsigned RetAddr = *RetAddrLoc; |
Chris Lattner | 7ddde32 | 2004-11-20 23:54:33 +0000 | [diff] [blame] | 115 | #else |
Chris Lattner | 1030f72 | 2005-05-19 06:49:17 +0000 | [diff] [blame] | 116 | unsigned *StackPtr = (unsigned*)__builtin_frame_address(1); |
| 117 | unsigned RetAddr = (unsigned)(intptr_t)__builtin_return_address(1); |
Jeff Cohen | 8bc6f93 | 2005-05-20 01:35:39 +0000 | [diff] [blame] | 118 | unsigned *RetAddrLoc = &StackPtr[1]; |
Chris Lattner | 7ddde32 | 2004-11-20 23:54:33 +0000 | [diff] [blame] | 119 | |
| 120 | // NOTE: __builtin_frame_address doesn't work if frame pointer elimination has |
| 121 | // been performed. Having a variable sized alloca disables frame pointer |
| 122 | // elimination currently, even if it's dead. This is a gross hack. |
| 123 | alloca(10+(RetAddr >> 31)); |
Misha Brukman | 0e0a7a45 | 2005-04-21 23:38:14 +0000 | [diff] [blame] | 124 | |
Chris Lattner | 7ddde32 | 2004-11-20 23:54:33 +0000 | [diff] [blame] | 125 | #endif |
Jeff Cohen | 8bc6f93 | 2005-05-20 01:35:39 +0000 | [diff] [blame] | 126 | assert(*RetAddrLoc == RetAddr && |
Chris Lattner | 7ddde32 | 2004-11-20 23:54:33 +0000 | [diff] [blame] | 127 | "Could not find return address on the stack!"); |
| 128 | |
| 129 | // It's a stub if there is an interrupt marker after the call. |
| 130 | bool isStub = ((unsigned char*)(intptr_t)RetAddr)[0] == 0xCD; |
| 131 | |
| 132 | // The call instruction should have pushed the return value onto the stack... |
| 133 | RetAddr -= 4; // Backtrack to the reference itself... |
| 134 | |
| 135 | #if 0 |
| 136 | DEBUG(std::cerr << "In callback! Addr=" << (void*)RetAddr |
| 137 | << " ESP=" << (void*)StackPtr |
| 138 | << ": Resolving call to function: " |
| 139 | << TheVM->getFunctionReferencedName((void*)RetAddr) << "\n"); |
| 140 | #endif |
| 141 | |
| 142 | // Sanity check to make sure this really is a call instruction. |
| 143 | assert(((unsigned char*)(intptr_t)RetAddr)[-1] == 0xE8 &&"Not a call instr!"); |
Misha Brukman | 0e0a7a45 | 2005-04-21 23:38:14 +0000 | [diff] [blame] | 144 | |
Chris Lattner | 7ddde32 | 2004-11-20 23:54:33 +0000 | [diff] [blame] | 145 | unsigned NewVal = (intptr_t)JITCompilerFunction((void*)(intptr_t)RetAddr); |
| 146 | |
| 147 | // Rewrite the call target... so that we don't end up here every time we |
| 148 | // execute the call. |
| 149 | *(unsigned*)(intptr_t)RetAddr = NewVal-RetAddr-4; |
| 150 | |
| 151 | if (isStub) { |
| 152 | // If this is a stub, rewrite the call into an unconditional branch |
| 153 | // instruction so that two return addresses are not pushed onto the stack |
| 154 | // when the requested function finally gets called. This also makes the |
| 155 | // 0xCD byte (interrupt) dead, so the marker doesn't effect anything. |
| 156 | ((unsigned char*)(intptr_t)RetAddr)[-1] = 0xE9; |
| 157 | } |
| 158 | |
| 159 | // Change the return address to reexecute the call instruction... |
Jeff Cohen | 8bc6f93 | 2005-05-20 01:35:39 +0000 | [diff] [blame] | 160 | *RetAddrLoc -= 5; |
Chris Lattner | 7ddde32 | 2004-11-20 23:54:33 +0000 | [diff] [blame] | 161 | } |
| 162 | |
Chris Lattner | 7ddde32 | 2004-11-20 23:54:33 +0000 | [diff] [blame] | 163 | TargetJITInfo::LazyResolverFn |
| 164 | X86JITInfo::getLazyResolverFunction(JITCompilerFn F) { |
| 165 | JITCompilerFunction = F; |
Chris Lattner | 1030f72 | 2005-05-19 06:49:17 +0000 | [diff] [blame] | 166 | return X86CompilationCallback; |
Chris Lattner | 7ddde32 | 2004-11-20 23:54:33 +0000 | [diff] [blame] | 167 | } |
| 168 | |
Chris Lattner | 90b1b45 | 2004-11-22 22:25:30 +0000 | [diff] [blame] | 169 | void *X86JITInfo::emitFunctionStub(void *Fn, MachineCodeEmitter &MCE) { |
Chris Lattner | d74ea2b | 2006-05-24 17:04:05 +0000 | [diff] [blame] | 170 | if (Fn != (void*)X86CompilationCallback) { |
Chris Lattner | 90b1b45 | 2004-11-22 22:25:30 +0000 | [diff] [blame] | 171 | MCE.startFunctionStub(5); |
| 172 | MCE.emitByte(0xE9); |
Chris Lattner | d3f0aef | 2006-05-02 19:14:47 +0000 | [diff] [blame] | 173 | MCE.emitWordLE((intptr_t)Fn-MCE.getCurrentPCValue()-4); |
Chris Lattner | 90b1b45 | 2004-11-22 22:25:30 +0000 | [diff] [blame] | 174 | return MCE.finishFunctionStub(0); |
| 175 | } |
Misha Brukman | 0e0a7a45 | 2005-04-21 23:38:14 +0000 | [diff] [blame] | 176 | |
Chris Lattner | 90b1b45 | 2004-11-22 22:25:30 +0000 | [diff] [blame] | 177 | MCE.startFunctionStub(6); |
| 178 | MCE.emitByte(0xE8); // Call with 32 bit pc-rel destination... |
| 179 | |
Chris Lattner | d3f0aef | 2006-05-02 19:14:47 +0000 | [diff] [blame] | 180 | MCE.emitWordLE((intptr_t)Fn-MCE.getCurrentPCValue()-4); |
Chris Lattner | 90b1b45 | 2004-11-22 22:25:30 +0000 | [diff] [blame] | 181 | |
| 182 | MCE.emitByte(0xCD); // Interrupt - Just a marker identifying the stub! |
| 183 | return MCE.finishFunctionStub(0); |
| 184 | } |
Chris Lattner | 7ddde32 | 2004-11-20 23:54:33 +0000 | [diff] [blame] | 185 | |
| 186 | /// relocate - Before the JIT can run a block of code that has been emitted, |
| 187 | /// it must rewrite the code to contain the actual addresses of any |
| 188 | /// referenced global symbols. |
| 189 | void X86JITInfo::relocate(void *Function, MachineRelocation *MR, |
Andrew Lenharth | 908bc86 | 2005-07-22 20:49:37 +0000 | [diff] [blame] | 190 | unsigned NumRelocs, unsigned char* GOTBase) { |
Chris Lattner | 7ddde32 | 2004-11-20 23:54:33 +0000 | [diff] [blame] | 191 | for (unsigned i = 0; i != NumRelocs; ++i, ++MR) { |
| 192 | void *RelocPos = (char*)Function + MR->getMachineCodeOffset(); |
| 193 | intptr_t ResultPtr = (intptr_t)MR->getResultPointer(); |
| 194 | switch ((X86::RelocationType)MR->getRelocationType()) { |
| 195 | case X86::reloc_pcrel_word: |
| 196 | // PC relative relocation, add the relocated value to the value already in |
| 197 | // memory, after we adjust it for where the PC is. |
| 198 | ResultPtr = ResultPtr-(intptr_t)RelocPos-4; |
| 199 | *((intptr_t*)RelocPos) += ResultPtr; |
| 200 | break; |
| 201 | case X86::reloc_absolute_word: |
| 202 | // Absolute relocation, just add the relocated value to the value already |
| 203 | // in memory. |
| 204 | *((intptr_t*)RelocPos) += ResultPtr; |
| 205 | break; |
| 206 | } |
| 207 | } |
| 208 | } |