From 0ac77828e7d1558e05887350151ef573477487aa Mon Sep 17 00:00:00 2001 From: lxsang Date: Fri, 3 May 2019 13:17:45 +0200 Subject: [PATCH] working ffi --- lib.mk | 2 +- lib/ffi/example/example.lua | 70 +++++--- lib/ffi/example/lib.c | 30 +++- lib/ffi/ffi.c | 331 +++++++++++++++++++++++++++++------- 4 files changed, 338 insertions(+), 95 deletions(-) diff --git a/lib.mk b/lib.mk index ba68680..f0d4e2b 100644 --- a/lib.mk +++ b/lib.mk @@ -2,7 +2,7 @@ include ../../var.mk main:$(LIB_OBJ) $(LIB_NAME) %.o: %.c - $(CC) $(LIB_CFLAGS) $(LIB_INC) -fPIC $(LUA_H) -I$(REAL_PLUGINS_BASE) -c $< -o $@ + $(CC) $(LIB_CFLAGS) -D DEBUG $(LIB_INC) -fPIC $(LUA_H) -I$(REAL_PLUGINS_BASE) -c $< -o $@ %.$(LIB_EXT): %.o -mkdir $(LIB_BUILD_DIR) diff --git a/lib/ffi/example/example.lua b/lib/ffi/example/example.lua index 34dcaa7..f4ae5ce 100644 --- a/lib/ffi/example/example.lua +++ b/lib/ffi/example/example.lua @@ -1,5 +1,5 @@ +local path = "/home/blackjack/workspace/ant-http/plugins/antd-lua-plugin/lib/ffi/example/libtest.so" require("cif") -local path = "/Users/mrsang/Google Drive/ushare/cwp/ant-http/plugins/antd-lua-plugin/lib/ffi/example/libtest.so" local lib = nil local fn = nil local rettype = nil @@ -7,38 +7,54 @@ local argtype = nil lib = FFI.load(path) if lib then -- now try to lookup for the greet function - echo("looking for greet") fn = FFI.lookup(lib,"greet") if fn then - -- now the function found + -- now the function -- tried to called it - rettype = FFI.atomic(FFI.type.VOID) -- void - if rettype then - argtype = { - FFI.atomic(FFI.type.POINTER), - FFI.atomic(FFI.type.DOUBLE), - FFI.atomic(FFI.type.SINT64), - FFI.atomic(FFI.type.SINT8) - } -- pointer - if(argtype) then - -- call the function - local r = FFI.call(rettype, argtype, fn, {"hello world", 0.987, -76, 65}) - if r then - echo("BIG SUCCESS") - else - echo("HELL FAIL") - end - else - echo("argtype not found") - end + rettype = FFI.atomic(FFI.type.UINT8) -- voidn + argtype = { + FFI.atomic(FFI.type.POINTER), + FFI.atomic(FFI.type.DOUBLE), + FFI.atomic(FFI.type.SINT64), + FFI.atomic(FFI.type.SINT8) + } -- pointer + -- call the function + local r = FFI.call(rettype, argtype, fn, {"hello world", 0.987, -76, 65}) + if r then + echo(r) else - echo("return type not found") + echo("HELL FAIL") end - else - echo("unable to find greet") end + fn = FFI.lookup(lib, "test_struct") + if fn then + local struct1 = FFI.struct({ + FFI.atomic(FFI.type.UINT8), -- char + FFI.atomic(FFI.type.SINT32), -- char + FFI.atomic(FFI.type.SINT16), -- char + FFI.atomic(FFI.type.UINT8), -- char + }) + local struct = FFI.struct({ + FFI.atomic(FFI.type.UINT8), -- char + struct1, + FFI.atomic(FFI.type.SINT32), -- int + FFI.atomic(FFI.type.UINT8), -- char + }) + rettype = struct --FFI.atomic(FFI.type.DOUBLE) + echo("call with struct") + local r = FFI.call(rettype,{struct},fn,{{65, {66, 2048, -97,67},-1024, 68}}) + if r then echo(JSON.encode(r)) end + --echo(JSON.encode(FFI.meta(struct1))) + end + + fn = FFI.lookup(lib, "test_string") + if(fn) then + local buff = FFI.new(256) + FFI.call(FFI.atomic(FFI.type.VOID),{FFI.atomic(FFI.type.POINTER), FFI.atomic(FFI.type.POINTER)}, fn, {buff,"Hello world"}) + echo(FFI.string(buff)) + + end + FFI.unloadAll() -else - echo("unable to load the lib") end echo("end the day") \ No newline at end of file diff --git a/lib/ffi/example/lib.c b/lib/ffi/example/lib.c index e801162..caef882 100644 --- a/lib/ffi/example/lib.c +++ b/lib/ffi/example/lib.c @@ -1,6 +1,34 @@ #include -void greet(const char* msg, float num, int sint, char c) + +typedef struct{ + char a; + int b; + short c; + char d; +} inner_t; + +typedef struct{ + char a; + inner_t b; + int c; + char d; +} test_t; + +char greet(const char* msg, float num, int sint, char c) { printf("%s: '%f' '%d' '%c'\n", msg, num, sint, c); + return 'A'; } + +test_t test_struct(test_t data) +{ + printf("data is '%c' '%c' '%d' '%d' '%c' '%d' '%c'\n", data.a, data.b.a, data.b.b, data.b.c, data.b.d, data.c, data.d); + return data; +} + +void test_string(char* buff, const char* a) +{ + sprintf(buff,"you say %s", a); + printf("%s\n", buff); +} \ No newline at end of file diff --git a/lib/ffi/ffi.c b/lib/ffi/ffi.c index b8d5f74..41e2be6 100644 --- a/lib/ffi/ffi.c +++ b/lib/ffi/ffi.c @@ -22,11 +22,6 @@ #define MAX_FN_ARGC 32 -typedef struct { - uint8_t allocated; - uint8_t is_pointer; - void* data; -} arg_pointer_t; // define atomic type typedef enum ffi_atomic_t { L_FFI_TYPE_VOID, @@ -146,84 +141,102 @@ static int l_ffi_prepare(lua_State* L, ffi_type** argvtype, int idx) return argc; } -void parser_value(lua_State* L, int idx, ffi_type* ffitype, arg_pointer_t * ptr) +void parser_value(lua_State* L, int idx, ffi_type* ffitype, void * data) { - ptr->allocated = 1; - ptr->is_pointer = 0; + intptr_t address = (intptr_t) data; + int offset = 0; + int pad = 0; + int i = 0; switch(ffitype->type) { case FFI_TYPE_POINTER: - ptr->allocated = 0; - ptr->is_pointer = 1; - ptr->data = (void*)lua_tostring(L, idx); + if(lua_isstring(L,idx)) + *((void**)data) = (void*)lua_tostring(L, idx); + else + *((void**)data) = (void*)lua_touserdata(L, idx); return; case FFI_TYPE_UINT8: - ptr->data = (void*) malloc(ffitype->size); - *((uint8_t*)ptr->data) = (uint8_t)lua_tonumber(L,idx); + *((uint8_t*)data) = (uint8_t)lua_tonumber(L,idx); return; case FFI_TYPE_SINT8: - ptr->data = (void*) malloc(ffitype->size); - *((int8_t*)ptr->data) = (int8_t)lua_tonumber(L,idx); + *((int8_t*)data) = (int8_t)lua_tonumber(L,idx); return; case FFI_TYPE_UINT16: - ptr->data = (void*) malloc(ffitype->size); - *((uint16_t*)ptr->data) = (uint16_t)lua_tonumber(L,idx); + *((uint16_t*)data) = (uint16_t)lua_tonumber(L,idx); return; case FFI_TYPE_SINT16: - ptr->data = (void*) malloc(ffitype->size); - *((int16_t*)ptr->data) = (int16_t)lua_tonumber(L,idx); + *((int16_t*)data) = (int16_t)lua_tonumber(L,idx); return; case FFI_TYPE_UINT32: - ptr->data = (void*) malloc(ffitype->size); - *((uint32_t*)ptr->data) = (uint32_t)lua_tonumber(L,idx); + *((uint32_t*)data) = (uint32_t)lua_tonumber(L,idx); return; case FFI_TYPE_SINT32: - ptr->data = (void*) malloc(ffitype->size); - *((int32_t*)ptr->data) = (int32_t)lua_tonumber(L,idx); + *((int32_t*)data) = (int32_t)lua_tonumber(L,idx); return; case FFI_TYPE_UINT64: - ptr->data = (void*) malloc(ffitype->size); - *((uint64_t*)ptr->data) = (uint64_t)lua_tonumber(L,idx); + *((uint64_t*)data) = (uint64_t)lua_tonumber(L,idx); return; case FFI_TYPE_SINT64: - ptr->data = (void*) malloc(ffitype->size); - *((int64_t*)ptr->data) = (int64_t)lua_tonumber(L,idx); + *((int64_t*)data) = (int64_t)lua_tonumber(L,idx); return; case FFI_TYPE_LONGDOUBLE: /*This is bug in lua*/ - ptr->data = (void*) malloc(ffitype->size); - *((long double*)ptr->data) = (long double)lua_tonumber(L,idx); + *((long double*)data) = (long double)lua_tonumber(L,idx); return; case FFI_TYPE_FLOAT: case FFI_TYPE_DOUBLE: - ptr->data = (void*) malloc(ffitype->size); - *((float*)ptr->data) = (float)lua_tonumber(L,idx); + *((float*)data) = (float)lua_tonumber(L,idx); return; - /*case FFI_TYPE_STRUCT: - // not implemented yet - return NULL; - break;*/ - default: - ptr->allocated = 0; - ptr->is_pointer = 0; - ptr->data = NULL; - break; + case FFI_TYPE_STRUCT: + // loop through the table + lua_pushvalue(L,idx); + // stack now contains: -1 => table + lua_pushnil(L); + // stack now contains: -1 => nil, -2 => table + while(lua_next(L, -2)) + { + // stack now contains: -1 => value; -2 key; -3 table + parser_value(L, -1, ffitype->elements[i],data+offset); + // pop the value, leaving the original key + lua_pop(L,1); + // stack now contains: -1 key; -2 table + // recalculate offs + address += ffitype->elements[i]->size; + if(ffitype->elements[i+1]) + { + pad = address % ffitype->elements[i+1]->alignment; + if( pad != 0) + { + pad = ffitype->elements[i+1]->alignment - pad; + } + + address += pad; + offset += ffitype->elements[i]->size + pad; + } + i++; + } + // lua_next return 0, it popout the key at -1, leaving the table + // so, popout the table + lua_pop(L,1); + return; + + default: return; } } -static void parser_arguments(lua_State* L, int idx, arg_pointer_t* argv, ffi_type** argvtype) +static void parser_arguments(lua_State* L, int idx, void** argv, ffi_type** argvtype) { // loop through table lua_pushvalue(L,idx); @@ -234,7 +247,8 @@ static void parser_arguments(lua_State* L, int idx, arg_pointer_t* argv, ffi_typ while(lua_next(L, -2)) { // stack now contains: -1 => value; -2 key; -3 table - parser_value(L, -1, argvtype[i],&argv[i]); + argv[i] = (void*)malloc(argvtype[i]->size); + parser_value(L, -1, argvtype[i],argv[i]); i++; // pop the value, leaving the original key lua_pop(L,1); @@ -245,25 +259,102 @@ static void parser_arguments(lua_State* L, int idx, arg_pointer_t* argv, ffi_typ lua_pop(L,1); } -static void free_arguments(arg_pointer_t* argv, int argc) + +static void ffi_post_call(lua_State* L, void* ret, ffi_type* rettype) { - for(int i = 0; i< argc; i++) + if(!ret) { - if(argv[i].allocated) - free(argv[i].data); + lua_pushnil(L); + return; + } + int i = 0; + intptr_t address = (intptr_t) ret; + int offset = 0; + int pad = 0; + switch (rettype->type) + { + case FFI_TYPE_POINTER: + lua_pushlightuserdata(L,ret); + break; + + case FFI_TYPE_UINT8: + lua_pushnumber(L, (lua_Number)(*((uint8_t*)ret))); + break; + case FFI_TYPE_SINT8: + lua_pushnumber(L, (lua_Number)(*((int8_t*)ret))); + break; + case FFI_TYPE_UINT16: + lua_pushnumber(L, (lua_Number)(*((uint16_t*)ret))); + break; + case FFI_TYPE_SINT16: + lua_pushnumber(L, (lua_Number)(*((int16_t*)ret))); + break; + case FFI_TYPE_UINT32: + lua_pushnumber(L, (lua_Number)(*((uint32_t*)ret))); + break; + case FFI_TYPE_SINT32: + lua_pushnumber(L, (lua_Number)(*((int32_t*)ret))); + break; + case FFI_TYPE_UINT64: + lua_pushnumber(L, (lua_Number)(*((uint64_t*)ret))); + break; + case FFI_TYPE_SINT64: + lua_pushnumber(L, (lua_Number)(*((int64_t*)ret))); + break; + case FFI_TYPE_LONGDOUBLE: + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + lua_pushnumber(L, *((double*)ret)); + break; + case FFI_TYPE_STRUCT: + lua_newtable(L); + for ( i = 0; rettype->elements[i] != NULL; i++) + { + lua_pushnumber(L,i); + ffi_post_call(L, ret + offset,rettype->elements[i]); + lua_settable(L, -3); + address += rettype->elements[i]->size; + if(rettype->elements[i+1]) + { + pad = address % rettype->elements[i+1]->alignment; + if( pad != 0) + { + pad = rettype->elements[i+1]->alignment - pad; + } + + address += pad; + offset += rettype->elements[i]->size + pad; + } + } + break; + + default: + lua_pushnil(L); + break; + } +} +/* +static void dump(ffi_type* st) +{ + printf("Type: %d %d\n", st->size, st->alignment); + if(st->type == FFI_TYPE_STRUCT) + for (int i = 0; st->elements[i] != NULL; i++) + { + dump(st->elements[i]); } } - +*/ static int l_ffi_call(lua_State* L) { ffi_type * argvtype[MAX_FN_ARGC]; void* argv[MAX_FN_ARGC]; ffi_type * rettype = lua_touserdata(L,1); int argc = l_ffi_prepare(L, argvtype, 2); - arg_pointer_t* args; - ffi_arg ret; + int len = lua_rawlen(L,4); + void* ret = NULL; ffi_cif cif; + //dump(argvtype[0]); if(ffi_prep_cif(&cif,FFI_DEFAULT_ABI,argc,rettype,argvtype) == FFI_OK) { void * fn = lua_touserdata(L,3); @@ -273,34 +364,28 @@ static int l_ffi_call(lua_State* L) lua_pushboolean(L,0); return 1; } - if(lua_rawlen(L,4) != argc) + if(len != argc) { - LOG("%s\n", "Argument count does not not match"); + LOG("Argument count does not not match: expected %d, but have: %d\n", argc, len); lua_pushboolean(L,0); return 1; } // the arguments of the function is at 4th position on the stack // we need to loop through this table and check if argument type // is correct to the definition in argvtype - args = (arg_pointer_t*)malloc(sizeof(arg_pointer_t)*(argc+1)); - //ret = (void*)malloc(rettype->size); - // now parser the argument - parser_arguments(L,4,args,argvtype); - + parser_arguments(L,4,argv,argvtype); + if(rettype->type != FFI_TYPE_VOID) + ret = (void*)malloc(rettype->size); + ffi_call(&cif,fn, ret, argv); for(int i = 0; i< argc; i++) { - if(args[i].is_pointer && args[i].data) - argv[i] = &(args[i].data); - else - argv[i] = args[i].data; + if(argv[i]) free(argv[i]); } - ffi_call(&cif,fn, &ret, argv); - free_arguments(args, argc); - if(args) free(args); - lua_pushboolean(L,1); + ffi_post_call(L,ret, rettype); + if(ret) free(ret); + //lua_pushboolean(L,1); return 1; } - printf("fail to prepare %d\n"); lua_pushboolean(L,0); return 1; @@ -325,7 +410,9 @@ static int l_ffi_struct(lua_State* L) // 1st element in the stack is the // struct table int len = lua_rawlen(L,1); - ffi_type* cstruct = lua_newuserdata(L, (len+2) * sizeof(ffi_type) ); + ffi_type* cstruct = lua_newuserdata(L,sizeof(ffi_type) + (len+1) * sizeof(ffi_type*)); + void *ptr = (void*)cstruct+(sizeof(ffi_type)); + cstruct->elements = (ffi_type**)ptr; int i = 0; cstruct->size = cstruct->alignment = 0; cstruct->type = FFI_TYPE_STRUCT; @@ -353,6 +440,112 @@ static int l_ffi_struct(lua_State* L) return 1; } +static int l_ffi_new(lua_State* L) +{ + int size = luaL_checkinteger(L, 1); + void* ptr = lua_newuserdata(L, size); + memset(ptr,size,0); + return 1; +} + +static int l_ffi_meta(lua_State* L) +{ + ffi_type* type = lua_touserdata(L,1); + if(type) + { + lua_newtable(L); + lua_pushstring(L,"size"); + lua_pushnumber(L, type->size); + lua_settable(L, -3); + + lua_pushstring(L,"alignment"); + lua_pushnumber(L, type->alignment); + lua_settable(L, -3); + + lua_pushstring(L,"type"); + switch (type->type) + { + case FFI_TYPE_POINTER: + lua_pushstring(L, "POINTER"); + break; + + case FFI_TYPE_UINT8: + lua_pushstring(L, "UINT8"); + break; + case FFI_TYPE_SINT8: + lua_pushstring(L, "SINT8"); + break; + case FFI_TYPE_UINT16: + lua_pushstring(L, "UINT16"); + break; + case FFI_TYPE_SINT16: + lua_pushstring(L, "SINT16"); + break; + case FFI_TYPE_UINT32: + lua_pushstring(L, "UINT32"); + break; + case FFI_TYPE_SINT32: + lua_pushstring(L, "SINT32"); + break; + case FFI_TYPE_UINT64: + lua_pushstring(L, "UINT64"); + break; + case FFI_TYPE_SINT64: + lua_pushstring(L, "SINT64"); + break; + case FFI_TYPE_LONGDOUBLE: + lua_pushstring(L, "LONGDOUBLE"); + break; + case FFI_TYPE_FLOAT: + lua_pushstring(L, "FLOAT"); + break; + case FFI_TYPE_DOUBLE: + lua_pushstring(L, "DOUBLE"); + break; + case FFI_TYPE_STRUCT: + lua_pushstring(L, "STRUCT"); + break; + default: + lua_pushnil(L); + break; + } + + lua_settable(L, -3); + return 1; + } + lua_pushnil(L); + return 1; +} + +static int l_ffi_offset(lua_State* L) +{ + void* ptr = lua_touserdata(L, 1); + int off = luaL_checkinteger(L,2); + if(ptr) + { + lua_pushlightuserdata(L, ptr + off); + return 1; + } + lua_pushnil(L); + return 1; +} +static int l_ffi_string(lua_State* L) +{ + void* ptr = lua_touserdata(L,1); + if(ptr) + lua_pushstring(L, (const char*)ptr); + else + lua_pushstring(L, ""); + return 1; +} +static int l_ffi_free(lua_State* L) +{ + void* ptr = lua_touserdata(L,1); + if(ptr) + free(ptr); + lua_pushboolean(L, 1); + return 1; +} static const struct luaL_Reg _lib [] = { {"dlopen", l_dlopen}, {"dlsym",l_dlsym}, @@ -360,6 +553,12 @@ static const struct luaL_Reg _lib [] = { {"call",l_ffi_call}, {"atomic", l_ffi_atomic_type}, {"struct", l_ffi_struct }, + {"new", l_ffi_new}, + {"meta", l_ffi_meta}, + {"at", l_ffi_offset}, + // special case: pointer to string + {"string", l_ffi_string}, + {"free", l_ffi_free}, {NULL,NULL} };