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