Chris Lattner | 7ddde32 | 2004-11-20 23:54:33 +0000 | [diff] [blame] | 1 | //===-- X86JITInfo.cpp - Implement the JIT interfaces for the X86 target --===// |
| 2 | // |
| 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. |
| 7 | // |
| 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 | |
| 39 | /// CompilationCallback - This is the target-specific function invoked by the |
| 40 | /// function stub when we did not know the real target of a call. This function |
| 41 | /// must locate the start of the stub or call site and pass it into the JIT |
| 42 | /// compiler function. |
| 43 | static void CompilationCallback() { |
| 44 | #ifdef _MSC_VER |
| 45 | unsigned *StackPtr, RetAddr; |
| 46 | __asm mov StackPtr, ebp; |
| 47 | __asm mov eax, DWORD PTR [ebp + 4]; |
| 48 | __asm mov RetAddr, eax; |
| 49 | #else |
| 50 | unsigned *StackPtr = (unsigned*)__builtin_frame_address(0); |
| 51 | unsigned RetAddr = (unsigned)(intptr_t)__builtin_return_address(0); |
| 52 | |
| 53 | // NOTE: __builtin_frame_address doesn't work if frame pointer elimination has |
| 54 | // been performed. Having a variable sized alloca disables frame pointer |
| 55 | // elimination currently, even if it's dead. This is a gross hack. |
| 56 | alloca(10+(RetAddr >> 31)); |
| 57 | |
| 58 | #endif |
| 59 | assert(StackPtr[1] == RetAddr && |
| 60 | "Could not find return address on the stack!"); |
| 61 | |
| 62 | // It's a stub if there is an interrupt marker after the call. |
| 63 | bool isStub = ((unsigned char*)(intptr_t)RetAddr)[0] == 0xCD; |
| 64 | |
| 65 | // The call instruction should have pushed the return value onto the stack... |
| 66 | RetAddr -= 4; // Backtrack to the reference itself... |
| 67 | |
| 68 | #if 0 |
| 69 | DEBUG(std::cerr << "In callback! Addr=" << (void*)RetAddr |
| 70 | << " ESP=" << (void*)StackPtr |
| 71 | << ": Resolving call to function: " |
| 72 | << TheVM->getFunctionReferencedName((void*)RetAddr) << "\n"); |
| 73 | #endif |
| 74 | |
| 75 | // Sanity check to make sure this really is a call instruction. |
| 76 | assert(((unsigned char*)(intptr_t)RetAddr)[-1] == 0xE8 &&"Not a call instr!"); |
| 77 | |
| 78 | unsigned NewVal = (intptr_t)JITCompilerFunction((void*)(intptr_t)RetAddr); |
| 79 | |
| 80 | // Rewrite the call target... so that we don't end up here every time we |
| 81 | // execute the call. |
| 82 | *(unsigned*)(intptr_t)RetAddr = NewVal-RetAddr-4; |
| 83 | |
| 84 | if (isStub) { |
| 85 | // If this is a stub, rewrite the call into an unconditional branch |
| 86 | // instruction so that two return addresses are not pushed onto the stack |
| 87 | // when the requested function finally gets called. This also makes the |
| 88 | // 0xCD byte (interrupt) dead, so the marker doesn't effect anything. |
| 89 | ((unsigned char*)(intptr_t)RetAddr)[-1] = 0xE9; |
| 90 | } |
| 91 | |
| 92 | // Change the return address to reexecute the call instruction... |
| 93 | StackPtr[1] -= 5; |
| 94 | } |
| 95 | |
| 96 | #ifdef _MSC_VER |
| 97 | #pragma optimize( "", on ) |
| 98 | #endif |
| 99 | |
| 100 | TargetJITInfo::LazyResolverFn |
| 101 | X86JITInfo::getLazyResolverFunction(JITCompilerFn F) { |
| 102 | JITCompilerFunction = F; |
| 103 | return CompilationCallback; |
| 104 | } |
| 105 | |
Chris Lattner | 90b1b45 | 2004-11-22 22:25:30 +0000 | [diff] [blame] | 106 | void *X86JITInfo::emitFunctionStub(void *Fn, MachineCodeEmitter &MCE) { |
| 107 | if (Fn != CompilationCallback) { |
| 108 | MCE.startFunctionStub(5); |
| 109 | MCE.emitByte(0xE9); |
| 110 | MCE.emitWord((intptr_t)Fn-MCE.getCurrentPCValue()-4); |
| 111 | return MCE.finishFunctionStub(0); |
| 112 | } |
| 113 | |
| 114 | MCE.startFunctionStub(6); |
| 115 | MCE.emitByte(0xE8); // Call with 32 bit pc-rel destination... |
| 116 | |
| 117 | MCE.emitWord((intptr_t)Fn-MCE.getCurrentPCValue()-4); |
| 118 | |
| 119 | MCE.emitByte(0xCD); // Interrupt - Just a marker identifying the stub! |
| 120 | return MCE.finishFunctionStub(0); |
| 121 | } |
Chris Lattner | 7ddde32 | 2004-11-20 23:54:33 +0000 | [diff] [blame] | 122 | |
| 123 | /// relocate - Before the JIT can run a block of code that has been emitted, |
| 124 | /// it must rewrite the code to contain the actual addresses of any |
| 125 | /// referenced global symbols. |
| 126 | void X86JITInfo::relocate(void *Function, MachineRelocation *MR, |
| 127 | unsigned NumRelocs) { |
| 128 | for (unsigned i = 0; i != NumRelocs; ++i, ++MR) { |
| 129 | void *RelocPos = (char*)Function + MR->getMachineCodeOffset(); |
| 130 | intptr_t ResultPtr = (intptr_t)MR->getResultPointer(); |
| 131 | switch ((X86::RelocationType)MR->getRelocationType()) { |
| 132 | case X86::reloc_pcrel_word: |
| 133 | // PC relative relocation, add the relocated value to the value already in |
| 134 | // memory, after we adjust it for where the PC is. |
| 135 | ResultPtr = ResultPtr-(intptr_t)RelocPos-4; |
| 136 | *((intptr_t*)RelocPos) += ResultPtr; |
| 137 | break; |
| 138 | case X86::reloc_absolute_word: |
| 139 | // Absolute relocation, just add the relocated value to the value already |
| 140 | // in memory. |
| 141 | *((intptr_t*)RelocPos) += ResultPtr; |
| 142 | break; |
| 143 | } |
| 144 | } |
| 145 | } |