github.com/goccy/go-jit@v0.0.0-20200514131505-ff78d45cf6af/internal/ccall/jit-apply-x86.c (about)

     1  /*
     2   * jit-apply-x86.c - Apply support routines for x86.
     3   *
     4   * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
     5   *
     6   * This file is part of the libjit library.
     7   *
     8   * The libjit library is free software: you can redistribute it and/or
     9   * modify it under the terms of the GNU Lesser General Public License
    10   * as published by the Free Software Foundation, either version 2.1 of
    11   * the License, or (at your option) any later version.
    12   *
    13   * The libjit library is distributed in the hope that it will be useful,
    14   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    15   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    16   * Lesser General Public License for more details.
    17   *
    18   * You should have received a copy of the GNU Lesser General Public
    19   * License along with the libjit library.  If not, see
    20   * <http://www.gnu.org/licenses/>.
    21   */
    22  
    23  #include "jit-internal.h"
    24  #include "jit-apply-rules.h"
    25  #include "jit-apply-func.h"
    26  
    27  #if defined(__i386) || defined(__i386__) || defined(_M_IX86)
    28  
    29  #include "jit-gen-x86.h"
    30  
    31  void _jit_create_closure(unsigned char *buf, void *func,
    32                           void *closure, void *_type)
    33  {
    34  	jit_type_t signature = (jit_type_t)_type;
    35  	jit_type_t type;
    36  #if JIT_APPLY_X86_FASTCALL == 1
    37  	jit_abi_t abi = jit_type_get_abi(signature);
    38  #endif
    39  	unsigned int num_bytes = 0;
    40  	int struct_return_offset = 0;
    41  
    42  	/* Set up the local stack frame */
    43  	x86_push_reg(buf, X86_EBP);
    44  	x86_mov_reg_reg(buf, X86_EBP, X86_ESP, 4);
    45  
    46  	/* Create the apply argument block on the stack */
    47  #if JIT_APPLY_X86_FASTCALL == 1
    48  	if(abi == jit_abi_fastcall)
    49  	{
    50  		x86_push_reg(buf, X86_EDX);
    51  		x86_push_reg(buf, X86_ECX);
    52  	}
    53  #endif
    54  	x86_lea_membase(buf, X86_EAX, X86_EBP, 8);
    55  	x86_push_reg(buf, X86_EAX);
    56  
    57  	/* Push the arguments for calling "func" */
    58  	x86_mov_reg_reg(buf, X86_EAX, X86_ESP, 4);
    59  	x86_push_reg(buf, X86_EAX);
    60  	x86_push_imm(buf, (int)closure);
    61  
    62  	/* Call the closure handling function */
    63  	x86_call_code(buf, func);
    64  
    65  	/* Determine the number of bytes to pop when we return */
    66  #if JIT_APPLY_X86_FASTCALL == 1
    67  	if(abi == jit_abi_stdcall || abi == jit_abi_fastcall)
    68  	{
    69  		unsigned int word_regs;
    70  		unsigned int size;
    71  		unsigned int num_params;
    72  		unsigned int param;
    73  		if(abi == jit_abi_stdcall)
    74  		{
    75  			word_regs = 0;
    76  		}
    77  		else
    78  		{
    79  			word_regs = 2;
    80  		}
    81  		type = jit_type_normalize(jit_type_get_return(signature));
    82  		if(jit_type_return_via_pointer(type))
    83  		{
    84  			if(word_regs > 0)
    85  			{
    86  				--word_regs;
    87  			}
    88  			else
    89  			{
    90  				num_bytes += sizeof(void *);
    91  				struct_return_offset = 2 * sizeof(void *);
    92  			}
    93  		}
    94  		num_params = jit_type_num_params(signature);
    95  		for(param = 0; param < num_params; ++param)
    96  		{
    97  			type = jit_type_normalize(jit_type_get_param(signature, param));
    98  			size = jit_type_get_size(type);
    99  			if(word_regs > 0)
   100  			{
   101  				switch(type->kind)
   102  				{
   103  					case JIT_TYPE_SBYTE:
   104  					case JIT_TYPE_UBYTE:
   105  					case JIT_TYPE_SHORT:
   106  					case JIT_TYPE_USHORT:
   107  					case JIT_TYPE_INT:
   108  					case JIT_TYPE_UINT:
   109  					case JIT_TYPE_NINT:
   110  					case JIT_TYPE_NUINT:
   111  					case JIT_TYPE_SIGNATURE:
   112  					case JIT_TYPE_PTR:
   113  					{
   114  						--word_regs;
   115  					}
   116  					continue;
   117  
   118  					case JIT_TYPE_LONG:
   119  					case JIT_TYPE_ULONG:
   120  					{
   121  						if(word_regs == 1)
   122  						{
   123  							num_bytes += sizeof(void *);
   124  						}
   125  						word_regs = 0;
   126  					}
   127  					continue;
   128  				}
   129  				word_regs = 0;
   130  			}
   131  			num_bytes += (size + sizeof(void *) - 1) & ~(sizeof(void *) - 1);
   132  		}
   133  	}
   134  	else
   135  #endif
   136  	{
   137  		type = jit_type_normalize(jit_type_get_return(signature));
   138  		if(jit_type_return_via_pointer(type))
   139  		{
   140  #if JIT_APPLY_X86_POP_STRUCT_RETURN == 1
   141  			/* Pop the structure return pointer as we return back */
   142  			num_bytes += sizeof(void *);
   143  #endif
   144  			struct_return_offset = 2 * sizeof(void *);
   145  		}
   146  	}
   147  
   148  	/* If we are returning a structure via a pointer, then load
   149  	   the address of the structure into the EAX register */
   150  	if(struct_return_offset != 0)
   151  	{
   152  		x86_mov_reg_membase(buf, X86_EAX, X86_EBP, struct_return_offset, 4);
   153  	}
   154  
   155  	/* Pop the current stack frame */
   156  	x86_mov_reg_reg(buf, X86_ESP, X86_EBP, 4);
   157  	x86_pop_reg(buf, X86_EBP);
   158  
   159  	/* Return from the closure */
   160  	if(num_bytes > 0)
   161  	{
   162  		x86_ret_imm(buf, num_bytes);
   163  	}
   164  	else
   165  	{
   166  		x86_ret(buf);
   167  	}
   168  }
   169  
   170  void *_jit_create_redirector(unsigned char *buf, void *func,
   171  							 void *user_data, int abi)
   172  {
   173  	void *start = (void *)buf;
   174  
   175  	/* Save the fastcall registers, if necessary */
   176  #if JIT_APPLY_X86_FASTCALL == 1
   177  	if(abi == (int)jit_abi_fastcall)
   178  	{
   179  		x86_push_reg(buf, X86_EDX);
   180  		x86_push_reg(buf, X86_ECX);
   181  	}
   182  #endif
   183  
   184  	/* Push the user data onto the stack */
   185  	x86_push_imm(buf, (int)user_data);
   186  
   187  	/* Call "func" (the pointer result will be in EAX) */
   188  	x86_call_code(buf, func);
   189  
   190  	/* Remove the user data from the stack */
   191  	x86_pop_reg(buf, X86_ECX);
   192  
   193  	/* Restore the fastcall registers, if necessary */
   194  #if JIT_APPLY_X86_FASTCALL == 1
   195  	if(abi == (int)jit_abi_fastcall)
   196  	{
   197  		x86_pop_reg(buf, X86_ECX);
   198  		x86_pop_reg(buf, X86_EDX);
   199  	}
   200  #endif
   201  
   202  	/* Jump to the function that the redirector indicated */
   203  	x86_jump_reg(buf, X86_EAX);
   204  
   205  	/* Return the start of the buffer as the redirector entry point */
   206  	return start;
   207  }
   208  
   209  void *_jit_create_indirector(unsigned char *buf, void **entry)
   210  {
   211  	void *start = (void *)buf;
   212  
   213  	/* Jump to the entry point. */
   214  	x86_jump_mem(buf, entry);
   215  
   216  	return start;
   217  }
   218  
   219  void _jit_pad_buffer(unsigned char *buf, int len)
   220  {
   221  	while(len >= 6)
   222  	{
   223  		/* "leal 0(%esi), %esi" with 32-bit displacement */
   224  		*buf++ = (unsigned char)0x8D;
   225  		x86_address_byte(buf, 2, X86_ESI, X86_ESI);
   226  		x86_imm_emit32(buf, 0);
   227  		len -= 6;
   228  	}
   229  	if(len >= 3)
   230  	{
   231  		/* "leal 0(%esi), %esi" with 8-bit displacement */
   232  		*buf++ = (unsigned char)0x8D;
   233  		x86_address_byte(buf, 1, X86_ESI, X86_ESI);
   234  		x86_imm_emit8(buf, 0);
   235  		len -= 3;
   236  	}
   237  	if(len == 1)
   238  	{
   239  		/* Traditional x86 NOP */
   240  		x86_nop(buf);
   241  	}
   242  	else if(len == 2)
   243  	{
   244  		/* movl %esi, %esi */
   245  		x86_mov_reg_reg(buf, X86_ESI, X86_ESI, 4);
   246  	}
   247  }
   248  
   249  #endif /* x86 */