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