/** * 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, ffi_type *retarg, size_t len, ffi_callback func) { ffi_cif cif; ffi_arg rc; /* Iniitalize the cif */ int ret = ffi_prep_cif(&cif, FFI_DEFAULT_ABI, len, retarg, 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; } int main(void) { ffi_cif cif; /* 8bit signed integer test */ { int8_t a = (CHAR_MAX / 2) + 1, b = (CHAR_MAX / 2) - 1; const int8_t result = a + b; ffi_type *args[] = {&ffi_type_sint8, &ffi_type_sint8}; void *values[] = {&a, &b}; ffi_arg rc = call(args, values, &ffi_type_sint8, 2, (ffi_callback)add_signed8); printf("Signed 8bit integer result:\t%"PRIi8"\n", (int8_t)rc); assert( (int8_t)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}; ffi_arg rc = call(args, values, &ffi_type_uint8, 2, (ffi_callback)add_unsigned8); printf("Unsigned 8bit integer result:\t%"PRIu8"\n", (uint8_t)rc); assert( (uint8_t)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}; ffi_arg rc = call(args, values, &ffi_type_sint16, 2, (ffi_callback)add_signed16); printf("Signed 16bit integer result:\t%"PRIi16"\n", (int16_t)rc); assert( (int16_t)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}; ffi_arg rc = call(args, values, &ffi_type_uint16, 2, (ffi_callback)add_unsigned16); printf("Unsigned 16bit integer result:\t%"PRIu16"\n", (uint16_t)rc); assert( (uint16_t)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}; ffi_arg rc = call(args, values, &ffi_type_sint32, 2, (ffi_callback)add_signed32); printf("Signed 32bit integer result:\t%"PRIi32"\n", (int32_t)rc); assert( (int32_t)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}; ffi_arg rc = call(args, values, &ffi_type_uint32, 2, (ffi_callback)add_unsigned32); printf("Unsigned 32bit integer result:\t%"PRIu32"\n", (uint32_t)rc); assert( (uint32_t)rc == result ); } /* 64bit signed integer test */ { int64_t a = (LONG_MAX / 2) + 1, b = (LONG_MAX / 2) - 1; const int64_t result = a + b; ffi_type *args[] = {&ffi_type_sint64, &ffi_type_sint64}; void *values[] = {&a, &b}; ffi_arg rc = call(args, values, &ffi_type_sint64, 2, (ffi_callback)add_signed64); const int64_t *src = (int64_t*)&rc; printf("Signed 64bit integer result:\t%"PRIi64", expected: %"PRIi64"\n", *src, result); assert( *src == result ); } /* 64bit unsigned integer test */ { uint64_t a = (ULONG_MAX / 2) + 1, b = (ULONG_MAX / 2) - 1; const uint64_t result = a + b; ffi_type *args[] = {&ffi_type_uint64, &ffi_type_uint64}; void *values[] = {&a, &b}; ffi_arg rc = call(args, values, &ffi_type_uint64, 2, (ffi_callback)add_unsigned64); const uint64_t *urc = (uint64_t*)&rc; printf("Unsigned 64bit integer result:\t%"PRIu64"\n", *urc); assert( *urc == result ); } /* single precision float test */ { float a = (FLT_MAX / 2.0F) + 0.5F, b = (FLT_MAX / 2.0F) - 0.5F; const float result = a + b; ffi_type *args[] = {&ffi_type_float, &ffi_type_float}; void *values[] = {&a, &b}; ffi_arg rc = call(args, values, &ffi_type_float, 2, (ffi_callback)add_floatS); const float *frc = (float*)&rc; printf("Single precision float result:\t%f\n", *frc); assert( *frc == result ); } /* double precision float test */ { double a = (DBL_MAX / 2.0) + 0.5, b = (DBL_MAX / 2.0) - 0.5; const double result = a + b; ffi_type *args[] = {&ffi_type_double, &ffi_type_double}; void *values[] = {&a, &b}; ffi_arg rc = call(args, values, &ffi_type_double, 2, (ffi_callback)add_floatD); const double *frc = (double*)&rc; printf("Double precision float result:\t%lf\n", *frc); assert( *frc == result ); } #if 0 /* struct test */ { simple_t a = {(INT_MAX / 2) + 1, (INT_MAX / 2) - 1}; simple_t b = {(INT_MAX / 2) - 1, (INT_MAX / 2) + 1}; const simple_t result = {a._1 + b._1, a._2 + b._2}; ffi_type *args[] = {&ffi_type_pointer, &ffi_type_pointer}; void *values[] = {&a, &b}; ffi_arg rc = call(args, values, &ffi_type_pointer, 2, (ffi_callback)add_simple); const simple_t *src = (simple_t*)&rc; printf("Simple_t result:\t%d, %d\n", src->_1, src->_2); assert( src->_1 == result._1 && src->_2 == result._2 ); } #endif exit(EXIT_SUCCESS); }