github.com/goccy/go-jit@v0.0.0-20200514131505-ff78d45cf6af/internal/ccall/jit-apply-x86.h (about) 1 /* 2 * jit-apply-x86.h - Special definitions for x86 function application. 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 #ifndef _JIT_APPLY_X86_H 24 #define _JIT_APPLY_X86_H 25 26 /* 27 * The "__builtin_apply" functionality in gcc has some problems 28 * dealing with floating-point values, and it also doesn't handle 29 * STDCALL and FASTCALL functions well. Therefore, we use assembly 30 * code instead. 31 * 32 * There are three versions here: gcc/non-Win32, gcc/Win32, and msvc/Win32. 33 * Cygwin is included in the gcc/Win32 case. 34 */ 35 36 #if defined(__GNUC__) 37 38 #if !defined(__CYGWIN__) && !defined(_WIN32) && !defined(WIN32) 39 40 /* Mac OS X prefixes static symbols with an underscore, and external symbol 41 references are late-bound through a PIC stub by the dynamic linker */ 42 #ifndef JIT_MEMCPY 43 # if defined(__APPLE__) && defined(__MACH__) 44 # define JIT_MEMCPY "L_memcpy$stub" 45 # else 46 # define JIT_MEMCPY "memcpy@PLT" 47 # endif 48 #endif 49 50 #define jit_builtin_apply(func,args,size,return_float,return_buf) \ 51 do { \ 52 void *__func = (void *)(func); \ 53 void *__args = (void *)(args); \ 54 void *__size = (void *)(size); \ 55 void *__return_buf = alloca(20); \ 56 (return_buf) = __return_buf; \ 57 __asm__ ( \ 58 "pushl %%esi\n\t" \ 59 "movl %%esp, %%esi\n\t" \ 60 "subl %2, %%esp\n\t" \ 61 "movl %%esp, %%eax\n\t" \ 62 "movl %1, %%ecx\n\t" \ 63 "movl (%%ecx), %%ecx\n\t" \ 64 "pushl %2\n\t" \ 65 "pushl %%ecx\n\t" \ 66 "pushl %%eax\n\t" \ 67 "call " JIT_MEMCPY "\n\t" \ 68 "addl $12, %%esp\n\t" \ 69 "movl %1, %%ecx\n\t" \ 70 "movl %0, %%eax\n\t" \ 71 "call *%%eax\n\t" \ 72 "movl %3, %%ecx\n\t" \ 73 "movl %%eax, (%%ecx)\n\t" \ 74 "movl %%edx, 4(%%ecx)\n\t" \ 75 "movl %%esi, %%esp\n\t" \ 76 "popl %%esi\n\t" \ 77 : : "m"(__func), "m"(__args), "m"(__size), "m"(__return_buf) \ 78 : "eax", "ecx", "edx" \ 79 ); \ 80 if((return_float)) \ 81 { \ 82 if(sizeof(jit_nfloat) == sizeof(double)) \ 83 { \ 84 __asm__ ( \ 85 "movl %0, %%ecx\n\t" \ 86 "fstpl 8(%%ecx)\n\t" \ 87 : : "m"(__return_buf) \ 88 : "ecx", "st" \ 89 ); \ 90 } \ 91 else \ 92 { \ 93 __asm__ ( \ 94 "movl %0, %%ecx\n\t" \ 95 "fstpt 8(%%ecx)\n\t" \ 96 : : "m"(__return_buf) \ 97 : "ecx", "st" \ 98 ); \ 99 } \ 100 } \ 101 } while (0) 102 103 #define jit_builtin_apply_args(type,args) \ 104 do { \ 105 void *__args = alloca(4); \ 106 __asm__ ( \ 107 "leal 8(%%ebp), %%eax\n\t" \ 108 "movl %0, %%ecx\n\t" \ 109 "movl %%eax, (%%ecx)\n\t" \ 110 : : "m"(__args) \ 111 : "eax", "ecx" \ 112 ); \ 113 (args) = (type)__args; \ 114 } while (0) 115 116 #define jit_builtin_return_int(return_buf) \ 117 do { \ 118 __asm__ ( \ 119 "leal %0, %%ecx\n\t" \ 120 "movl (%%ecx), %%eax\n\t" \ 121 "movl 4(%%ecx), %%edx\n\t" \ 122 : : "m"(*(return_buf)) \ 123 : "eax", "ecx", "edx" \ 124 ); \ 125 return; \ 126 } while (0) 127 128 #define jit_builtin_return_float(return_buf) \ 129 do { \ 130 jit_nfloat __value = \ 131 ((jit_apply_return *)(return_buf))-> \ 132 nfloat_value.f_value; \ 133 if(sizeof(jit_nfloat) == sizeof(double)) \ 134 { \ 135 __asm__ ( \ 136 "leal %0, %%ecx\n\t" \ 137 "fldl (%%ecx)\n\t" \ 138 : : "m"(__value) \ 139 : "ecx", "st" \ 140 ); \ 141 } \ 142 else \ 143 { \ 144 __asm__ ( \ 145 "leal %0, %%ecx\n\t" \ 146 "fldt (%%ecx)\n\t" \ 147 : : "m"(__value) \ 148 : "ecx", "st" \ 149 ); \ 150 } \ 151 return; \ 152 } while (0) 153 154 #else /* Win32 */ 155 156 #define jit_builtin_apply(func,args,size,return_float,return_buf) \ 157 do { \ 158 void *__func = (void *)(func); \ 159 void *__args = (void *)(args); \ 160 void *__size = (void *)(size); \ 161 void *__return_buf = alloca(20); \ 162 (return_buf) = __return_buf; \ 163 __asm__ ( \ 164 "pushl %%esi\n\t" \ 165 "movl %%esp, %%esi\n\t" \ 166 "subl %2, %%esp\n\t" \ 167 "movl %%esp, %%eax\n\t" \ 168 "movl %1, %%ecx\n\t" \ 169 "movl (%%ecx), %%ecx\n\t" \ 170 "pushl %2\n\t" \ 171 "pushl %%ecx\n\t" \ 172 "pushl %%eax\n\t" \ 173 "call _memcpy\n\t" \ 174 "addl $12, %%esp\n\t" \ 175 "movl %1, %%ecx\n\t" \ 176 "movl 8(%%ecx), %%edx\n\t" \ 177 "movl 4(%%ecx), %%ecx\n\t" \ 178 "movl %0, %%eax\n\t" \ 179 "call *%%eax\n\t" \ 180 "movl %3, %%ecx\n\t" \ 181 "movl %%eax, (%%ecx)\n\t" \ 182 "movl %%edx, 4(%%ecx)\n\t" \ 183 "movl %%esi, %%esp\n\t" \ 184 "popl %%esi\n\t" \ 185 : : "m"(__func), "m"(__args), "m"(__size), "m"(__return_buf) \ 186 : "eax", "ecx", "edx" \ 187 ); \ 188 if((return_float)) \ 189 { \ 190 if(sizeof(jit_nfloat) == sizeof(double)) \ 191 { \ 192 __asm__ ( \ 193 "movl %0, %%ecx\n\t" \ 194 "fstpl 8(%%ecx)\n\t" \ 195 : : "m"(__return_buf) \ 196 : "ecx", "st" \ 197 ); \ 198 } \ 199 else \ 200 { \ 201 __asm__ ( \ 202 "movl %0, %%ecx\n\t" \ 203 "fstpt 8(%%ecx)\n\t" \ 204 : : "m"(__return_buf) \ 205 : "ecx", "st" \ 206 ); \ 207 } \ 208 } \ 209 } while (0) 210 211 #define jit_builtin_apply_args(type,args) \ 212 do { \ 213 void *__args = alloca(12); \ 214 __asm__ ( \ 215 "movl %0, %%eax\n\t" \ 216 "movl %%ecx, 4(%%eax)\n\t" \ 217 "movl %%edx, 8(%%eax)\n\t" \ 218 "leal 8(%%ebp), %%ecx\n\t" \ 219 "movl %%ecx, (%%eax)\n\t" \ 220 : : "m"(__args) \ 221 : "eax", "ecx", "edx" \ 222 ); \ 223 (args) = (type)__args; \ 224 } while (0) 225 226 #define jit_builtin_return_int(return_buf) \ 227 do { \ 228 __asm__ ( \ 229 "leal %0, %%ecx\n\t" \ 230 "movl (%%ecx), %%eax\n\t" \ 231 "movl 4(%%ecx), %%edx\n\t" \ 232 : : "m"(*(return_buf)) \ 233 : "eax", "ecx", "edx" \ 234 ); \ 235 return; \ 236 } while (0) 237 238 #define jit_builtin_return_float(return_buf) \ 239 do { \ 240 jit_nfloat __value = \ 241 ((jit_apply_return *)(return_buf))-> \ 242 nfloat_value.f_value; \ 243 if(sizeof(jit_nfloat) == sizeof(double)) \ 244 { \ 245 __asm__ ( \ 246 "leal %0, %%ecx\n\t" \ 247 "fldl (%%ecx)\n\t" \ 248 : : "m"(__value) \ 249 : "ecx", "st" \ 250 ); \ 251 } \ 252 else \ 253 { \ 254 __asm__ ( \ 255 "leal %0, %%ecx\n\t" \ 256 "fldt (%%ecx)\n\t" \ 257 : : "m"(__value) \ 258 : "ecx", "st" \ 259 ); \ 260 } \ 261 return; \ 262 } while (0) 263 264 #endif /* Win32 */ 265 266 #elif defined(_MSC_VER) 267 268 #define jit_builtin_apply(func,args,size,return_float,return_buf) \ 269 do { \ 270 void *__func = (void *)(func); \ 271 void *__args = (void *)(args); \ 272 void *__size = (void *)(size); \ 273 void *__return_buf = alloca(20); \ 274 (return_buf) = __return_buf; \ 275 __asm { \ 276 __asm push esi \ 277 __asm mov esi, esp \ 278 __asm sub esp, dword ptr __size \ 279 __asm mov eax, esp \ 280 __asm mov ecx, dword ptr __args \ 281 __asm mov ecx, [ecx] \ 282 __asm push dword ptr __size \ 283 __asm push ecx \ 284 __asm push eax \ 285 __asm call jit_memcpy \ 286 __asm add esp, 12 \ 287 __asm mov ecx, dword ptr __args \ 288 __asm mov edx, [ecx + 8] \ 289 __asm mov ecx, [ecx + 4] \ 290 __asm mov eax, dword ptr __func \ 291 __asm call eax \ 292 __asm mov ecx, dword ptr __return_buf \ 293 __asm mov [ecx], eax \ 294 __asm mov [ecx + 4], edx \ 295 __asm mov esp, esi \ 296 __asm pop esi \ 297 } \ 298 if((return_float)) \ 299 { \ 300 __asm { \ 301 __asm mov ecx, dword ptr __return_buf \ 302 /*__asm fstpl [ecx + 8]*/ \ 303 __asm _emit 0xDD \ 304 __asm _emit 0x59 \ 305 __asm _emit 0x08 \ 306 } \ 307 } \ 308 } while (0) 309 310 #define jit_builtin_apply_args(type,args) \ 311 do { \ 312 void *__args = alloca(12); \ 313 __asm { \ 314 __asm mov eax, dword ptr __args \ 315 __asm mov [eax + 4], ecx \ 316 __asm mov [eax + 8], edx \ 317 __asm lea ecx, [ebp + 8] \ 318 __asm mov [eax], ecx \ 319 } \ 320 (args) = (type)(__args); \ 321 } while (0) 322 323 #define jit_builtin_return_int(return_buf) \ 324 do { \ 325 void *__return_buf = (void *)(return_buf); \ 326 __asm { \ 327 __asm mov ecx, dword ptr __return_buf \ 328 __asm mov eax, [ecx] \ 329 __asm mov edx, [ecx + 4] \ 330 } \ 331 return; \ 332 } while (0) 333 334 #define jit_builtin_return_float(return_buf) \ 335 do { \ 336 double __dvalue = \ 337 ((jit_apply_return *)(return_buf))-> \ 338 nfloat_value.f_value; \ 339 __asm { \ 340 __asm lea ecx, dword ptr __dvalue \ 341 /* __asm fldl [ecx] */ \ 342 __asm _emit 0xDD \ 343 __asm _emit 0x01 \ 344 } \ 345 return; \ 346 } while (0) 347 348 #endif /* MSC_VER */ 349 350 #define jit_builtin_return_double(return_buf) \ 351 jit_builtin_return_float((return_buf)) 352 353 #define jit_builtin_return_nfloat(return_buf) \ 354 jit_builtin_return_float((return_buf)) 355 356 /* 357 * The maximum number of bytes that are needed to represent a closure, 358 * and the alignment to use for the closure. 359 */ 360 #define jit_closure_size 64 361 #define jit_closure_align 32 362 363 /* 364 * The number of bytes that are needed for a redirector stub. 365 * This includes any extra bytes that are needed for alignment. 366 */ 367 #define jit_redirector_size 24 368 369 /* 370 * The number of bytes that are needed for a indirector stub. 371 * This includes any extra bytes that are needed for alignment. 372 */ 373 #define jit_indirector_size 8 374 375 /* 376 * We should pad unused code space with NOP's. 377 */ 378 #define jit_should_pad 1 379 380 #endif /* _JIT_APPLY_X86_H */