2007-09-04 Andrew Haley * src/arm/sysv.S (UNWIND): New. (Whole file): Conditionally compile unwinder directives. * src/arm/sysv.S: Add unwinder directives. * src/arm/ffi.c (ffi_prep_args): Align structs by at least 4 bytes. Only treat r0 as a struct address if we're actually returning a struct by address. Only copy the bytes that are actually within a struct. (ffi_prep_cif_machdep): A Composite Type not larger than 4 bytes is returned in r0, not passed by address. (ffi_call): Allocate a word-sized temporary for the case where a composite is returned in r0. (ffi_prep_incoming_args_SYSV): Align as necessary. 2007-08-05 Steven Newbury * src/arm/ffi.c (FFI_INIT_TRAMPOLINE): Use __clear_cache instead of directly using the sys_cacheflush syscall. 2007-07-27 Andrew Haley * src/arm/sysv.S (ffi_closure_SYSV): Add soft-float. Index: libffi/src/arm/ffi.c =================================================================== --- libffi/src/arm/ffi.c.orig +++ libffi/src/arm/ffi.c @@ -40,7 +40,7 @@ void ffi_prep_args(char *stack, extended argp = stack; - if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT ) { + if ( ecif->cif->flags == FFI_TYPE_STRUCT ) { *(void **) argp = ecif->rvalue; argp += 4; } @@ -58,6 +58,9 @@ void ffi_prep_args(char *stack, extended argp = (char *) ALIGN(argp, (*p_arg)->alignment); } + if ((*p_arg)->type == FFI_TYPE_STRUCT) + argp = (char *) ALIGN(argp, 4); + z = (*p_arg)->size; if (z < sizeof(int)) { @@ -81,7 +84,7 @@ void ffi_prep_args(char *stack, extended break; case FFI_TYPE_STRUCT: - *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv); + memcpy(argp, *p_argv, (*p_arg)->size); break; default: @@ -115,7 +118,6 @@ ffi_status ffi_prep_cif_machdep(ffi_cif switch (cif->rtype->type) { case FFI_TYPE_VOID: - case FFI_TYPE_STRUCT: case FFI_TYPE_FLOAT: case FFI_TYPE_DOUBLE: cif->flags = (unsigned) cif->rtype->type; @@ -126,6 +128,17 @@ ffi_status ffi_prep_cif_machdep(ffi_cif cif->flags = (unsigned) FFI_TYPE_SINT64; break; + case FFI_TYPE_STRUCT: + if (cif->rtype->size <= 4) + /* A Composite Type not larger than 4 bytes is returned in r0. */ + cif->flags = (unsigned)FFI_TYPE_INT; + else + /* A Composite Type larger than 4 bytes, or whose size cannot + be determined statically ... is stored in memory at an + address passed [in r0]. */ + cif->flags = (unsigned)FFI_TYPE_STRUCT; + break; + default: cif->flags = FFI_TYPE_INT; break; @@ -141,21 +154,27 @@ void ffi_call(ffi_cif *cif, void (*fn)() { extended_cif ecif; + int small_struct = (cif->flags == FFI_TYPE_INT + && cif->rtype->type == FFI_TYPE_STRUCT); + ecif.cif = cif; ecif.avalue = avalue; + + unsigned int temp; /* If the return value is a struct and we don't have a return */ /* value address then we need to make one */ if ((rvalue == NULL) && - (cif->rtype->type == FFI_TYPE_STRUCT)) + (cif->flags == FFI_TYPE_STRUCT)) { ecif.rvalue = alloca(cif->rtype->size); } + else if (small_struct) + ecif.rvalue = &temp; else ecif.rvalue = rvalue; - - + switch (cif->abi) { case FFI_SYSV: @@ -167,6 +186,8 @@ void ffi_call(ffi_cif *cif, void (*fn)() FFI_ASSERT(0); break; } + if (small_struct) + memcpy (rvalue, &temp, cif->rtype->size); } /** private members **/ @@ -228,9 +249,12 @@ ffi_prep_incoming_args_SYSV(char *stack, { size_t z; + size_t alignment = (*p_arg)->alignment; + if (alignment < 4) + alignment = 4; /* Align if necessary */ - if ((sizeof(int) - 1) & (unsigned) argp) { - argp = (char *) ALIGN(argp, sizeof(int)); + if ((alignment - 1) & (unsigned) argp) { + argp = (char *) ALIGN(argp, alignment); } z = (*p_arg)->size; @@ -248,21 +272,16 @@ ffi_prep_incoming_args_SYSV(char *stack, /* How to make a trampoline. */ -#define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX) \ -({ unsigned char *__tramp = (unsigned char*)(TRAMP); \ - unsigned int __fun = (unsigned int)(FUN); \ - unsigned int __ctx = (unsigned int)(CTX); \ +#define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX) \ +({ unsigned char *__tramp = (unsigned char*)(TRAMP); \ + unsigned int __fun = (unsigned int)(FUN); \ + unsigned int __ctx = (unsigned int)(CTX); \ *(unsigned int*) &__tramp[0] = 0xe92d000f; /* stmfd sp!, {r0-r3} */ \ - *(unsigned int*) &__tramp[4] = 0xe59f0000; /* ldr r0, [pc] */ \ - *(unsigned int*) &__tramp[8] = 0xe59ff000; /* ldr pc, [pc] */ \ - *(unsigned int*) &__tramp[12] = __ctx; \ - *(unsigned int*) &__tramp[16] = __fun; \ - register unsigned long _beg __asm ("a1") = (unsigned long) (&__tramp[0]); \ - register unsigned long _end __asm ("a2") = (unsigned long) (&__tramp[19]); \ - register unsigned long _flg __asm ("a3") = 0; \ - __asm __volatile ("swi 0x9f0002 @ sys_cacheflush" \ - : "=r" (_beg) \ - : "0" (_beg), "r" (_end), "r" (_flg)); \ + *(unsigned int*) &__tramp[4] = 0xe59f0000; /* ldr r0, [pc] */ \ + *(unsigned int*) &__tramp[8] = 0xe59ff000; /* ldr pc, [pc] */ \ + *(unsigned int*) &__tramp[12] = __ctx; \ + *(unsigned int*) &__tramp[16] = __fun; \ + __clear_cache((&__tramp[0]), (&__tramp[19])); \ }) Index: libffi/src/arm/sysv.S =================================================================== --- libffi/src/arm/sysv.S.orig +++ libffi/src/arm/sysv.S @@ -82,6 +82,14 @@ # define call_reg(x) mov lr, pc ; mov pc, x #endif +/* Conditionally compile unwinder directives. */ +#ifdef __ARM_EABI__ +#define UNWIND +#else +#define UNWIND @ +#endif + + #if defined(__thumb__) && !defined(__THUMB_INTERWORK__) .macro ARM_FUNC_START name .text @@ -92,6 +100,7 @@ bx pc nop .arm + UNWIND .fnstart /* A hook to tell gdb that we've switched to ARM mode. Also used to call directly from other local arm routines. */ _L__\name: @@ -102,6 +111,7 @@ _L__\name: .align 0 .arm ENTRY(\name) + UNWIND .fnstart .endm #endif @@ -134,8 +144,11 @@ _L__\name: ARM_FUNC_START ffi_call_SYSV @ Save registers stmfd sp!, {r0-r3, fp, lr} + UNWIND .save {r0-r3, fp, lr} mov fp, sp + UNWIND .setfp fp, sp + @ Make room for all of the new args. sub sp, fp, r2 @@ -205,6 +218,7 @@ LSYM(Lepilogue): RETLDM "r0-r3,fp" .ffi_call_SYSV_end: + UNWIND .fnend .size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV) /* @@ -216,21 +230,40 @@ LSYM(Lepilogue): */ ARM_FUNC_START ffi_closure_SYSV + UNWIND .pad #16 add ip, sp, #16 stmfd sp!, {ip, lr} + UNWIND .save {r0, lr} add r2, sp, #8 + .pad #16 sub sp, sp, #16 str sp, [sp, #8] add r1, sp, #8 bl ffi_closure_SYSV_inner cmp r0, #FFI_TYPE_INT beq .Lretint + cmp r0, #FFI_TYPE_FLOAT +#ifdef __SOFTFP__ + beq .Lretint +#else beq .Lretfloat +#endif + cmp r0, #FFI_TYPE_DOUBLE +#ifdef __SOFTFP__ + beq .Lretlonglong +#else beq .Lretdouble +#endif + cmp r0, #FFI_TYPE_LONGDOUBLE +#ifdef __SOFTFP__ + beq .Lretlonglong +#else beq .Lretlongdouble +#endif + cmp r0, #FFI_TYPE_SINT64 beq .Lretlonglong .Lclosure_epilogue: @@ -243,6 +276,8 @@ ARM_FUNC_START ffi_closure_SYSV ldr r0, [sp] ldr r1, [sp, #4] b .Lclosure_epilogue + +#ifndef __SOFTFP__ .Lretfloat: ldfs f0, [sp] b .Lclosure_epilogue @@ -252,7 +287,10 @@ ARM_FUNC_START ffi_closure_SYSV .Lretlongdouble: ldfd f0, [sp] b .Lclosure_epilogue +#endif + .ffi_closure_SYSV_end: + UNWIND .fnend .size CNAME(ffi_closure_SYSV),.ffi_closure_SYSV_end-CNAME(ffi_closure_SYSV) #if defined __ELF__ && defined __linux__