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