ffi.c revision 056e203a7aec4c87c077192ad776b532a3d0305f
1/* ----------------------------------------------------------------------- 2 ffi.c - Copyright (c) 1998 Cygnus Solutions 3 Copyright (c) 2004 Simon Posnjak 4 Copyright (c) 2005 Axis Communications AB 5 6 CRIS Foreign Function Interface 7 8 Permission is hereby granted, free of charge, to any person obtaining 9 a copy of this software and associated documentation files (the 10 ``Software''), to deal in the Software without restriction, including 11 without limitation the rights to use, copy, modify, merge, publish, 12 distribute, sublicense, and/or sell copies of the Software, and to 13 permit persons to whom the Software is furnished to do so, subject to 14 the following conditions: 15 16 The above copyright notice and this permission notice shall be included 17 in all copies or substantial portions of the Software. 18 19 THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS 20 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 IN NO EVENT SHALL SIMON POSNJAK BE LIABLE FOR ANY CLAIM, DAMAGES OR 23 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 24 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 25 OTHER DEALINGS IN THE SOFTWARE. 26 ----------------------------------------------------------------------- */ 27 28#include <ffi.h> 29#include <ffi_common.h> 30 31#define STACK_ARG_SIZE(x) ALIGN(x, FFI_SIZEOF_ARG) 32 33static ffi_status 34initialize_aggregate_packed_struct (ffi_type * arg) 35{ 36 ffi_type **ptr; 37 38 FFI_ASSERT (arg != NULL); 39 40 FFI_ASSERT (arg->elements != NULL); 41 FFI_ASSERT (arg->size == 0); 42 FFI_ASSERT (arg->alignment == 0); 43 44 ptr = &(arg->elements[0]); 45 46 while ((*ptr) != NULL) 47 { 48 if (((*ptr)->size == 0) 49 && (initialize_aggregate_packed_struct ((*ptr)) != FFI_OK)) 50 return FFI_BAD_TYPEDEF; 51 52 FFI_ASSERT (ffi_type_test ((*ptr))); 53 54 arg->size += (*ptr)->size; 55 56 arg->alignment = (arg->alignment > (*ptr)->alignment) ? 57 arg->alignment : (*ptr)->alignment; 58 59 ptr++; 60 } 61 62 if (arg->size == 0) 63 return FFI_BAD_TYPEDEF; 64 else 65 return FFI_OK; 66} 67 68int 69ffi_prep_args (char *stack, extended_cif * ecif) 70{ 71 unsigned int i; 72 unsigned int struct_count = 0; 73 void **p_argv; 74 char *argp; 75 ffi_type **p_arg; 76 77 argp = stack; 78 79 p_argv = ecif->avalue; 80 81 for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; 82 (i != 0); i--, p_arg++) 83 { 84 size_t z; 85 86 switch ((*p_arg)->type) 87 { 88 case FFI_TYPE_STRUCT: 89 { 90 z = (*p_arg)->size; 91 if (z <= 4) 92 { 93 memcpy (argp, *p_argv, z); 94 z = 4; 95 } 96 else if (z <= 8) 97 { 98 memcpy (argp, *p_argv, z); 99 z = 8; 100 } 101 else 102 { 103 unsigned int uiLocOnStack; 104 z = sizeof (void *); 105 uiLocOnStack = 4 * ecif->cif->nargs + struct_count; 106 struct_count = struct_count + (*p_arg)->size; 107 *(unsigned int *) argp = 108 (unsigned int) (UINT32 *) (stack + uiLocOnStack); 109 memcpy ((stack + uiLocOnStack), *p_argv, (*p_arg)->size); 110 } 111 break; 112 } 113 default: 114 z = (*p_arg)->size; 115 if (z < sizeof (int)) 116 { 117 switch ((*p_arg)->type) 118 { 119 case FFI_TYPE_SINT8: 120 *(signed int *) argp = (signed int) *(SINT8 *) (*p_argv); 121 break; 122 123 case FFI_TYPE_UINT8: 124 *(unsigned int *) argp = 125 (unsigned int) *(UINT8 *) (*p_argv); 126 break; 127 128 case FFI_TYPE_SINT16: 129 *(signed int *) argp = (signed int) *(SINT16 *) (*p_argv); 130 break; 131 132 case FFI_TYPE_UINT16: 133 *(unsigned int *) argp = 134 (unsigned int) *(UINT16 *) (*p_argv); 135 break; 136 137 default: 138 FFI_ASSERT (0); 139 } 140 z = sizeof (int); 141 } 142 else if (z == sizeof (int)) 143 *(unsigned int *) argp = (unsigned int) *(UINT32 *) (*p_argv); 144 else 145 memcpy (argp, *p_argv, z); 146 break; 147 } 148 p_argv++; 149 argp += z; 150 } 151 152 return (struct_count); 153} 154 155ffi_status 156ffi_prep_cif (ffi_cif * cif, 157 ffi_abi abi, unsigned int nargs, 158 ffi_type * rtype, ffi_type ** atypes) 159{ 160 unsigned bytes = 0; 161 unsigned int i; 162 ffi_type **ptr; 163 164 FFI_ASSERT (cif != NULL); 165 FFI_ASSERT ((abi > FFI_FIRST_ABI) && (abi <= FFI_DEFAULT_ABI)); 166 167 cif->abi = abi; 168 cif->arg_types = atypes; 169 cif->nargs = nargs; 170 cif->rtype = rtype; 171 172 cif->flags = 0; 173 174 if ((cif->rtype->size == 0) 175 && (initialize_aggregate_packed_struct (cif->rtype) != FFI_OK)) 176 return FFI_BAD_TYPEDEF; 177 178 FFI_ASSERT_VALID_TYPE (cif->rtype); 179 180 for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++) 181 { 182 if (((*ptr)->size == 0) 183 && (initialize_aggregate_packed_struct ((*ptr)) != FFI_OK)) 184 return FFI_BAD_TYPEDEF; 185 186 FFI_ASSERT_VALID_TYPE (*ptr); 187 188 if (((*ptr)->alignment - 1) & bytes) 189 bytes = ALIGN (bytes, (*ptr)->alignment); 190 if ((*ptr)->type == FFI_TYPE_STRUCT) 191 { 192 if ((*ptr)->size > 8) 193 { 194 bytes += (*ptr)->size; 195 bytes += sizeof (void *); 196 } 197 else 198 { 199 if ((*ptr)->size > 4) 200 bytes += 8; 201 else 202 bytes += 4; 203 } 204 } 205 else 206 bytes += STACK_ARG_SIZE ((*ptr)->size); 207 } 208 209 cif->bytes = bytes; 210 211 return ffi_prep_cif_machdep (cif); 212} 213 214ffi_status 215ffi_prep_cif_machdep (ffi_cif * cif) 216{ 217 switch (cif->rtype->type) 218 { 219 case FFI_TYPE_VOID: 220 case FFI_TYPE_STRUCT: 221 case FFI_TYPE_FLOAT: 222 case FFI_TYPE_DOUBLE: 223 case FFI_TYPE_SINT64: 224 case FFI_TYPE_UINT64: 225 cif->flags = (unsigned) cif->rtype->type; 226 break; 227 228 default: 229 cif->flags = FFI_TYPE_INT; 230 break; 231 } 232 233 return FFI_OK; 234} 235 236extern void ffi_call_SYSV (int (*)(char *, extended_cif *), 237 extended_cif *, 238 unsigned, unsigned, unsigned *, void (*fn) ()) 239 __attribute__ ((__visibility__ ("hidden"))); 240 241void 242ffi_call (ffi_cif * cif, void (*fn) (), void *rvalue, void **avalue) 243{ 244 extended_cif ecif; 245 246 ecif.cif = cif; 247 ecif.avalue = avalue; 248 249 if ((rvalue == NULL) && (cif->rtype->type == FFI_TYPE_STRUCT)) 250 { 251 ecif.rvalue = alloca (cif->rtype->size); 252 } 253 else 254 ecif.rvalue = rvalue; 255 256 switch (cif->abi) 257 { 258 case FFI_SYSV: 259 ffi_call_SYSV (ffi_prep_args, &ecif, cif->bytes, 260 cif->flags, ecif.rvalue, fn); 261 break; 262 default: 263 FFI_ASSERT (0); 264 break; 265 } 266} 267 268/* Because the following variables are not exported outside libffi, we 269 mark them hidden. */ 270 271/* Assembly code for the jump stub. */ 272extern const char ffi_cris_trampoline_template[] 273 __attribute__ ((__visibility__ ("hidden"))); 274 275/* Offset into ffi_cris_trampoline_template of where to put the 276 ffi_prep_closure_inner function. */ 277extern const int ffi_cris_trampoline_fn_offset 278 __attribute__ ((__visibility__ ("hidden"))); 279 280/* Offset into ffi_cris_trampoline_template of where to put the 281 closure data. */ 282extern const int ffi_cris_trampoline_closure_offset 283 __attribute__ ((__visibility__ ("hidden"))); 284 285/* This function is sibling-called (jumped to) by the closure 286 trampoline. We get R10..R13 at PARAMS[0..3] and a copy of [SP] at 287 PARAMS[4] to simplify handling of a straddling parameter. A copy 288 of R9 is at PARAMS[5] and SP at PARAMS[6]. These parameters are 289 put at the appropriate place in CLOSURE which is then executed and 290 the return value is passed back to the caller. */ 291 292static unsigned long long 293ffi_prep_closure_inner (void **params, ffi_closure* closure) 294{ 295 char *register_args = (char *) params; 296 void *struct_ret = params[5]; 297 char *stack_args = params[6]; 298 char *ptr = register_args; 299 ffi_cif *cif = closure->cif; 300 ffi_type **arg_types = cif->arg_types; 301 302 /* Max room needed is number of arguments as 64-bit values. */ 303 void **avalue = alloca (closure->cif->nargs * sizeof(void *)); 304 int i; 305 int doing_regs; 306 long long llret = 0; 307 308 /* Find the address of each argument. */ 309 for (i = 0, doing_regs = 1; i < cif->nargs; i++) 310 { 311 /* Types up to and including 8 bytes go by-value. */ 312 if (arg_types[i]->size <= 4) 313 { 314 avalue[i] = ptr; 315 ptr += 4; 316 } 317 else if (arg_types[i]->size <= 8) 318 { 319 avalue[i] = ptr; 320 ptr += 8; 321 } 322 else 323 { 324 FFI_ASSERT (arg_types[i]->type == FFI_TYPE_STRUCT); 325 326 /* Passed by-reference, so copy the pointer. */ 327 avalue[i] = *(void **) ptr; 328 ptr += 4; 329 } 330 331 /* If we've handled more arguments than fit in registers, start 332 looking at the those passed on the stack. Step over the 333 first one if we had a straddling parameter. */ 334 if (doing_regs && ptr >= register_args + 4*4) 335 { 336 ptr = stack_args + ((ptr > register_args + 4*4) ? 4 : 0); 337 doing_regs = 0; 338 } 339 } 340 341 /* Invoke the closure. */ 342 (closure->fun) (cif, 343 344 cif->rtype->type == FFI_TYPE_STRUCT 345 /* The caller allocated space for the return 346 structure, and passed a pointer to this space in 347 R9. */ 348 ? struct_ret 349 350 /* We take advantage of being able to ignore that 351 the high part isn't set if the return value is 352 not in R10:R11, but in R10 only. */ 353 : (void *) &llret, 354 355 avalue, closure->user_data); 356 357 return llret; 358} 359 360/* API function: Prepare the trampoline. */ 361 362ffi_status 363ffi_prep_closure (ffi_closure* closure, 364 ffi_cif* cif, 365 void (*fun)(ffi_cif *, void *, void **, void*), 366 void *user_data) 367{ 368 void *innerfn = ffi_prep_closure_inner; 369 FFI_ASSERT (cif->abi == FFI_SYSV); 370 closure->cif = cif; 371 closure->user_data = user_data; 372 closure->fun = fun; 373 memcpy (closure->tramp, ffi_cris_trampoline_template, 374 FFI_CRIS_TRAMPOLINE_CODE_PART_SIZE); 375 memcpy (closure->tramp + ffi_cris_trampoline_fn_offset, 376 &innerfn, sizeof (void *)); 377 memcpy (closure->tramp + ffi_cris_trampoline_closure_offset, 378 &closure, sizeof (void *)); 379 380 return FFI_OK; 381} 382