mirror of
				https://github.com/lxsang/antd-lua-plugin
				synced 2025-10-31 02:15:37 +01:00 
			
		
		
		
	ffi via libffi (contd)
This commit is contained in:
		
							
								
								
									
										2
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								Makefile
									
									
									
									
									
								
							| @@ -3,7 +3,7 @@ include var.mk | |||||||
|  |  | ||||||
| PL_NAME=lua-api | PL_NAME=lua-api | ||||||
| PLUGINS=$(PL_NAME).$(EXT) | PLUGINS=$(PL_NAME).$(EXT) | ||||||
| LLIBS=wurl.llib ulib.llib  ann.llib stmr.llib #pibot.llib | LLIBS=wurl.llib ulib.llib  ann.llib stmr.llib ffi.llib #pibot.llib | ||||||
|   |   | ||||||
| OBJS = 		$(PLUGINS_BASE)/plugin.o  | OBJS = 		$(PLUGINS_BASE)/plugin.o  | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										6
									
								
								lib/ffi/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								lib/ffi/Makefile
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | |||||||
|  | include ../../../../var.mk | ||||||
|  |  | ||||||
|  | LIB_NAME=ffi.$(LIB_EXT) | ||||||
|  | LIB_OBJ=  ffi.o  | ||||||
|  | LIB_CONF= -lffi | ||||||
|  | include ../../lib.mk | ||||||
							
								
								
									
										6
									
								
								lib/ffi/example/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								lib/ffi/example/Makefile
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | |||||||
|  | CC = gcc | ||||||
|  | main: lib.o | ||||||
|  | 	$(CC) -shared lib.o -o libtest.so | ||||||
|  | 	 | ||||||
|  | %.o: %.c | ||||||
|  | 	$(CC)  -fPIC -c $< -o $@ | ||||||
							
								
								
									
										45
									
								
								lib/ffi/example/example.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								lib/ffi/example/example.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | |||||||
|  | local ffi = require("ffi") | ||||||
|  | local path = "/home/mrsang/Desktop/testffi/libtest.so" | ||||||
|  | local lib = nil | ||||||
|  | local fn = nil | ||||||
|  | local rettype = nil | ||||||
|  | local argtype = nil | ||||||
|  | if ffi then | ||||||
|  |     -- now ffi exist | ||||||
|  |     -- try to load the test library | ||||||
|  |     lib = ffi.dlopen(path) | ||||||
|  |     if lib then | ||||||
|  |         -- now try to lookup for the greet function | ||||||
|  |         echo("looking for greet") | ||||||
|  |         fn = ffi.dlsym(lib,"greet") | ||||||
|  |         if fn then | ||||||
|  |             -- now the function found | ||||||
|  |             -- tried to called it | ||||||
|  |             rettype = ffi.atomic_type(0) -- void | ||||||
|  |             if rettype then | ||||||
|  |                 argtype = ffi.atomic_type(20) -- pointer | ||||||
|  |                 if(argtype) then | ||||||
|  |                     -- call the function | ||||||
|  |                     local r = ffi.call(rettype, {argtype}, fn, {"hello world"}) | ||||||
|  |                     if r then | ||||||
|  |                         echo("BIG SUCCESS") | ||||||
|  |                     else | ||||||
|  |                         echo("HELL FAIL") | ||||||
|  |                     end | ||||||
|  |                 else | ||||||
|  |                     echo("argtype not found") | ||||||
|  |                 end | ||||||
|  |             else | ||||||
|  |                 echo("return type not found") | ||||||
|  |             end | ||||||
|  |         else | ||||||
|  |             echo("unable to find greet") | ||||||
|  |         end | ||||||
|  |        ffi.dlclose(lib) | ||||||
|  |     else | ||||||
|  |         echo("unable to load the lib") | ||||||
|  |     end | ||||||
|  | else | ||||||
|  |     echo("cannot find ffi") | ||||||
|  | end | ||||||
|  | echo("end the day") | ||||||
							
								
								
									
										6
									
								
								lib/ffi/example/lib.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								lib/ffi/example/lib.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | |||||||
|  | #include <stdio.h> | ||||||
|  |  | ||||||
|  | void greet(const char* msg) | ||||||
|  | { | ||||||
|  |     printf("%s\n", msg); | ||||||
|  | } | ||||||
							
								
								
									
										333
									
								
								lib/ffi/ffi.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										333
									
								
								lib/ffi/ffi.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,333 @@ | |||||||
|  | /* | ||||||
|  | 	This lib use libffi | ||||||
|  | 	so libffi should be installed in the system | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | #include "../lualib.h" | ||||||
|  | #include "../../lua-api.h" | ||||||
|  | #include "utils.h" | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #include <stdint.h> | ||||||
|  | #include <unistd.h> | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <getopt.h> | ||||||
|  | #include <fcntl.h> | ||||||
|  | #include <sys/ioctl.h> | ||||||
|  | // for library access | ||||||
|  | #include <dlfcn.h> | ||||||
|  | // ffi | ||||||
|  | #include <ffi.h> | ||||||
|  |  | ||||||
|  | #define MAX_FN_ARGC 32 | ||||||
|  | // define atomic type | ||||||
|  | typedef enum ffi_atomic_t { | ||||||
|  | 	L_FFI_TYPE_VOID, | ||||||
|  | 	L_FFI_TYPE_UINT8, | ||||||
|  | 	L_FFI_TYPE_SINT8, | ||||||
|  | 	L_FFI_TYPE_UINT16, | ||||||
|  | 	L_FFI_TYPE_SINT16, | ||||||
|  | 	L_FFI_TYPE_UINT32, | ||||||
|  | 	L_FFI_TYPE_SINT32, | ||||||
|  | 	L_FFI_TYPE_UINT64, | ||||||
|  | 	L_FFI_TYPE_SINT64, | ||||||
|  | 	L_FFI_TYPE_FLOAT, | ||||||
|  | 	L_FFI_TYPE_DOUBLE, | ||||||
|  | 	L_FFI_TYPE_UCHAR, | ||||||
|  | 	L_FFI_TYPE_SCHAR, | ||||||
|  | 	L_FFI_TYPE_USHORT, | ||||||
|  | 	L_FFI_TYPE_SSHORT, | ||||||
|  | 	L_FFI_TYPE_UINT, | ||||||
|  | 	L_FFI_TYPE_SINT, | ||||||
|  | 	L_FFI_TYPE_ULONG, | ||||||
|  | 	L_FFI_TYPE_SLONG, | ||||||
|  | 	L_FFI_TYPE_LONGDOUBLE, | ||||||
|  | 	L_FFI_TYPE_POINTER | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static const ffi_type* ffi_atomic_type_ptrs[] =  | ||||||
|  | { | ||||||
|  | 	&ffi_type_void, | ||||||
|  | 	&ffi_type_uint8, | ||||||
|  | 	&ffi_type_sint8, | ||||||
|  | 	&ffi_type_uint16, | ||||||
|  | 	&ffi_type_sint16, | ||||||
|  | 	&ffi_type_uint32, | ||||||
|  | 	&ffi_type_sint32, | ||||||
|  | 	&ffi_type_uint64, | ||||||
|  | 	&ffi_type_sint64, | ||||||
|  | 	&ffi_type_float, | ||||||
|  | 	&ffi_type_double, | ||||||
|  | 	&ffi_type_uchar, | ||||||
|  | 	&ffi_type_schar, | ||||||
|  | 	&ffi_type_ushort, | ||||||
|  | 	&ffi_type_sshort, | ||||||
|  | 	&ffi_type_uint, | ||||||
|  | 	&ffi_type_sint, | ||||||
|  | 	&ffi_type_ulong, | ||||||
|  | 	&ffi_type_slong, | ||||||
|  | 	&ffi_type_longdouble, | ||||||
|  | 	&ffi_type_pointer, | ||||||
|  | 	NULL | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static int l_dlopen(lua_State* L) | ||||||
|  | { | ||||||
|  |     const char* path = luaL_checkstring(L,1); | ||||||
|  |     void* lib_handle = dlopen(path, RTLD_LAZY); | ||||||
|  | 	if(!lib_handle) | ||||||
|  | 	{ | ||||||
|  | 		lua_pushnil(L); | ||||||
|  | 		return 1; | ||||||
|  | 	} | ||||||
|  | 	// push the handle pointer to lua | ||||||
|  |     lua_pushlightuserdata(L, lib_handle); | ||||||
|  |     return 1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int l_dlclose(lua_State* L) | ||||||
|  | { | ||||||
|  | 	LOG("%s\n","Begin close"); | ||||||
|  | 	void* handle = lua_touserdata(L,1); | ||||||
|  | 	if(!handle) | ||||||
|  | 	{ | ||||||
|  | 		LOG("%s\n","Cannot close that thing, handle not found"); | ||||||
|  | 		lua_pushboolean(L,0); | ||||||
|  | 		return 1; | ||||||
|  | 	} | ||||||
|  | 	LOG("%s\n","the handle is found"); | ||||||
|  | 	dlclose(handle); | ||||||
|  | 	lua_pushboolean(L,1); | ||||||
|  | 	return 1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int l_dlsym(lua_State* L) | ||||||
|  | { | ||||||
|  | 	char* error; | ||||||
|  | 	void* handle = lua_touserdata(L,1); | ||||||
|  | 	const char* fname = luaL_checkstring(L,2); | ||||||
|  | 	void* fn = dlsym(handle, fname); | ||||||
|  | 	if ((error = dlerror()) != NULL)  | ||||||
|  | 	{ | ||||||
|  | 		lua_pushnil(L); | ||||||
|  | 		return 1; | ||||||
|  | 	} | ||||||
|  | 	lua_pushlightuserdata(L, fn); | ||||||
|  | 	return 1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int l_ffi_prepare(lua_State* L, ffi_type** argvtype, int idx) | ||||||
|  | { | ||||||
|  | 	// argument count not more than 64 | ||||||
|  | 	int argc = 0; | ||||||
|  | 	// now loop through the args type table, then fill the argvtype | ||||||
|  |  | ||||||
|  | 	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 | ||||||
|  | 		argvtype[argc] = lua_touserdata(L, -1); | ||||||
|  | 		argc++; | ||||||
|  | 		// pop the value, leaving the original key | ||||||
|  | 		lua_pop(L,1); | ||||||
|  | 		// stack now contains: -1 key; -2 table | ||||||
|  | 	} | ||||||
|  | 	// lua_next return 0, it popout the key at -1, leaving the table | ||||||
|  | 	// so, popout the table | ||||||
|  | 	argvtype[argc] = NULL; | ||||||
|  | 	lua_pop(L,1); | ||||||
|  | 	return argc; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void * parser_value(lua_State* L, int idx, ffi_type* ffitype) | ||||||
|  | { | ||||||
|  | 	lua_Number * value; | ||||||
|  | 	switch(ffitype->type) | ||||||
|  | 	{ | ||||||
|  | 		case FFI_TYPE_VOID : return NULL; | ||||||
|  | 		case FFI_TYPE_POINTER: | ||||||
|  | 			// TODO: need to fix this to universal pointer | ||||||
|  | 			return lua_tostring(L, idx); | ||||||
|  |  | ||||||
|  | 		case FFI_TYPE_UINT8: | ||||||
|  | 		case FFI_TYPE_SINT8: | ||||||
|  | 		case FFI_TYPE_UINT16: | ||||||
|  | 		case FFI_TYPE_SINT16: | ||||||
|  | 		case FFI_TYPE_UINT32: | ||||||
|  | 		case FFI_TYPE_SINT32: | ||||||
|  | 		case FFI_TYPE_UINT64: | ||||||
|  | 		case FFI_TYPE_SINT64: | ||||||
|  | 		case FFI_TYPE_LONGDOUBLE: | ||||||
|  | 		case FFI_TYPE_FLOAT: | ||||||
|  | 		case FFI_TYPE_DOUBLE: | ||||||
|  | 			value = (lua_Number*) malloc(ffitype->size); | ||||||
|  | 			*value = lua_tonumber(L,idx); | ||||||
|  | 			break; | ||||||
|  |  | ||||||
|  | 		 | ||||||
|  | 		case FFI_TYPE_STRUCT: | ||||||
|  | 			// not implemented yet | ||||||
|  | 			return NULL; | ||||||
|  | 			break; | ||||||
|  | 		default: return NULL; | ||||||
|  | 	} | ||||||
|  | 	return (void*)value; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void parser_arguments(lua_State* L, int idx, void** argv, ffi_type** argvtype) | ||||||
|  | { | ||||||
|  | 	// loop through table | ||||||
|  | 	lua_pushvalue(L,idx); | ||||||
|  | 	// stack now contains: -1 => table | ||||||
|  | 	lua_pushnil(L); | ||||||
|  | 	int i = 0; | ||||||
|  | 	// stack now contains: -1 => nil, -2 => table | ||||||
|  | 	while(lua_next(L, -2)) | ||||||
|  | 	{ | ||||||
|  | 		// stack now contains: -1 => value; -2 key; -3 table | ||||||
|  | 		argv[i] = parser_value(L, -1, argvtype[i]); | ||||||
|  | 		i++; | ||||||
|  | 		// pop the value, leaving the original key | ||||||
|  | 		lua_pop(L,1); | ||||||
|  | 		// stack now contains: -1 key; -2 table | ||||||
|  | 	} | ||||||
|  | 	// lua_next return 0, it popout the key at -1, leaving the table | ||||||
|  | 	// so, popout the table | ||||||
|  | 	lua_pop(L,1); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void free_arguments(void** argv, ffi_type** argvtype) | ||||||
|  | { | ||||||
|  | 	ffi_type * ffitype; | ||||||
|  | 	for(int i = 0; argvtype[i] != NULL; i++) | ||||||
|  | 	{ | ||||||
|  | 		ffitype = argvtype[i]; | ||||||
|  | 		switch (ffitype->type) | ||||||
|  | 		{ | ||||||
|  | 			case FFI_TYPE_UINT8: | ||||||
|  | 			case FFI_TYPE_SINT8: | ||||||
|  | 			case FFI_TYPE_UINT16: | ||||||
|  | 			case FFI_TYPE_SINT16: | ||||||
|  | 			case FFI_TYPE_UINT32: | ||||||
|  | 			case FFI_TYPE_SINT32: | ||||||
|  | 			case FFI_TYPE_UINT64: | ||||||
|  | 			case FFI_TYPE_SINT64: | ||||||
|  | 			case FFI_TYPE_LONGDOUBLE: | ||||||
|  | 			case FFI_TYPE_FLOAT: | ||||||
|  | 			case FFI_TYPE_DOUBLE: | ||||||
|  | 				if(argv[i]) free(argv[i]); | ||||||
|  | 				break; | ||||||
|  | 			default: break; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int l_ffi_call(lua_State* L) | ||||||
|  | { | ||||||
|  | 	ffi_type * argvtype[MAX_FN_ARGC]; | ||||||
|  | 	ffi_type * rettype = lua_touserdata(L,1); | ||||||
|  | 	int argc = l_ffi_prepare(L, argvtype, 2); | ||||||
|  | 	printf("Argument count %d\n", argc); | ||||||
|  | 	printf("ret type: %d\n", rettype->type); | ||||||
|  | 	void* argv[MAX_FN_ARGC]; | ||||||
|  | 	ffi_arg ret; | ||||||
|  | 	ffi_cif cif; | ||||||
|  | 	if(ffi_prep_cif(&cif,FFI_DEFAULT_ABI,argc,rettype,argvtype) == FFI_OK) | ||||||
|  | 	{ | ||||||
|  | 		void(* fn)(const char*) = lua_touserdata(L,3); | ||||||
|  | 		if(!fn) | ||||||
|  | 		{ | ||||||
|  | 			LOG("%s\n", "function not found"); | ||||||
|  | 			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 | ||||||
|  | 		//argv = (void**)malloc(sizeof(void*)*argc); | ||||||
|  | 		//ret = (void*)malloc(rettype->size); | ||||||
|  | 		// now parser the argument | ||||||
|  | 		parser_arguments(L,4,argv,argvtype); | ||||||
|  | 		// test | ||||||
|  | 		char* tmp = (char*)argv[0]; | ||||||
|  | 		argv[0] = &tmp; | ||||||
|  | 		ffi_call(&cif,fn, &ret, argv); | ||||||
|  | 		free_arguments(argv, argvtype); | ||||||
|  | 		//if(argv) free(argv); | ||||||
|  | 		//if(ret) free(ret); | ||||||
|  | 		lua_pushboolean(L,1); | ||||||
|  | 		return 1; | ||||||
|  | 	} | ||||||
|  | 	printf("fail to prepare %d\n"); | ||||||
|  | 	lua_pushboolean(L,0); | ||||||
|  | 	 | ||||||
|  | 	return 1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int l_ffi_atomic_type(lua_State* L) | ||||||
|  | { | ||||||
|  | 	int etype = (int)luaL_checknumber(L,1); | ||||||
|  | 	ffi_type* type = NULL;  | ||||||
|  | 	if(etype > L_FFI_TYPE_POINTER) | ||||||
|  | 	{ | ||||||
|  | 		lua_pushnil(L); | ||||||
|  | 		return 1; | ||||||
|  | 	} | ||||||
|  | 	type = ffi_atomic_type_ptrs[etype]; | ||||||
|  | 	lua_pushlightuserdata(L,type); | ||||||
|  | 	return 1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | 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)  ); | ||||||
|  | 	int i = 0; | ||||||
|  |     cstruct->size = cstruct->alignment = 0; | ||||||
|  |     cstruct->type = FFI_TYPE_STRUCT; | ||||||
|  |     // now iterate the lua table to pick all the type | ||||||
|  |  | ||||||
|  | 	lua_pushvalue(L,1); | ||||||
|  | 	// 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 | ||||||
|  | 		cstruct->elements[i] = lua_touserdata(L, -1); | ||||||
|  | 		i++; | ||||||
|  | 		// pop the value, leaving the original key | ||||||
|  | 		lua_pop(L,1); | ||||||
|  | 		// stack now contains: -1 key; -2 table | ||||||
|  | 	} | ||||||
|  | 	// null terminated elements | ||||||
|  | 	cstruct->elements[i] = NULL; | ||||||
|  | 	// lua_next return 0, it popout the key at -1, leaving the table | ||||||
|  | 	// so, popout the table | ||||||
|  | 	lua_pop(L,1); | ||||||
|  | 	// the top of the stack is now the new user data | ||||||
|  | 	return 1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static const struct luaL_Reg _lib [] = { | ||||||
|  | 	{"dlopen", l_dlopen}, | ||||||
|  | 	{"dlsym",l_dlsym}, | ||||||
|  | 	{"dlclose",l_dlclose}, | ||||||
|  | 	{"call",l_ffi_call}, | ||||||
|  | 	{"atomic_type", l_ffi_atomic_type}, | ||||||
|  | 	{"struct", l_ffi_struct }, | ||||||
|  | 	{NULL,NULL} | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | int luaopen_ffi(lua_State *L) | ||||||
|  | { | ||||||
|  | 	luaL_newlib(L, _lib); | ||||||
|  | 	return 1; | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user