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 */