From: Yicheng Qin <qycqycqycqycqyc@xxxxxxxxx> kp_ffi_call function calls into C functions according to arguments passed in ktap vm stack. Only support x86_64 platform now, but it is rather easy to add support for new platforms. Signed-off-by: Yicheng Qin <qycqycqycqycqyc@xxxxxxxxx> Signed-off-by: Qingping Hou <qingping.hou@xxxxxxxxx> --- interpreter/ffi/call_x86_64.S | 139 ++++++++++++++++ interpreter/ffi/cdata.c | 68 ++++++++ interpreter/ffi/ffi_call.c | 361 ++++++++++++++++++++++++++++++++++++++++++ interpreter/ffi/ffi_symbol.c | 172 ++++++++++++++++++++ interpreter/ffi/ffi_util.c | 93 +++++++++++ 5 files changed, 833 insertions(+) create mode 100644 interpreter/ffi/call_x86_64.S create mode 100644 interpreter/ffi/cdata.c create mode 100644 interpreter/ffi/ffi_call.c create mode 100644 interpreter/ffi/ffi_symbol.c create mode 100644 interpreter/ffi/ffi_util.c diff --git a/interpreter/ffi/call_x86_64.S b/interpreter/ffi/call_x86_64.S new file mode 100644 index 0000000..e109f72 --- /dev/null +++ b/interpreter/ffi/call_x86_64.S @@ -0,0 +1,139 @@ +/* + * call_x86_64.S - assembly code to call C function and handle return value + * + * This file is part of ktap by zhangwei(Jovi). + * + * Copyright (C) 2012-2013 zhangwei(Jovi) <jovi.zhangwei@xxxxxxxxx>. + * See the COPYRIGHT file at the top-level directory of this distribution. + * + * ktap is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * ktap is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + */ + + +#ifdef __x86_64 + + .file "call_x86_64.S" + .text + +/* ffi_call_assem_x86_64(void *stack, void *temp_stack, + * void *func_addr, void *rvalue, ffi_type rftype) + * @stack: base address of register values and new stack + * @temp_stack: stack to store temporary values + * @func_addr: Function address + * @rvalue: where to put return value + * @rftype: FFI type of return value + */ + .align 2 + .globl ffi_call_assem_x86_64 + .type ffi_call_assem_x86_64,@function + +ffi_call_assem_x86_64: + movq %rsp, %rax /* save return address */ + /* move stuffs to temp memory region(void *temp_stack) */ + movq %rcx, (%rsi) /* save pointer to return value */ + movq %rbp, 8(%rsi) /* save %rbp */ + movq %rax, 16(%rsi) /* save %rsp */ + movq %r8, 24(%rsi) /* save return_ffi_type */ + movq %rsi, %rbp /* point %rbp to temp memory region */ + + movq %rdx, %r11 /* move function address to %r11 */ + + movq %rdi, %r10 /* set %r10 point to register region */ + movq (%r10), %rdi /* load registers */ + movq 8(%r10), %rsi + movq 16(%r10), %rdx + movq 24(%r10), %rcx + movq 32(%r10), %r8 + movq 40(%r10), %r9 + leaq 48(%r10), %rsp + + callq *%r11 + + movq 16(%rbp), %rsp /* restore return address */ + + movq (%rbp), %rcx /* get pointer to return value */ + movq 24(%rbp), %r8 /* get return_ffi_type */ + movq 8(%rbp), %rbp /* restore rbp */ + + leaq .Lreturn_table(%rip), %r11 /* start address of return_table */ + movslq (%r11, %r8, 8), %r11 /* fetch target address from table */ + jmpq *%r11 /* jump according to value in table */ + + .align 8 +.Lreturn_table: + .quad .Lreturn_void /* FFI_VOID */ + .quad .Lreturn_uint8 /* FFI_UINT8 */ + .quad .Lreturn_int8 /* FFI_INT8 */ + .quad .Lreturn_uint16 /* FFI_UINT16 */ + .quad .Lreturn_int16 /* FFI_INT16 */ + .quad .Lreturn_uint32 /* FFI_UINT32 */ + .quad .Lreturn_int32 /* FFI_INT32 */ + .quad .Lreturn_uint64 /* FFI_UINT64 */ + .quad .Lreturn_int64 /* FFI_INT64 */ + .quad .Lreturn_ptr /* FFI_PTR */ + .quad .Lreturn_func /* FFI_FUNC */ + .quad .Lreturn_struct /* FFI_STRUCT */ + .quad .Lreturn_unknown /* FFI_UNKNOWN */ + + .align 8 +.Lreturn_void: +.Lreturn_func: +.Lreturn_unknown: + retq + .align 8 +.Lreturn_uint8: + movzbq %al, %rax + movq %rax, (%rcx) + retq + .align 8 +.Lreturn_int8: + movsbq %al, %rax + movq %rax, (%rcx) + retq + .align 8 +.Lreturn_uint16: + movzwq %ax, %rax + movq %rax, (%rcx) + retq + .align 8 +.Lreturn_int16: + movswq %ax, %rax + movq %rax, (%rcx) + retq + .align 8 +.Lreturn_uint32: + movl %eax, %eax + movq %rax, (%rcx) + retq + .align 8 +.Lreturn_int32: + movslq %eax, %rax + movq %rax, (%rcx) + retq + .align 8 +.Lreturn_uint64: +.Lreturn_int64: +.Lreturn_ptr: + movq %rax, (%rcx) + retq +/* Struct type indicates that struct is put into at most two registers, + * and 16 bytes space is always available + */ + .align 8 +.Lreturn_struct: + movq %rax, (%rcx) + movq %rdx, 8(%rcx) + retq + +#endif /* end for __x86_64 */ diff --git a/interpreter/ffi/cdata.c b/interpreter/ffi/cdata.c new file mode 100644 index 0000000..af8b05a --- /dev/null +++ b/interpreter/ffi/cdata.c @@ -0,0 +1,68 @@ +/* + * cdata.c - support functions for ktap_cdata + * + * This file is part of ktap by zhangwei(Jovi). + * + * Copyright (C) 2012-2013 zhangwei(Jovi) <jovi.zhangwei@xxxxxxxxx>. + * See the COPYRIGHT file at the top-level directory of this distribution. + * + * ktap is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * ktap is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + */ + + +#include "../../include/ktap_types.h" +#include "../kp_obj.h" +#include "../kp_ffi.h" + +ktap_cdata *kp_cdata_new(ktap_state *ks) +{ + ktap_cdata *cd; + + cd = &kp_newobject(ks, KTAP_TCDATA, sizeof(ktap_cdata), NULL)->cd; + + return cd; +} + +ktap_cdata *kp_cdata_new_ptr(ktap_state *ks, void *addr, csymbol_id id) +{ + ktap_cdata *cd; + + cd = kp_cdata_new(ks); + cd_set_csym_id(cd, id); + cd_ptr(cd) = addr; + + return cd; +} + +ktap_cdata *kp_cdata_new_struct(ktap_state *ks, void *val, csymbol_id id) +{ + ktap_cdata *cd; + + cd = kp_cdata_new(ks); + cd_set_csym_id(cd, id); + cd_struct(cd) = val; + + return cd; +} + +void kp_cdata_dump(ktap_state *ks, ktap_cdata *cd) +{ + switch (cd_type(ks, cd)) { + case FFI_PTR: + kp_printf(ks, "pointer(%p)", cd_ptr(cd)); + break; + default: + kp_printf(ks, "unsupported cdata type %d!\n", cd_type(ks, cd)); + } +} diff --git a/interpreter/ffi/ffi_call.c b/interpreter/ffi/ffi_call.c new file mode 100644 index 0000000..4475d72 --- /dev/null +++ b/interpreter/ffi/ffi_call.c @@ -0,0 +1,361 @@ +/* + * ffi_call.c - foreign function calling library support for ktap + * + * This file is part of ktap by zhangwei(Jovi). + * + * Copyright (C) 2012-2013 zhangwei(Jovi) <jovi.zhangwei@xxxxxxxxx>. + * See the COPYRIGHT file at the top-level directory of this distribution. + * + * ktap is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * ktap is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <linux/ctype.h> +#include <linux/slab.h> +#include "../../include/ktap_types.h" +#include "../ktap.h" +#include "../kp_vm.h" +#include "../kp_obj.h" +#include "../kp_ffi.h" + +static int ffi_type_check(ktap_state *ks, csymbol *cs, StkId arg, int idx) +{ + ffi_type type = csym_type(cs); + + if (type == FFI_FUNC) + goto error; + + switch (ttypenv(arg)) { + case KTAP_TLIGHTUSERDATA: + if (type != FFI_PTR) goto error; + break; + case KTAP_TBOOLEAN: + case KTAP_TNUMBER: + if (type != FFI_UINT8 && type != FFI_INT8 + && type != FFI_UINT16 && type != FFI_INT16 + && type != FFI_UINT32 && type != FFI_INT32 + && type != FFI_UINT64 && type != FFI_INT64) + goto error; + break; + case KTAP_TSTRING: + if (type != FFI_PTR && type != FFI_UINT8 && type != FFI_INT8) + goto error; + break; + case KTAP_TCDATA: + if (cs != cd_csym(ks, cdvalue(arg))) + goto error; + break; + default: + goto error; + } + return 0; + + error: + kp_error(ks, "Error: Cannot convert to csymbol %s for arg %d\n", + csym_name(cs), idx); + return -1; +} + + +static void ffi_unpack(ktap_state *ks, csymbol *cs, StkId arg, char *dst) +{ + ffi_type type = csym_type(cs); + size_t size = csym_size(ks, cs); + void *p; + struct ktap_cdata *cd; + + switch (ttypenv(arg)) { + case KTAP_TBOOLEAN: + memset(dst, 0, size); + memcpy(dst, &bvalue(arg), sizeof(bool)); + return; + case KTAP_TLIGHTUSERDATA: + memcpy(dst, pvalue(arg), size); + return; + case KTAP_TNUMBER: + memset(dst, 0, size); + memcpy(dst, &nvalue(arg), size < sizeof(ktap_number) ? + size : sizeof(ktap_number)); + return; + case KTAP_TSTRING: + p = &rawtsvalue(arg)->tsv + 1; + memcpy(dst, &p, size); + return; + } + + cd = cdvalue(arg); + switch (type) { + case FFI_VOID: + kp_error(ks, "Error: Cannot copy data from void type\n"); + return; + case FFI_UINT8: + case FFI_INT8: + case FFI_UINT16: + case FFI_INT16: + case FFI_UINT32: + case FFI_INT32: + case FFI_UINT64: + case FFI_INT64: + memcpy(dst, &cd_int(cd), size); + return; + case FFI_PTR: + memcpy(dst, &cd_ptr(cd), size); + return; + case FFI_STRUCT: + memcpy(dst, cd_struct(cd), size); + return; + case FFI_FUNC: + case FFI_UNKNOWN: + kp_error(ks, "Error: internal error for csymbol %s\n", + csym_name(cs)); + return; + } +} + +#ifdef __x86_64 + +extern void ffi_call_assem_x86_64(void *stack, void *temp_stack, + void *rvalue, void *func_addr, ffi_type rtype); + +static void ffi_call_x86_64(ktap_state *ks, csymbol_func *csf, void *rvalue) +{ + int i; + int gpr_nr; + int arg_bytes; /* total bytes needed for exceeded args in stack */ + int mem_bytes; /* total bytes needed for memory storage */ + char *stack, *stack_p, *gpr_p, *arg_p, *mem_p, *tmp_p; + csymbol *rsym; + ffi_type rtype; + size_t rsize; + bool ret_in_memory; + + rsym = csymf_ret(ks, csf); + rtype = csym_type(rsym); + rsize = csym_size(ks, rsym); + ret_in_memory = false; + if (rtype == FFI_STRUCT) { + if (rsize > 16) { + rvalue = kp_malloc(ks, rsize); + rtype = FFI_VOID; + ret_in_memory = true; + } else { + /* much easier to always copy 16 bytes from registers */ + rvalue = kp_malloc(ks, 16); + } + } + + gpr_nr = 0; + arg_bytes = mem_bytes = 0; + if (ret_in_memory) + gpr_nr++; + /* calculate bytes needed for stack */ + for (i = 0; i < csymf_arg_nr(csf); i++) { + /*@TODO create api for this use case 28.11 2013 (houqp)*/ + size_t size = csym_size(ks, csymf_arg(ks, csf, i)); + size_t align = csym_align(ks, csymf_arg(ks, csf, i)); + enum arg_status st = IN_REGISTER; + int n_gpr_nr = 0; + if (size > 32) { + st = IN_MEMORY; + n_gpr_nr = 1; + } else if (size > 16) + st = IN_STACK; + else + n_gpr_nr = ALIGN(size, GPR_SIZE) / GPR_SIZE; + + if (gpr_nr + n_gpr_nr > MAX_GPR) { + if (st == IN_MEMORY) + arg_bytes += GPR_SIZE; + else + st = IN_STACK; + } else + gpr_nr += n_gpr_nr; + if (st == IN_STACK) { + arg_bytes = ALIGN(arg_bytes, align); + arg_bytes += size; + arg_bytes = ALIGN(arg_bytes, STACK_ALIGNMENT); + } + if (st == IN_MEMORY) { + mem_bytes = ALIGN(mem_bytes, align); + mem_bytes += size; + mem_bytes = ALIGN(mem_bytes, STACK_ALIGNMENT); + } + } + + /* apply space to fake stack for C function call */ + stack = kp_malloc(ks, REDZONE_SIZE + MAX_GPR_SIZE + arg_bytes + + mem_bytes + 6 * 8); + /* 128 bytes below %rsp is red zone */ + /* stack should be 16-bytes aligned */ + stack_p = ALIGN_STACK(stack + REDZONE_SIZE, 16); + /* save general purpose registers here */ + gpr_p = stack_p; + memset(gpr_p, 0, MAX_GPR_SIZE); + /* save arguments in stack here */ + arg_p = gpr_p + MAX_GPR_SIZE; + /* save arguments in memory here */ + mem_p = arg_p + arg_bytes; + /* set additional space as temporary space */ + tmp_p = mem_p + mem_bytes; + + /* copy arguments here */ + gpr_nr = 0; + if (ret_in_memory) { + memcpy(gpr_p, &rvalue, GPR_SIZE); + gpr_p += GPR_SIZE; + gpr_nr++; + } + for (i = 0; i < csymf_arg_nr(csf); i++) { + size_t size = csym_size(ks, csymf_arg(ks, csf, i)); + size_t align = csym_align(ks, csymf_arg(ks, csf, i)); + enum arg_status st = IN_REGISTER; + int n_gpr_nr = 0; + if (size > 32) { + st = IN_MEMORY; + n_gpr_nr = 1; + } else if (size > 16) + st = IN_STACK; + else + n_gpr_nr = ALIGN(size, GPR_SIZE) / GPR_SIZE; + + if (st == IN_MEMORY) + mem_p = ALIGN_STACK(mem_p, align); + /* Tricky way about storing it above mem_p. It won't overflow + * because temp region can be temporarily used if necesseary. */ + ffi_unpack(ks, csymf_arg(ks, csf, i), kp_arg(ks, i+1), mem_p); + if (gpr_nr + n_gpr_nr > MAX_GPR) { + if (st == IN_MEMORY) { + memcpy(arg_p, &mem_p, GPR_SIZE); + arg_p += GPR_SIZE; + } else + st = IN_STACK; + } else { + memcpy(gpr_p, mem_p, n_gpr_nr * GPR_SIZE); + gpr_p += n_gpr_nr * GPR_SIZE; + gpr_nr += n_gpr_nr; + } + if (st == IN_STACK) { + arg_p = ALIGN_STACK(arg_p, align); + memcpy(arg_p, mem_p, size); + arg_p += size; + arg_p = ALIGN_STACK(arg_p, STACK_ALIGNMENT); + } + if (st == IN_MEMORY) { + mem_p += size; + mem_p = ALIGN_STACK(mem_p, STACK_ALIGNMENT); + } + } + + kp_verbose_printf(ks, "Stack location: %p -redzone- %p -general purpose " + "register used- %p -zero- %p -stack for argument- %p" + " -memory for argument- %p -temp stack-\n", + stack, stack_p, gpr_p, stack_p + MAX_GPR_SIZE, + arg_p, mem_p); + kp_verbose_printf(ks, "GPR number: %d; arg in stack: %d; " + "arg in mem: %d\n", + gpr_nr, arg_bytes, mem_bytes); + kp_verbose_printf(ks, "Return: address %p type %d\n", rvalue, rtype); + kp_verbose_printf(ks, "Number of register used: %d\n", gpr_nr); + kp_verbose_printf(ks, "Start FFI call on %p\n", csf->addr); + ffi_call_assem_x86_64(stack_p, tmp_p, csf->addr, rvalue, rtype); + kp_verbose_printf(ks, "Finish FFI call\n"); + + kp_free(ks, stack); + return; +} + +#else + +static void ffi_call_unsupported(ktap_state *ks, + csymbol_func *csf, void *rvalue) +{ + kp_error(ks, "unsupported architecture.\n"); +} + +#endif + +static int ffi_set_return(ktap_state *ks, void *rvalue, csymbol_id ret_id) +{ + ktap_cdata *cd; + ffi_type type = csym_type(id_to_csym(ks, ret_id)); + + /* push return value to ktap stack */ + switch (type) { + case FFI_VOID: + return 0; + case FFI_UINT8: + case FFI_INT8: + case FFI_UINT16: + case FFI_INT16: + case FFI_UINT32: + case FFI_INT32: + case FFI_UINT64: + case FFI_INT64: + set_number(ks->top, (ktap_number)rvalue); + break; + case FFI_PTR: + cd = kp_cdata_new_ptr(ks, rvalue, ret_id); + set_cdata(ks->top, cd); + break; + case FFI_STRUCT: + cd = kp_cdata_new_struct(ks, rvalue, ret_id); + set_cdata(ks->top, cd); + break; + case FFI_FUNC: + case FFI_UNKNOWN: + kp_error(ks, "Error: Have not support ffi_type %s\n", + ffi_type_name(type)); + return 0; + } + incr_top(ks); + return 1; +} + +/* + * Call C into function + * First argument should be function symbol address, argument types + * and return type. + * Left arguments should be arguments for calling the C function. + * Types between Ktap and C are converted automatically. + * Only support x86_64 function call by now + */ +int kp_ffi_call(ktap_state *ks, csymbol_func *csf) +{ + int i, arg_nr = csf->arg_nr; + ktap_closure *cl; + void *rvalue; + + /* check stack status for C call */ + if (arg_nr != kp_arg_nr(ks)) { + kp_error(ks, "wrong argument number %d, which should be %d\n", + kp_arg_nr(ks), arg_nr); + goto out; + } + + /* maybe useful later, leave it here first */ + cl = clvalue(kp_arg(ks, arg_nr + 1)); + + /* check the argument types */ + for (i = 0; i < arg_nr; i++) { + StkId karg = kp_arg(ks, i + 1); + csymbol *atype = csymf_arg(ks, csf, i); + if (ffi_type_check(ks, atype, karg, i) < 0) + goto out; + } + + /* platform-specific calling workflow */ + ffi_call(ks, csf, &rvalue); + +out: + return ffi_set_return(ks, rvalue, csymf_ret_id(csf)); +} diff --git a/interpreter/ffi/ffi_symbol.c b/interpreter/ffi/ffi_symbol.c new file mode 100644 index 0000000..fd32523 --- /dev/null +++ b/interpreter/ffi/ffi_symbol.c @@ -0,0 +1,172 @@ +/* + * ffi_symbol.c - ktapvm kernel module ffi symbol submodule + * + * This file is part of ktap by Jovi Zhangwei. + * + * Copyright (C) 2012-2013 Jovi Zhangwei <jovi.zhangwei@xxxxxxxxx>. + * + * ktap is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * ktap is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + */ + + +#include "../../include/ktap_types.h" +#include "../ktap.h" +#include "../kp_vm.h" +#include "../kp_obj.h" +#include "../kp_str.h" +#include "../kp_tab.h" +#include "../kp_ffi.h" + + +static inline csymbol *get_csym_arr(ktap_state *ks) +{ + return G(ks)->ffis.csym_arr; +} + +static inline int get_csym_nr(ktap_state *ks) +{ + return G(ks)->ffis.csym_nr; +} + +static inline void set_csym_arr(ktap_state *ks, csymbol *csym) +{ + G(ks)->ffis.csym_arr = csym; +} + +static inline void set_csym_nr(ktap_state *ks, int nr) +{ + G(ks)->ffis.csym_nr = nr; +} + + +static inline ktap_tab *get_ffi_ctable(ktap_state *ks) +{ + return G(ks)->ffis.ctable; +} + +static void setup_ffi_ctable(ktap_state *ks) +{ + ktap_value ffi_lib_name, ffi_mt; + ktap_tab *registry; + const ktap_value *gt; + + gt = kp_tab_getint(hvalue(&G(ks)->registry), KTAP_RIDX_GLOBALS); + + G(ks)->ffis.ctable = kp_tab_new(ks); + + /* insert ffi C table to global table */ + set_table(&ffi_mt, get_ffi_ctable(ks)); + set_string(&ffi_lib_name, kp_tstring_new(ks, "C")); + registry = hvalue(gt); + kp_tab_setvalue(ks, registry, &ffi_lib_name, &ffi_mt); +} + + +void ffi_set_csym_arr(ktap_state *ks, int cs_nr, csymbol *new_arr) +{ + set_csym_nr(ks, cs_nr); + set_csym_arr(ks, new_arr); + + if (!new_arr) + return; + + setup_kp_ffi_symbol_table(ks); +} + +inline csymbol *ffi_get_csym_by_id(ktap_state *ks, int id) +{ + return &(get_csym_arr(ks)[id]); +} + +csymbol_id ffi_get_csym_id(ktap_state *ks, char *name) +{ + int i; + + for (i = 0; i < get_csym_nr(ks); i++) { + if (!strcmp(name, csym_name(ffi_get_csym_by_id(ks, i)))) { + return i; + } + } + + return 0; +} + +static void add_ffi_func_to_ctable(ktap_state *ks, csymbol_id id) +{ + ktap_value func_name, fv; + ktap_cdata *cd; + csymbol *cs; + + /* push cdata to ctable */ + set_cdata(&fv, kp_newobject(ks, KTAP_TCDATA, sizeof(ktap_cdata), NULL)); + cd = cdvalue(&fv); + cd_set_csym_id(cd, id); + + cs = id_to_csym(ks, id); + set_string(&func_name, kp_tstring_new(ks, csym_name(cs))); + kp_tab_setvalue(ks, get_ffi_ctable(ks), &func_name, &fv); +} + +void setup_kp_ffi_symbol_table(ktap_state *ks) +{ + int i; + csymbol *cs; + + setup_ffi_ctable(ks); + + /* push all functions to ctable */ + for (i = 0; i < get_csym_nr(ks); i++) { + cs = &get_csym_arr(ks)[i]; + switch (cs->type) { + case FFI_FUNC: + kp_verbose_printf(ks, "[%d] loading C function %s\n", + i, csym_name(cs)); + add_ffi_func_to_ctable(ks, i); + kp_verbose_printf(ks, "%s loaded\n", csym_name(cs)); + break; + case FFI_STRUCT: + break; + default: + break; + } + } +} + +void kp_ffi_free_symbol(ktap_state *ks) +{ + int i; + csymbol_id *arg_ids; + csymbol *cs; + + if (!get_csym_arr(ks)) + return; + + for (i = 0; i < get_csym_nr(ks); i++) { + cs = &get_csym_arr(ks)[i]; + switch (csym_type(cs)) { + case FFI_FUNC: + arg_ids = csym_func_arg_ids(cs); + if (arg_ids) + kp_free(ks, arg_ids); + break; + case FFI_STRUCT: + /*@TODO finish this 20.11 2013 (houqp)*/ + break; + default: + break; + } + } + + kp_free(ks, get_csym_arr(ks)); +} diff --git a/interpreter/ffi/ffi_util.c b/interpreter/ffi/ffi_util.c new file mode 100644 index 0000000..98e9423 --- /dev/null +++ b/interpreter/ffi/ffi_util.c @@ -0,0 +1,93 @@ +/* + * ffi_util.c - utility function for ffi module + * + * This file is part of ktap by Jovi Zhangwei. + * + * Copyright (C) 2012-2013 Jovi Zhangwei <jovi.zhangwei@xxxxxxxxx>. + * + * ktap is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * ktap is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + */ + + +#include "../../include/ktap_types.h" +#include "../ktap.h" +#include "../kp_vm.h" +#include "../kp_ffi.h" + +size_t csym_size(ktap_state *ks, csymbol *cs) +{ + ffi_type type = csym_type(cs); + switch(type) { + case FFI_STRUCT: + if (csym_struct(cs)->align == 0) + init_csym_struct(ks, csym_struct(cs)); + return csym_struct(cs)->size; + default: + return ffi_type_size(type); + } +} + +size_t csym_align(ktap_state *ks, csymbol *cs) +{ + ffi_type type = csym_type(cs); + switch(type) { + case FFI_STRUCT: + if (csym_struct(cs)->align == 0) + init_csym_struct(ks, csym_struct(cs)); + return csym_struct(cs)->align; + default: + return ffi_type_align(type); + } +} + +size_t csym_struct_offset(ktap_state *ks, csymbol_struct *csst, int idx) +{ + int nr = csymst_mb_nr(csst); + size_t off = 0; + size_t align = 1; + int i; + + if (idx < 0 || idx > nr) + return -1; + for (i = 0; i < idx; i++) { + csymbol *var_cs = csymst_mb(ks, csst, i); + size_t var_size = csym_size(ks, var_cs); + size_t var_align = csym_align(ks, var_cs); + off = ALIGN(off, var_align); + off += var_size; + align = align > var_align ? align : var_align; + } + off = ALIGN(off, align); + return off; +} + +void init_csym_struct(ktap_state *ks, csymbol_struct *csst) +{ + int nr = csymst_mb_nr(csst); + size_t size = 0; + size_t align = 1; + int i; + + for (i = 0; i < nr; i++) { + csymbol *var_cs = csymst_mb(ks, csst, i); + size_t var_size = csym_size(ks, var_cs); + size_t var_align = csym_align(ks, var_cs); + size = ALIGN(size, var_align); + size += var_size; + align = align > var_align ? align : var_align; + } + size = ALIGN(size, align); + csst->size = size; + csst->align = align; +} -- 1.8.1.2