1#ifdef __i386__ 2/* ----------------------------------------------------------------------- 3 ffi.c - Copyright (c) 1996, 1998, 1999, 2001 Red Hat, Inc. 4 Copyright (c) 2002 Ranjit Mathew 5 Copyright (c) 2002 Bo Thorsen 6 Copyright (c) 2002 Roger Sayle 7 8 x86 Foreign Function Interface 9 10 Permission is hereby granted, free of charge, to any person obtaining 11 a copy of this software and associated documentation files (the 12 ``Software''), to deal in the Software without restriction, including 13 without limitation the rights to use, copy, modify, merge, publish, 14 distribute, sublicense, and/or sell copies of the Software, and to 15 permit persons to whom the Software is furnished to do so, subject to 16 the following conditions: 17 18 The above copyright notice and this permission notice shall be included 19 in all copies or substantial portions of the Software. 20 21 THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS 22 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 24 IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR 25 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 26 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 OTHER DEALINGS IN THE SOFTWARE. 28 ----------------------------------------------------------------------- */ 29 30//#ifndef __x86_64__ 31 32#include <ffi.h> 33#include <ffi_common.h> 34 35#include <stdlib.h> 36 37//void ffi_prep_args(char *stack, extended_cif *ecif); 38 39static inline int 40retval_on_stack( 41 ffi_type* tp) 42{ 43 if (tp->type == FFI_TYPE_STRUCT) 44 { 45// int size = tp->size; 46 47 if (tp->size > 8) 48 return 1; 49 50 switch (tp->size) 51 { 52 case 1: case 2: case 4: case 8: 53 return 0; 54 default: 55 return 1; 56 } 57 } 58 59 return 0; 60} 61 62/* ffi_prep_args is called by the assembly routine once stack space 63 has been allocated for the function's arguments */ 64/*@-exportheader@*/ 65extern void ffi_prep_args(char*, extended_cif*); 66void 67ffi_prep_args( 68 char* stack, 69 extended_cif* ecif) 70/*@=exportheader@*/ 71{ 72 register unsigned int i; 73 register void** p_argv = ecif->avalue; 74 register char* argp = stack; 75 register ffi_type** p_arg; 76 77 if (retval_on_stack(ecif->cif->rtype)) 78 { 79 *(void**)argp = ecif->rvalue; 80 argp += 4; 81 } 82 83 p_arg = ecif->cif->arg_types; 84 85 for (i = ecif->cif->nargs; i > 0; i--, p_arg++, p_argv++) 86 { 87 size_t z = (*p_arg)->size; 88 89 /* Align if necessary */ 90 if ((sizeof(int) - 1) & (unsigned)argp) 91 argp = (char*)ALIGN(argp, sizeof(int)); 92 93 if (z < sizeof(int)) 94 { 95 z = sizeof(int); 96 97 switch ((*p_arg)->type) 98 { 99 case FFI_TYPE_SINT8: 100 *(signed int*)argp = (signed int)*(SINT8*)(*p_argv); 101 break; 102 103 case FFI_TYPE_UINT8: 104 *(unsigned int*)argp = (unsigned int)*(UINT8*)(*p_argv); 105 break; 106 107 case FFI_TYPE_SINT16: 108 *(signed int*)argp = (signed int)*(SINT16*)(*p_argv); 109 break; 110 111 case FFI_TYPE_UINT16: 112 *(unsigned int*)argp = (unsigned int)*(UINT16*)(*p_argv); 113 break; 114 115 case FFI_TYPE_SINT32: 116 *(signed int*)argp = (signed int)*(SINT32*)(*p_argv); 117 break; 118 119 case FFI_TYPE_UINT32: 120 *(unsigned int*)argp = (unsigned int)*(UINT32*)(*p_argv); 121 break; 122 123 case FFI_TYPE_STRUCT: 124 *(unsigned int*)argp = (unsigned int)*(UINT32*)(*p_argv); 125 break; 126 127 default: 128 FFI_ASSERT(0); 129 break; 130 } 131 } 132 else 133 memcpy(argp, *p_argv, z); 134 135 argp += z; 136 } 137} 138 139/* Perform machine dependent cif processing */ 140ffi_status 141ffi_prep_cif_machdep( 142 ffi_cif* cif) 143{ 144 /* Set the return type flag */ 145 switch (cif->rtype->type) 146 { 147#if !defined(X86_WIN32) && !defined(X86_DARWIN) 148 case FFI_TYPE_STRUCT: 149#endif 150 case FFI_TYPE_VOID: 151 case FFI_TYPE_SINT64: 152 case FFI_TYPE_FLOAT: 153 case FFI_TYPE_DOUBLE: 154 case FFI_TYPE_LONGDOUBLE: 155 cif->flags = (unsigned)cif->rtype->type; 156 break; 157 158 case FFI_TYPE_UINT64: 159 cif->flags = FFI_TYPE_SINT64; 160 break; 161 162#if defined(X86_WIN32) || defined(X86_DARWIN) 163 case FFI_TYPE_STRUCT: 164 switch (cif->rtype->size) 165 { 166 case 1: 167 cif->flags = FFI_TYPE_SINT8; 168 break; 169 170 case 2: 171 cif->flags = FFI_TYPE_SINT16; 172 break; 173 174 case 4: 175 cif->flags = FFI_TYPE_INT; 176 break; 177 178 case 8: 179 cif->flags = FFI_TYPE_SINT64; 180 break; 181 182 default: 183 cif->flags = FFI_TYPE_STRUCT; 184 break; 185 } 186 187 break; 188#endif 189 190 default: 191 cif->flags = FFI_TYPE_INT; 192 break; 193 } 194 195 /* Darwin: The stack needs to be aligned to a multiple of 16 bytes */ 196 cif->bytes = (cif->bytes + 15) & ~0xF; 197 198 return FFI_OK; 199} 200 201/*@-declundef@*/ 202/*@-exportheader@*/ 203extern void 204ffi_call_SYSV( 205 void (*)(char *, extended_cif *), 206/*@out@*/ extended_cif* , 207 unsigned , 208 unsigned , 209/*@out@*/ unsigned* , 210 void (*fn)(void)); 211/*@=declundef@*/ 212/*@=exportheader@*/ 213 214#ifdef X86_WIN32 215/*@-declundef@*/ 216/*@-exportheader@*/ 217extern void 218ffi_call_STDCALL( 219 void (char *, extended_cif *), 220/*@out@*/ extended_cif* , 221 unsigned , 222 unsigned , 223/*@out@*/ unsigned* , 224 void (*fn)(void)); 225/*@=declundef@*/ 226/*@=exportheader@*/ 227#endif /* X86_WIN32 */ 228 229void 230ffi_call( 231/*@dependent@*/ ffi_cif* cif, 232 void (*fn)(void), 233/*@out@*/ void* rvalue, 234/*@dependent@*/ void** avalue) 235{ 236 extended_cif ecif; 237 238 ecif.cif = cif; 239 ecif.avalue = avalue; 240 241 /* If the return value is a struct and we don't have a return 242 value address then we need to make one. */ 243 244 if ((rvalue == NULL) && retval_on_stack(cif->rtype)) 245 { 246 /*@-sysunrecog@*/ 247 ecif.rvalue = alloca(cif->rtype->size); 248 /*@=sysunrecog@*/ 249 } 250 else 251 ecif.rvalue = rvalue; 252 253 switch (cif->abi) 254 { 255 case FFI_SYSV: 256 /*@-usedef@*/ 257 /* To avoid changing the assembly code make sure the size of the argument 258 block is a multiple of 16. Then add 8 to compensate for local variables 259 in ffi_call_SYSV. */ 260 ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, 261 cif->flags, ecif.rvalue, fn); 262 /*@=usedef@*/ 263 break; 264 265#ifdef X86_WIN32 266 case FFI_STDCALL: 267 /*@-usedef@*/ 268 ffi_call_STDCALL(ffi_prep_args, &ecif, cif->bytes, 269 cif->flags, ecif.rvalue, fn); 270 /*@=usedef@*/ 271 break; 272#endif /* X86_WIN32 */ 273 274 default: 275 FFI_ASSERT(0); 276 break; 277 } 278} 279 280/** private members **/ 281 282static void 283ffi_closure_SYSV( 284 ffi_closure* closure) __attribute__((regparm(1))); 285 286#if !FFI_NO_RAW_API 287static void 288ffi_closure_raw_SYSV( 289 ffi_raw_closure* closure) __attribute__((regparm(1))); 290#endif 291 292/*@-exportheader@*/ 293static inline 294void 295ffi_prep_incoming_args_SYSV( 296 char* stack, 297 void** rvalue, 298 void** avalue, 299 ffi_cif* cif) 300/*@=exportheader@*/ 301{ 302 register unsigned int i; 303 register void** p_argv = avalue; 304 register char* argp = stack; 305 register ffi_type** p_arg; 306 307 if (retval_on_stack(cif->rtype)) 308 { 309 *rvalue = *(void**)argp; 310 argp += 4; 311 } 312 313 for (i = cif->nargs, p_arg = cif->arg_types; i > 0; i--, p_arg++, p_argv++) 314 { 315// size_t z; 316 317 /* Align if necessary */ 318 if ((sizeof(int) - 1) & (unsigned)argp) 319 argp = (char*)ALIGN(argp, sizeof(int)); 320 321// z = (*p_arg)->size; 322 323 /* because we're little endian, this is what it turns into. */ 324 *p_argv = (void*)argp; 325 326 argp += (*p_arg)->size; 327 } 328} 329 330/* This function is jumped to by the trampoline */ 331__attribute__((regparm(1))) 332static void 333ffi_closure_SYSV( 334 ffi_closure* closure) 335{ 336 long double res; 337 ffi_cif* cif = closure->cif; 338 void** arg_area = (void**)alloca(cif->nargs * sizeof(void*)); 339 void* resp = (void*)&res; 340 void* args = __builtin_dwarf_cfa(); 341 342 /* This call will initialize ARG_AREA, such that each 343 element in that array points to the corresponding 344 value on the stack; and if the function returns 345 a structure, it will reset RESP to point to the 346 structure return address. */ 347 ffi_prep_incoming_args_SYSV(args, (void**)&resp, arg_area, cif); 348 349 (closure->fun)(cif, resp, arg_area, closure->user_data); 350 351 /* now, do a generic return based on the value of rtype */ 352 if (cif->flags == FFI_TYPE_INT) 353 asm("movl (%0),%%eax" 354 : : "r" (resp) : "eax"); 355 else if (cif->flags == FFI_TYPE_FLOAT) 356 asm("flds (%0)" 357 : : "r" (resp) : "st"); 358 else if (cif->flags == FFI_TYPE_DOUBLE) 359 asm("fldl (%0)" 360 : : "r" (resp) : "st", "st(1)"); 361 else if (cif->flags == FFI_TYPE_LONGDOUBLE) 362 asm("fldt (%0)" 363 : : "r" (resp) : "st", "st(1)"); 364 else if (cif->flags == FFI_TYPE_SINT64) 365 asm("movl 0(%0),%%eax;" 366 "movl 4(%0),%%edx" 367 : : "r" (resp) 368 : "eax", "edx"); 369 370#if defined(X86_WIN32) || defined(X86_DARWIN) 371 else if (cif->flags == FFI_TYPE_SINT8) /* 1-byte struct */ 372 asm("movsbl (%0),%%eax" 373 : : "r" (resp) : "eax"); 374 else if (cif->flags == FFI_TYPE_SINT16) /* 2-bytes struct */ 375 asm("movswl (%0),%%eax" 376 : : "r" (resp) : "eax"); 377#endif 378 379 else if (cif->flags == FFI_TYPE_STRUCT) 380 asm("lea -8(%ebp),%esp;" 381 "pop %esi;" 382 "pop %edi;" 383 "pop %ebp;" 384 "ret $4"); 385} 386 387 388/* How to make a trampoline. Derived from gcc/config/i386/i386.c. */ 389#define FFI_INIT_TRAMPOLINE(TRAMP, FUN, CTX) \ 390 ({ \ 391 unsigned char* __tramp = (unsigned char*)(TRAMP); \ 392 unsigned int __fun = (unsigned int)(FUN); \ 393 unsigned int __ctx = (unsigned int)(CTX); \ 394 unsigned int __dis = __fun - ((unsigned int)__tramp + FFI_TRAMPOLINE_SIZE); \ 395 *(unsigned char*)&__tramp[0] = 0xb8; \ 396 *(unsigned int*)&__tramp[1] = __ctx; /* movl __ctx, %eax */ \ 397 *(unsigned char*)&__tramp[5] = 0xe9; \ 398 *(unsigned int*)&__tramp[6] = __dis; /* jmp __fun */ \ 399 }) 400 401/* the cif must already be prep'ed */ 402ffi_status 403ffi_prep_closure( 404 ffi_closure* closure, 405 ffi_cif* cif, 406 void (*fun)(ffi_cif*,void*,void**,void*), 407 void* user_data) 408{ 409// FFI_ASSERT(cif->abi == FFI_SYSV); 410 if (cif->abi != FFI_SYSV) 411 return FFI_BAD_ABI; 412 413 FFI_INIT_TRAMPOLINE(closure->tramp, &ffi_closure_SYSV, (void*)closure); 414 415 closure->cif = cif; 416 closure->user_data = user_data; 417 closure->fun = fun; 418 419 return FFI_OK; 420} 421 422/* ------- Native raw API support -------------------------------- */ 423 424#if !FFI_NO_RAW_API 425 426__attribute__((regparm(1))) 427static void 428ffi_closure_raw_SYSV( 429 ffi_raw_closure* closure) 430{ 431 long double res; 432 ffi_raw* raw_args = (ffi_raw*)__builtin_dwarf_cfa(); 433 ffi_cif* cif = closure->cif; 434 unsigned short rtype = cif->flags; 435 void* resp = (void*)&res; 436 437 (closure->fun)(cif, resp, raw_args, closure->user_data); 438 439 /* now, do a generic return based on the value of rtype */ 440 if (rtype == FFI_TYPE_INT) 441 asm("movl (%0),%%eax" 442 : : "r" (resp) : "eax"); 443 else if (rtype == FFI_TYPE_FLOAT) 444 asm("flds (%0)" 445 : : "r" (resp) : "st"); 446 else if (rtype == FFI_TYPE_DOUBLE) 447 asm("fldl (%0)" 448 : : "r" (resp) : "st", "st(1)"); 449 else if (rtype == FFI_TYPE_LONGDOUBLE) 450 asm("fldt (%0)" 451 : : "r" (resp) : "st", "st(1)"); 452 else if (rtype == FFI_TYPE_SINT64) 453 asm("movl 0(%0),%%eax;" 454 "movl 4(%0),%%edx" 455 : : "r" (resp) : "eax", "edx"); 456} 457 458ffi_status 459ffi_prep_raw_closure( 460 ffi_raw_closure* closure, 461 ffi_cif* cif, 462 void (*fun)(ffi_cif*,void*,ffi_raw*,void*), 463 void* user_data) 464{ 465// FFI_ASSERT (cif->abi == FFI_SYSV); 466 if (cif->abi != FFI_SYSV) 467 return FFI_BAD_ABI; 468 469 int i; 470 471/* We currently don't support certain kinds of arguments for raw 472 closures. This should be implemented by a separate assembly language 473 routine, since it would require argument processing, something we 474 don't do now for performance. */ 475 for (i = cif->nargs - 1; i >= 0; i--) 476 { 477 FFI_ASSERT(cif->arg_types[i]->type != FFI_TYPE_STRUCT); 478 FFI_ASSERT(cif->arg_types[i]->type != FFI_TYPE_LONGDOUBLE); 479 } 480 481 FFI_INIT_TRAMPOLINE(closure->tramp, &ffi_closure_raw_SYSV, (void*)closure); 482 483 closure->cif = cif; 484 closure->user_data = user_data; 485 closure->fun = fun; 486 487 return FFI_OK; 488} 489 490static void 491ffi_prep_args_raw( 492 char* stack, 493 extended_cif* ecif) 494{ 495 memcpy(stack, ecif->avalue, ecif->cif->bytes); 496} 497 498/* We borrow this routine from libffi (it must be changed, though, to 499 actually call the function passed in the first argument. as of 500 libffi-1.20, this is not the case.) */ 501//extern void 502//ffi_call_SYSV( 503// void (*)(char *, extended_cif *), 504///*@out@*/ extended_cif* , 505// unsigned , 506// unsigned , 507//*@out@*/ unsigned* , 508// void (*fn)()); 509 510#ifdef X86_WIN32 511extern void 512ffi_call_STDCALL( 513 void (*)(char *, extended_cif *), 514/*@out@*/ extended_cif* , 515 unsigned , 516 unsigned , 517/*@out@*/ unsigned* , 518 void (*fn)()); 519#endif // X86_WIN32 520 521void 522ffi_raw_call( 523/*@dependent@*/ ffi_cif* cif, 524 void (*fn)(), 525/*@out@*/ void* rvalue, 526/*@dependent@*/ ffi_raw* fake_avalue) 527{ 528 extended_cif ecif; 529 void **avalue = (void **)fake_avalue; 530 531 ecif.cif = cif; 532 ecif.avalue = avalue; 533 534 /* If the return value is a struct and we don't have a return 535 value address then we need to make one */ 536 if ((rvalue == NULL) && retval_on_stack(cif->rtype)) 537 { 538 /*@-sysunrecog@*/ 539 ecif.rvalue = alloca(cif->rtype->size); 540 /*@=sysunrecog@*/ 541 } 542 else 543 ecif.rvalue = rvalue; 544 545 switch (cif->abi) 546 { 547 case FFI_SYSV: 548 /*@-usedef@*/ 549 ffi_call_SYSV(ffi_prep_args_raw, &ecif, cif->bytes, 550 cif->flags, ecif.rvalue, fn); 551 /*@=usedef@*/ 552 break; 553#ifdef X86_WIN32 554 case FFI_STDCALL: 555 /*@-usedef@*/ 556 ffi_call_STDCALL(ffi_prep_args_raw, &ecif, cif->bytes, 557 cif->flags, ecif.rvalue, fn); 558 /*@=usedef@*/ 559 break; 560#endif /* X86_WIN32 */ 561 default: 562 FFI_ASSERT(0); 563 break; 564 } 565} 566 567#endif // !FFI_NO_RAW_API 568//#endif // !__x86_64__ 569#endif // __i386__ 570