mirror of https://github.com/ademakov/libjit
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
254 lines
5.8 KiB
254 lines
5.8 KiB
/*
|
|
* jit-apply-x86.c - Apply support routines for x86.
|
|
*
|
|
* Copyright (C) 2004 Southern Storm Software, Pty Ltd.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#include "jit-internal.h"
|
|
#include "jit-apply-rules.h"
|
|
#include "jit-apply-func.h"
|
|
|
|
#if defined(__i386) || defined(__i386__) || defined(_M_IX86)
|
|
|
|
#include "jit-gen-x86.h"
|
|
|
|
void _jit_create_closure(unsigned char *buf, void *func,
|
|
void *closure, void *_type)
|
|
{
|
|
jit_type_t signature = (jit_type_t)_type;
|
|
jit_type_t type;
|
|
#if JIT_APPLY_X86_FASTCALL == 1
|
|
jit_abi_t abi = jit_type_get_abi(signature);
|
|
#endif
|
|
unsigned int num_bytes = 0;
|
|
int struct_return_offset = 0;
|
|
|
|
/* Set up the local stack frame */
|
|
x86_push_reg(buf, X86_EBP);
|
|
x86_mov_reg_reg(buf, X86_EBP, X86_ESP, 4);
|
|
|
|
/* Create the apply argument block on the stack */
|
|
#if JIT_APPLY_X86_FASTCALL == 1
|
|
if(abi == jit_abi_fastcall)
|
|
{
|
|
x86_push_reg(buf, X86_EDX);
|
|
x86_push_reg(buf, X86_ECX);
|
|
}
|
|
#endif
|
|
x86_lea_membase(buf, X86_EAX, X86_EBP, 8);
|
|
x86_push_reg(buf, X86_EAX);
|
|
|
|
/* Push the arguments for calling "func" */
|
|
x86_mov_reg_reg(buf, X86_EAX, X86_ESP, 4);
|
|
x86_push_reg(buf, X86_EAX);
|
|
x86_push_imm(buf, (int)closure);
|
|
|
|
/* Call the closure handling function */
|
|
x86_call_code(buf, func);
|
|
|
|
/* Determine the number of bytes to pop when we return */
|
|
#if JIT_APPLY_X86_FASTCALL == 1
|
|
if(abi == jit_abi_stdcall || abi == jit_abi_fastcall)
|
|
{
|
|
unsigned int word_regs;
|
|
unsigned int size;
|
|
unsigned int num_params;
|
|
unsigned int param;
|
|
if(abi == jit_abi_stdcall)
|
|
{
|
|
word_regs = 0;
|
|
}
|
|
else
|
|
{
|
|
word_regs = 2;
|
|
}
|
|
type = jit_type_normalize(jit_type_get_return(signature));
|
|
if(jit_type_return_via_pointer(type))
|
|
{
|
|
if(word_regs > 0)
|
|
{
|
|
--word_regs;
|
|
}
|
|
else
|
|
{
|
|
num_bytes += sizeof(void *);
|
|
struct_return_offset = 2 * sizeof(void *);
|
|
}
|
|
}
|
|
num_params = jit_type_num_params(signature);
|
|
for(param = 0; param < num_params; ++param)
|
|
{
|
|
type = jit_type_normalize(jit_type_get_param(signature, param));
|
|
size = jit_type_get_size(type);
|
|
if(word_regs > 0)
|
|
{
|
|
switch(type->kind)
|
|
{
|
|
case JIT_TYPE_SBYTE:
|
|
case JIT_TYPE_UBYTE:
|
|
case JIT_TYPE_SHORT:
|
|
case JIT_TYPE_USHORT:
|
|
case JIT_TYPE_INT:
|
|
case JIT_TYPE_UINT:
|
|
case JIT_TYPE_NINT:
|
|
case JIT_TYPE_NUINT:
|
|
case JIT_TYPE_SIGNATURE:
|
|
case JIT_TYPE_PTR:
|
|
{
|
|
--word_regs;
|
|
}
|
|
continue;
|
|
|
|
case JIT_TYPE_LONG:
|
|
case JIT_TYPE_ULONG:
|
|
{
|
|
if(word_regs == 1)
|
|
{
|
|
num_bytes += sizeof(void *);
|
|
}
|
|
word_regs = 0;
|
|
}
|
|
continue;
|
|
}
|
|
word_regs = 0;
|
|
}
|
|
num_bytes += (size + sizeof(void *) - 1) & ~(sizeof(void *) - 1);
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
type = jit_type_normalize(jit_type_get_return(signature));
|
|
if(jit_type_return_via_pointer(type))
|
|
{
|
|
#if JIT_APPLY_X86_POP_STRUCT_RETURN == 1
|
|
/* Pop the structure return pointer as we return back */
|
|
num_bytes += sizeof(void *);
|
|
#endif
|
|
struct_return_offset = 2 * sizeof(void *);
|
|
}
|
|
}
|
|
|
|
/* If we are returning a structure via a pointer, then load
|
|
the address of the structure into the EAX register */
|
|
if(struct_return_offset != 0)
|
|
{
|
|
x86_mov_reg_membase(buf, X86_EAX, X86_EBP, struct_return_offset, 4);
|
|
}
|
|
|
|
/* Pop the current stack frame */
|
|
x86_mov_reg_reg(buf, X86_ESP, X86_EBP, 4);
|
|
x86_pop_reg(buf, X86_EBP);
|
|
|
|
/* Return from the closure */
|
|
if(num_bytes > 0)
|
|
{
|
|
x86_ret_imm(buf, num_bytes);
|
|
}
|
|
else
|
|
{
|
|
x86_ret(buf);
|
|
}
|
|
}
|
|
|
|
void *_jit_create_redirector(unsigned char *buf, void *func,
|
|
void *user_data, int abi)
|
|
{
|
|
void *start = (void *)buf;
|
|
|
|
/* Set up a new stack frame */
|
|
x86_push_reg(buf, X86_EBP);
|
|
x86_mov_reg_reg(buf, X86_EBP, X86_ESP, 4);
|
|
|
|
/* Save the fastcall registers, if necessary */
|
|
#if JIT_APPLY_X86_FASTCALL == 1
|
|
if(abi == (int)jit_abi_fastcall)
|
|
{
|
|
x86_push_reg(buf, X86_EDX);
|
|
x86_push_reg(buf, X86_ECX);
|
|
}
|
|
#endif
|
|
|
|
/* Push the user data onto the stack */
|
|
x86_push_imm(buf, (int)user_data);
|
|
|
|
/* Call "func" (the pointer result will be in EAX) */
|
|
x86_call_code(buf, func);
|
|
|
|
/* Remove the user data from the stack */
|
|
x86_pop_reg(buf, X86_ECX);
|
|
|
|
/* Restore the fastcall registers, if necessary */
|
|
#if JIT_APPLY_X86_FASTCALL == 1
|
|
if(abi == (int)jit_abi_fastcall)
|
|
{
|
|
x86_pop_reg(buf, X86_ECX);
|
|
x86_pop_reg(buf, X86_EDX);
|
|
}
|
|
#endif
|
|
|
|
/* Restore the value of EBP */
|
|
x86_pop_reg(buf, X86_EBP);
|
|
|
|
/* Jump to the function that the redirector indicated */
|
|
x86_jump_reg(buf, X86_EAX);
|
|
|
|
/* Return the start of the buffer as the redirector entry point */
|
|
return start;
|
|
}
|
|
|
|
void *_jit_create_indirector(unsigned char *buf, void **entry)
|
|
{
|
|
void *start = (void *)buf;
|
|
|
|
/* Jump to the entry point. */
|
|
x86_jump_mem(buf, entry);
|
|
|
|
return start;
|
|
}
|
|
|
|
void _jit_pad_buffer(unsigned char *buf, int len)
|
|
{
|
|
while(len >= 6)
|
|
{
|
|
/* "leal 0(%esi), %esi" with 32-bit displacement */
|
|
*buf++ = (unsigned char)0x8D;
|
|
x86_address_byte(buf, 2, X86_ESI, X86_ESI);
|
|
x86_imm_emit32(buf, 0);
|
|
len -= 6;
|
|
}
|
|
if(len >= 3)
|
|
{
|
|
/* "leal 0(%esi), %esi" with 8-bit displacement */
|
|
*buf++ = (unsigned char)0x8D;
|
|
x86_address_byte(buf, 1, X86_ESI, X86_ESI);
|
|
x86_imm_emit8(buf, 0);
|
|
len -= 3;
|
|
}
|
|
if(len == 1)
|
|
{
|
|
/* Traditional x86 NOP */
|
|
x86_nop(buf);
|
|
}
|
|
else if(len == 2)
|
|
{
|
|
/* movl %esi, %esi */
|
|
x86_mov_reg_reg(buf, X86_ESI, X86_ESI, 4);
|
|
}
|
|
}
|
|
|
|
#endif /* x86 */
|
|
|