int main (void) { ffi_cif cif; ffi_type *args[MAX_ARGS]; void *values[MAX_ARGS]; float f; long double ld; args[0] = &ffi_type_float; values[0] = &f; /* Initialize the cif */ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ffi_type_longdouble, args) == FFI_OK); f = 3.14159; #if 1 /* This is ifdef'd out for now. long double support under SunOS/gcc is pretty much non-existent. You'll get the odd bus error in library routines like printf(). */ printf ("%Lf\n", ldblit(f)); #endif ld = 666; ffi_call(&cif, FFI_FN(ldblit), &ld, values); #if 1 /* This is ifdef'd out for now. long double support under SunOS/gcc is pretty much non-existent. You'll get the odd bus error in library routines like printf(). */ printf ("%Lf, %Lf, %Lf, %Lf\n", ld, ldblit(f), ld - ldblit(f), LDBL_EPSILON); #endif /* These are not always the same!! Check for a reasonable delta */ /*@-realcompare@*/ if (ld - ldblit(f) < LDBL_EPSILON) /*@=realcompare@*/ puts("long double return value tests ok!"); else CHECK(0); exit(0); }
int main(/*@unused@*/ int argc, /*@unused@*/ char *argv[]) { ffi_cif cif; ffi_type *args[MAX_ARGS]; void *values[MAX_ARGS]; char *s; signed char sc; unsigned char uc; signed short ss; unsigned short us; unsigned long ul; long long ll; float f; double d; long double ld; signed int si1; signed int si2; ffi_arg rint; long long rlonglong; ffi_type ts1_type; ffi_type ts2_type; ffi_type ts3_type; ffi_type ts4_type; ffi_type ts5_type; ffi_type *ts1_type_elements[4]; ffi_type *ts2_type_elements[3]; ffi_type *ts3_type_elements[2]; ffi_type *ts4_type_elements[4]; ffi_type *ts5_type_elements[3]; ts1_type.size = 0; ts1_type.alignment = 0; ts1_type.type = FFI_TYPE_STRUCT; ts2_type.size = 0; ts2_type.alignment = 0; ts2_type.type = FFI_TYPE_STRUCT; ts3_type.size = 0; ts3_type.alignment = 0; ts3_type.type = FFI_TYPE_STRUCT; ts4_type.size = 0; ts4_type.alignment = 0; ts4_type.type = FFI_TYPE_STRUCT; ts5_type.size = 0; ts5_type.alignment = 0; ts5_type.type = FFI_TYPE_STRUCT; /*@-immediatetrans@*/ ts1_type.elements = ts1_type_elements; ts2_type.elements = ts2_type_elements; ts3_type.elements = ts3_type_elements; ts4_type.elements = ts4_type_elements; ts5_type.elements = ts5_type_elements; /*@=immediatetrans@*/ ts1_type_elements[0] = &ffi_type_uchar; ts1_type_elements[1] = &ffi_type_double; ts1_type_elements[2] = &ffi_type_uint; ts1_type_elements[3] = NULL; ts2_type_elements[0] = &ffi_type_double; ts2_type_elements[1] = &ffi_type_double; ts2_type_elements[2] = NULL; ts3_type_elements[0] = &ffi_type_sint; ts3_type_elements[1] = NULL; ts4_type_elements[0] = &ffi_type_uint; ts4_type_elements[1] = &ffi_type_uint; ts4_type_elements[2] = &ffi_type_uint; ts4_type_elements[3] = NULL; ts5_type_elements[0] = &ffi_type_schar; ts5_type_elements[1] = &ffi_type_schar; ts5_type_elements[2] = NULL; ul = 0; /* return value tests */ { #if defined(MIPS) /* || defined(ARM) */ puts ("long long tests not run. This is a known bug on this architecture."); #else args[0] = &ffi_type_sint64; values[0] = ≪ /* Initialize the cif */ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ffi_type_sint64, args) == FFI_OK); for (ll = 0LL; ll < 100LL; ll++) { ul++; ffi_call(&cif, FFI_FN(return_ll), &rlonglong, values); CHECK(rlonglong == ll); } for (ll = 55555555555000LL; ll < 55555555555100LL; ll++) { ul++; ffi_call(&cif, FFI_FN(return_ll), &rlonglong, values); CHECK(rlonglong == ll); } #endif args[0] = &ffi_type_schar; values[0] = ≻ /* Initialize the cif */ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ffi_type_schar, args) == FFI_OK); for (sc = (signed char) -127; sc < (signed char) 127; /*@-type@*/ sc++ /*@=type@*/) { ul++; ffi_call(&cif, FFI_FN(return_sc), &rint, values); CHECK(rint == (int) sc); } args[0] = &ffi_type_uchar; values[0] = &uc; /* Initialize the cif */ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ffi_type_uchar, args) == FFI_OK); for (uc = (unsigned char) '\x00'; uc < (unsigned char) '\xff'; /*@-type@*/ uc++ /*@=type@*/) { ul++; ffi_call(&cif, FFI_FN(return_uc), &rint, values); CHECK(rint == (signed int) uc); } printf("%lu return value tests run\n", ul); } #ifdef BROKEN_LONG_DOUBLE printf ("This architecture has broken `long double' support. No floating point\ntests have been run.\n"); #else /* float arg tests */ { args[0] = &ffi_type_float; values[0] = &f; /* Initialize the cif */ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ffi_type_longdouble, args) == FFI_OK); f = 3.14159; #if 0 /* This is ifdef'd out for now. long double support under SunOS/gcc is pretty much non-existent. You'll get the odd bus error in library routines like printf(). */ printf ("%Lf\n", ldblit(f)); #endif ld = 666; ffi_call(&cif, FFI_FN(ldblit), &ld, values); #if 0 /* This is ifdef'd out for now. long double support under SunOS/gcc is pretty much non-existent. You'll get the odd bus error in library routines like printf(). */ printf ("%Lf, %Lf, %Lf, %Lf\n", ld, ldblit(f), ld - ldblit(f), LDBL_EPSILON); #endif /* These are not always the same!! Check for a reasonable delta */ /*@-realcompare@*/ if (ld - ldblit(f) < LDBL_EPSILON) /*@=realcompare@*/ puts("long double return value tests ok!"); else CHECK(0); } /* float arg tests */ { args[0] = &ffi_type_sint; values[0] = &si1; args[1] = &ffi_type_float; values[1] = &f; args[2] = &ffi_type_double; values[2] = &d; args[3] = &ffi_type_longdouble; values[3] = &ld; args[4] = &ffi_type_sint; values[4] = &si2; /* Initialize the cif */ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 5, &ffi_type_sint, args) == FFI_OK); si1 = 6; f = 3.14159; d = (double)1.0/(double)3.0; ld = 2.71828182846L; si2 = 10; floating (si1, f, d, ld, si2); ffi_call(&cif, FFI_FN(floating), &rint, values); printf ("%d vs %d\n", rint, floating (si1, f, d, ld, si2)); CHECK(rint == floating(si1, f, d, ld, si2)); printf("float arg tests ok!\n"); } #endif /* strlen tests */ { args[0] = &ffi_type_pointer; values[0] = (void*) &s; /* Initialize the cif */ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ffi_type_sint, args) == FFI_OK); s = "a"; ffi_call(&cif, FFI_FN(my_strlen), &rint, values); CHECK(rint == 1); s = "1234567"; ffi_call(&cif, FFI_FN(my_strlen), &rint, values); CHECK(rint == 7); s = "1234567890123456789012345"; ffi_call(&cif, FFI_FN(my_strlen), &rint, values); CHECK(rint == 25); printf("strlen tests passed\n"); } /* float arg tests */ { args[0] = &ffi_type_float; values[0] = &f; /* Initialize the cif */ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ffi_type_double, args) == FFI_OK); f = 3.14159; ffi_call(&cif, FFI_FN(dblit), &d, values); /* These are not always the same!! Check for a reasonable delta */ /*@-realcompare@*/ CHECK(d - dblit(f) < DBL_EPSILON); /*@=realcompare@*/ printf("double return value tests ok!\n"); } /* many arg tests */ { float ff; float fa[13]; for (ul = 0; ul < 13; ul++) { args[ul] = &ffi_type_float; values[ul] = &fa[ul]; fa[ul] = (float) ul; } /* Initialize the cif */ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 13, &ffi_type_float, args) == FFI_OK); /*@-usedef@*/ ff = many(fa[0], fa[1], fa[2], fa[3], fa[4], fa[5], fa[6], fa[7], fa[8], fa[9], fa[10],fa[11],fa[12]); /*@=usedef@*/ ffi_call(&cif, FFI_FN(many), &f, values); /*@-realcompare@*/ if (f - ff < FLT_EPSILON) /*@=realcompare@*/ printf("many arg tests ok!\n"); else #ifdef POWERPC printf("many arg tests failed! This is a gcc bug.\n"); #else CHECK(0); #endif } /* promotion tests */ { args[0] = &ffi_type_schar; args[1] = &ffi_type_sshort; args[2] = &ffi_type_uchar; args[3] = &ffi_type_ushort; values[0] = ≻ values[1] = &ss; values[2] = &uc; values[3] = &us; /* Initialize the cif */ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 4, &ffi_type_sint, args) == FFI_OK); us = 0; ul = 0; for (sc = (signed char) -127; sc <= (signed char) 120; /*@-type@*/ sc += 1 /*@=type@*/) for (ss = -30000; ss <= 30000; ss += 10000) for (uc = (unsigned char) 0; uc <= (unsigned char) 200; /*@-type@*/ uc += 20 /*@=type@*/) for (us = 0; us <= 60000; us += 10000) { ul++; ffi_call(&cif, FFI_FN(promotion), &rint, values); CHECK(rint == (int) sc + (int) ss + (int) uc + (int) us); } printf("%lu promotion tests run\n", ul); } #ifndef X86_WIN32 /* Structures dont work on Win32 */ /* struct tests */ { test_structure_1 ts1_arg; /* This is a hack to get a properly aligned result buffer */ test_structure_1 *ts1_result = (test_structure_1 *) malloc (sizeof(test_structure_1)); args[0] = &ts1_type; values[0] = &ts1_arg; /* Initialize the cif */ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ts1_type, args) == FFI_OK); ts1_arg.uc = '\x01'; ts1_arg.d = 3.14159; ts1_arg.ui = 555; ffi_call(&cif, FFI_FN(struct1), ts1_result, values); CHECK(ts1_result->ui == 556); CHECK(ts1_result->d == 3.14159 - 1); puts ("structure test 1 ok!\n"); free (ts1_result); } /* struct tests */ { test_structure_2 ts2_arg; /* This is a hack to get a properly aligned result buffer */ test_structure_2 *ts2_result = (test_structure_2 *) malloc (sizeof(test_structure_2)); args[0] = &ts2_type; values[0] = &ts2_arg; /* Initialize the cif */ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ts2_type, args) == FFI_OK); ts2_arg.d1 = 5.55; ts2_arg.d2 = 6.66; printf ("%g\n", ts2_result->d1); printf ("%g\n", ts2_result->d2); ffi_call(&cif, FFI_FN(struct2), ts2_result, values); printf ("%g\n", ts2_result->d1); printf ("%g\n", ts2_result->d2); CHECK(ts2_result->d1 == 5.55 - 1); CHECK(ts2_result->d2 == 6.66 - 1); printf("structure test 2 ok!\n"); free (ts2_result); } /* struct tests */ { int compare_value; test_structure_3 ts3_arg; test_structure_3 *ts3_result = (test_structure_3 *) malloc (sizeof(test_structure_3)); args[0] = &ts3_type; values[0] = &ts3_arg; /* Initialize the cif */ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ts3_type, args) == FFI_OK); ts3_arg.si = -123; compare_value = ts3_arg.si; ffi_call(&cif, FFI_FN(struct3), ts3_result, values); printf ("%d %d\n", ts3_result->si, -(compare_value*2)); if (ts3_result->si == -(ts3_arg.si*2)) puts ("structure test 3 ok!"); else { puts ("Structure test 3 found structure passing bug."); puts (" Current versions of GCC are not 100% compliant with the"); puts (" n32 ABI. There is a known problem related to passing"); puts (" small structures. Send a bug report to the gcc maintainers."); } free (ts3_result); } /* struct tests */ { test_structure_4 ts4_arg; /* This is a hack to get a properly aligned result buffer */ test_structure_4 *ts4_result = (test_structure_4 *) malloc (sizeof(test_structure_4)); args[0] = &ts4_type; values[0] = &ts4_arg; /* Initialize the cif */ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ts4_type, args) == FFI_OK); ts4_arg.ui1 = 2; ts4_arg.ui2 = 3; ts4_arg.ui3 = 4; ffi_call (&cif, FFI_FN(struct4), ts4_result, values); if (ts4_result->ui3 == 2U * 3U * 4U) puts ("structure test 4 ok!"); else puts ("Structure test 4 found GCC's structure passing bug."); free (ts4_result); } /* struct tests */ { test_structure_5 ts5_arg1, ts5_arg2; /* This is a hack to get a properly aligned result buffer */ test_structure_5 *ts5_result = (test_structure_5 *) malloc (sizeof(test_structure_5)); args[0] = &ts5_type; args[1] = &ts5_type; values[0] = &ts5_arg1; values[1] = &ts5_arg2; /* Initialize the cif */ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &ts5_type, args) == FFI_OK); ts5_arg1.c1 = 2; ts5_arg1.c2 = 6; ts5_arg2.c1 = 5; ts5_arg2.c2 = 3; ffi_call (&cif, FFI_FN(struct5), ts5_result, values); if (ts5_result->c1 == 7 && ts5_result->c2 == 3) puts ("structure test 5 ok!"); else puts ("Structure test 5 found GCC's structure passing bug."); free (ts5_result); } #else printf("Structure passing doesn't work on Win32.\n"); #endif /* X86_WIN32 */ # if FFI_CLOSURES /* A simple closure test */ { ffi_closure cl; ffi_type * cl_arg_types[3]; cl_arg_types[0] = &ffi_type_sint; cl_arg_types[1] = &ffi_type_float; cl_arg_types[2] = NULL; /* Initialize the cif */ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &ffi_type_sint, cl_arg_types) == FFI_OK); CHECK(ffi_prep_closure(&cl, &cif, closure_test_fn, (void *) 3 /* userdata */) == FFI_OK); CHECK((*((closure_test_type)(&cl)))(1, 2.0) == 6); } # endif /* If we arrived here, all is good */ (void) puts("\nLooks good. No surprises.\n"); /*@-compdestroy@*/ return 0; }