/** * libffi C99 test code * - proves that libffi calls are working correctly * copyright (C) 2019 * Created on: 12th April 2019 * Modified on: 13th April 2019 */ #include #include #include #include #include #include #include typedef void (*ffi_callback)(void); typedef struct { int _1; int _2; } simple_t; /* adder functors */ int8_t add_signed8(int8_t a, int8_t b) { return a + b; } uint8_t add_unsigned8(uint8_t a, uint8_t b) { return a + b; } int16_t add_signed16(int16_t a, int16_t b) { return a + b; } uint16_t add_unsigned16(uint16_t a, uint16_t b) { return a + b; } int32_t add_signed32(int32_t a, int32_t b) { return a + b; } uint32_t add_unsigned32(uint32_t a, uint32_t b) { return a + b; } int64_t add_signed64(int64_t a, int64_t b) { return a + b; } uint64_t add_unsigned64(uint64_t a, uint64_t b) { return a + b; } float add_floatS(float a, float b) { return a + b; } double add_floatD(double a, double b) { return a + b; } simple_t add_simple(simple_t a, simple_t b) { simple_t ret = { a._1 + b._1, a._2 + b._2 }; return ret; } /* ffi proxy function */ ffi_arg call(ffi_type **args, void **values, size_t nargs, ffi_type rctype, ffi_callback func) { ffi_cif cif; ffi_arg rc; /* Iniitalize the cif */ int ret = ffi_prep_cif(&cif, FFI_DEFAULT_ABI, nargs, &rctype, args); if(ret != FFI_OK) { fprintf(stderr, "[%s] Cant prepare ffi context: %d\n", __func__, ret); exit(EXIT_FAILURE); } ffi_call(&cif, func, &rc, values); return rc; } void call_ext(ffi_type **args, void **values, size_t nargs, ffi_type rctype, void *rc, ffi_callback func) { ffi_cif cif; /* Iniitalize the cif */ int ret = ffi_prep_cif(&cif, FFI_DEFAULT_ABI, nargs, &rctype, args); if(ret != FFI_OK) { fprintf(stderr, "[%s] Cant prepare ffi context: %d\n", __func__, ret); exit(EXIT_FAILURE); } ffi_call(&cif, func, rc, values); } int main(void) { /* 8bit signed integer test */ { int8_t a = (SCHAR_MAX / 2) + 1, b = (SCHAR_MAX / 2) - 1; const int8_t result = a + b; ffi_type *args[] = {&ffi_type_sint8, &ffi_type_sint8}; void *values[] = {&a, &b}; int8_t rc = (int8_t)call(args, values, 2, ffi_type_sint8, (ffi_callback)add_signed8); printf("Signed 8bit integer result:\t%"PRIi8"\n", rc); assert(rc == result); } /* 8bit unsigned integer test */ { uint8_t a = (UCHAR_MAX / 2) + 1, b = (UCHAR_MAX / 2) - 1; const uint8_t result = a + b; ffi_type *args[] = {&ffi_type_uint8, &ffi_type_uint8}; void *values[] = {&a, &b}; uint8_t rc = call(args, values, 2, ffi_type_uint8, (ffi_callback)add_unsigned8); printf("Unsigned 8bit integer result:\t%"PRIu8"\n", rc); assert(rc == result); } /* 16bit signed integer test */ { int16_t a = (SHRT_MAX / 2) + 1, b = (SHRT_MAX / 2) - 1; const int16_t result = a + b; ffi_type *args[] = {&ffi_type_sint16, &ffi_type_sint16}; void *values[] = {&a, &b}; int16_t rc = call(args, values, 2, ffi_type_sint16, (ffi_callback)add_signed16); printf("Signed 16bit integer result:\t%"PRIi16"\n", rc); assert(rc == result); } /* 16bit unsigned integer test */ { uint16_t a = (USHRT_MAX / 2) + 1, b = (USHRT_MAX / 2) - 1; const uint16_t result = a + b; ffi_type *args[] = {&ffi_type_uint16, &ffi_type_uint16}; void *values[] = {&a, &b}; uint16_t rc = call(args, values, 2, ffi_type_uint16, (ffi_callback)add_unsigned16); printf("Unsigned 16bit integer result:\t%"PRIu16"\n", rc); assert(rc == result); } /* 32bit signed integer test */ { int32_t a = (INT_MAX / 2) + 1, b = (INT_MAX / 2) - 1; const int32_t result = a + b; ffi_type *args[] = {&ffi_type_sint32, &ffi_type_sint32}; void *values[] = {&a, &b}; int32_t rc = call(args, values, 2, ffi_type_sint32, (ffi_callback)add_signed32); printf("Signed 32bit integer result:\t%"PRIi32"\n", rc); assert(rc == result); } /* 32bit unsigned integer test */ { uint32_t a = (UINT_MAX / 2) + 1, b = (UINT_MAX / 2) - 1; const uint32_t result = a + b; ffi_type *args[] = {&ffi_type_uint32, &ffi_type_uint32}; void *values[] = {&a, &b}; uint32_t rc = call(args, values, 2, ffi_type_uint32, (ffi_callback)add_unsigned32); printf("Unsigned 32bit integer result:\t%"PRIu32"\n", rc); assert(rc == result); } /* 64bit signed integer test */ { int64_t a = (LONG_MAX / 2) + 1, b = (LONG_MAX / 2) - 1, rc; const int64_t result = a + b; ffi_type *args[] = {&ffi_type_sint64, &ffi_type_sint64}; void *values[] = {&a, &b}; call_ext(args, values, 2, ffi_type_sint64, &rc, (ffi_callback)add_signed64); printf("Signed 64bit integer result:\t%"PRIi64"\n", rc); assert(rc == result); } /* 64bit unsigned integer test */ { uint64_t a = (ULONG_MAX / 2) + 1, b = (ULONG_MAX / 2) - 1, rc; const uint64_t result = a + b; ffi_type *args[] = {&ffi_type_uint64, &ffi_type_uint64}; void *values[] = {&a, &b}; call_ext(args, values, 2, ffi_type_uint64, &rc, (ffi_callback)add_unsigned64); printf("Unsigned 64bit integer result:\t%"PRIu64"\n", rc); assert(rc == result); } /* single precision float test */ { float a = (FLT_MAX / 2.0F) + 0.5F, b = (FLT_MAX / 2.0F) - 0.5F, rc; const float result = a + b; ffi_type *args[] = {&ffi_type_float, &ffi_type_float}; void *values[] = {&a, &b}; call_ext(args, values, 2, ffi_type_float, &rc, (ffi_callback)add_floatS); printf("Single precision float result:\t%f\n", rc); assert(rc == result); } /* double precision float test */ { double a = (DBL_MAX / 2.0) + 0.5, b = (DBL_MAX / 2.0) - 0.5, rc; const double result = a + b; ffi_type *args[] = {&ffi_type_double, &ffi_type_double}; void *values[] = {&a, &b}; call_ext(args, values, 2, ffi_type_double, &rc, (ffi_callback)add_floatD); printf("Double precision float result:\t%lf\n", rc); assert(rc == result); } /* struct test */ { simple_t a = {(INT_MAX / 2) + 1, (INT_MAX / 2) - 1}; simple_t b = {(INT_MAX / 2) - 1, (INT_MAX / 2) + 1}, rc; const simple_t result = {a._1 + b._1, a._2 + b._2}; ffi_type *prim[] = {&ffi_type_sint32, &ffi_type_sint32, NULL}; ffi_type sc = {0, 0, FFI_TYPE_STRUCT, (ffi_type**)&prim}; ffi_type *args[] = {&sc, &sc}; void *values[] = {&a, &b}; call_ext(args, values, 2, sc, &rc, (ffi_callback)add_simple); printf("Simple_t result:\t%d, %d\n", rc._1, rc._2); assert(rc._1 == result._1 && rc._2 == result._2); } exit(EXIT_SUCCESS); }