diff --git a/bridge/Windows/lsffi_asm_linux.S b/bridge/Windows/lsffi_asm_linux.S new file mode 100644 index 0000000000000000000000000000000000000000..13a4cc016a7e37ef8b68a8aaec2d740147951893 --- /dev/null +++ b/bridge/Windows/lsffi_asm_linux.S @@ -0,0 +1,190 @@ +/* +MIT License + +Copyright (c) 2023-2024 Matriller + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + + /* + 出于性能考虑,此处采用汇编代码 + */ + + .text + +/* + lsffi_cdel_intargs6 +*/ + .globl lsffi_cdel_intargs6 + .type llsffi_cdel_intargs6, @function +lsffi_cdel_intargs6: + /* + uint64_t lsffi_cdel_intargs6(uint64_t args[6], void *fun); + */ + endbr64 + movq %rdi, %rbx //将参数指针保存在rbx中 + movq %rsi, %r15 //将函数指针保存在r15中 + + //传参 + movq 0(%rbx), %rdi //第一个参数,剩下的以此类推 + movq 8(%rbx), %rsi + movq 16(%rbx), %rdx + movq 24(%rbx), %rcx + movq 36(%rbx), %r8 + movq 40(%rbx), %r9 + + call *%r15 //函数调用 + ret //返回 + + /* + 按寄存器传递的参数,传递顺序在Linux和Windows平台是不同的 + */ + +/* + uint64_numlist_reverse +*/ + +uint64_numlist_reverse: + /* + void numlist_reverse(uint64_t *num, uint64_t len); + + Linux cdel调用约定: + num参数储存在rdi中 + len参数储存在rsi中 + + 原理即交换内存实现数组反转.如有一个名为a,长度为n的int数组,用C实现如下: + for (int i = 0; i < n / 2; i ++) + { + int mid = a[i]; + a[i] = a[n - i - 1]; + a[n - i - 1] = mid; + } + + 汇编中使用三个寄存器实现这个算法 + 一是基址寄存器,用于保存数组的基址 + 二是前偏移寄存器,用于保存较小的偏移 + 三是后偏移寄存器,用于保存较大的偏移 + 每次循环时,将基址和前偏移相加,读取前数。之后将基址与后偏移相加,读取后数。 + 将前数存到后数的内存区,将后数存到前数的内存区,完成一轮交换。之后将前偏移值加8字节, + 将后偏移值加8字节。 + 循环退出的条件是前偏移地址大于等于后偏移地址。大于即n为偶数的情况,此时最中间的数不用移动。 + 等于即n为奇数的情况,此时所有数均已交换,并且没有最中间的数。 + */ + endbr64 //Linux程序中得有这行代码 + + cmp $0, %rsi //检查len参数是否为0,是则直接返回函数 + je ..LUINT64_NUMLIST_REVERSE_L1_END + + /* + 这段代码中的基址寄存器是rdi,前偏移寄存器是rcx,后偏移寄存器是rsi + */ + + dec %rsi //%rsi中储存着len参数 + imulq $8, %rsi //这一条指令和上一条是在计算最后一个数字的偏移量,减去1是避免差一错误 + movq $0, %rcx //rcx用于计数 +.LUINT64_NUMLIST_REVERSE_L1: + movq (%rdi, %rcx), %r14 //读取前数 + movq (%rdi, %rsi), %r15 //读取后数 + movq %r15, (%rdi, %rcx) //后数存至前数内存区域 + movq %r14, (%rdi, %rsi) //前数存至后数内存区域 + addq $8, %rcx //前偏移地址加8字节 + subq $8, %rsi //后偏移地址减8字节 + cmp %rsi, %rcx //比较前指针和后指针的值,如果前指针大于或等于后指针,则 + jl .LUINT64_NUMLIST_REVERSE_L1 +..LUINT64_NUMLIST_REVERSE_L1_END: + ret + +/* + lsffi_cdel_intargsx__维护须知 + 1. 在amd64计算机中,无论整形参数长度如何,都使用pushq,即压入8字节 + 2. 在ret之前,要调用leave清理栈桢 + 3. 在leave之前,要将rsp加上向栈中压入的参数的总字节数,即压入的参数的8倍 + 4. leave命令之前不可删去pushq %rbp和movq %rsp, %rbp两条指令,会导致程序异常 +*/ + + .globl lsffi_cdel_intargsx__ + .type lsffi_cdel_intargsx__, @function +lsffi_cdel_intargsx__: + /* + uint64_t lsffi_cdel_intargsx(uint64_t args[6], uint64_t *eargs, void *fun, uint64_t len); + */ + endbr64 + pushq %rbp + movq %rsp, %rbp + + movq %rdi, %r10 //r10保存前6个参数指针 + movq %rsi, %r11 //r11保存其余参数指针 + movq %rdx, %r12 //r12保存函数指针 + movq %rcx, %r13 //r13保存其余参数个数 + + //调用uint64_numlist_reverse函数 + movq %r11, %rdi //要反转的数组基址 + movq %r13, %rsi //元素个数 + call uint64_numlist_reverse //函数调用 + + //压栈传入的参数 + movq %r13, %rcx + movq $0, %r14 //相对r11的寻址偏移 +.L1: + movq (%r11, %r14), %r15 + pushq %r15 + addq $8, %r14 //每循环一次,r14加8字节,即相对r11多偏移8字节,即访问下一个64位数 + loop .L1 + + //按寄存器传递的参数 + movq 0(%r10), %rdi //第一个参数,剩下的以此类推 + movq 8(%r10), %rsi + movq 16(%r10), %rdx + movq 24(%r10), %rcx + movq 32(%r10), %r8 + movq 40(%r10), %r9 + call *%r12 //函数调用 + + //清理栈桢 + imulq $8, %r13 //计算压栈传参的字节数 + addq %r13, %rsp //向rsp加上该字节数 + leave //清理栈桢 + ret //函数返回 + + +/* + lsffi_cdel_floatargs8 +*/ + + .globl lsffi_cdel_floatargs8 + .type lsffi_cdel_floatargs8, @function +lsffi_cdel_floatargs8: + endbr64 + //保存数据 + movq %rdi, %rbx //rbx存储参数指针 + movq %rsi, %rax //rax存储函数指针 + + //传参 + movq 56(%rbx), %xmm7 + movq 48(%rbx), %xmm6 + movq 40(%rbx), %xmm5 + movq 32(%rbx), %xmm4 + movq 24(%rbx), %xmm3 + movq 16(%rbx), %xmm2 + movq 8(%rbx), %xmm1 + movq 0(%rbx), %xmm0 + + //函数调用 + call *%rax + ret diff --git a/bridge/Windows/lsffi_asm_win.S b/bridge/Windows/lsffi_asm_win.S new file mode 100644 index 0000000000000000000000000000000000000000..36073c87f762d021c94a1a44966fb6f737252134 --- /dev/null +++ b/bridge/Windows/lsffi_asm_win.S @@ -0,0 +1,176 @@ +/* +MIT License + +Copyright (c) 2023-2024 Matriller + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + .text + .globl lsffi_cdel_intargs6 +lsffi_cdel_intargs6: + movq %rcx, %rbx //rbx保存前6个参数指针 + movq %rdx, %r11 //r11保存函数指针 + + movq 0(%rbx), %rcx + movq 8(%rbx), %rdx + movq 16(%rbx), %r8 + movq 24(%rbx), %r9 + + movq 32(%rbx), %r12 //X86架构不允许内存直接直接传递数据 + movq %r12, -16(%rsp) + movq 40(%rbx), %r12 + movq %r12, -8(%rsp) + + subq $48, %rsp + call *%r11 + addq $48, %rsp + + ret + +uint64_numlist_reverse: + /* + void numlist_reverse(uint64_t *num, uint64_t len); + + Linux cdel调用约定: + num参数储存在rdi中 + len参数储存在rsi中 + + 原理即交换内存实现数组反转.如有一个名为a,长度为n的int数组,用C实现如下: + for (int i = 0; i < n / 2; i ++) + { + int mid = a[i]; + a[i] = a[n - i - 1]; + a[n - i - 1] = mid; + } + + 汇编中使用三个寄存器实现这个算法 + 一是基址寄存器,用于保存数组的基址 + 二是前偏移寄存器,用于保存较小的偏移 + 三是后偏移寄存器,用于保存较大的偏移 + 每次循环时,将基址和前偏移相加,读取前数。之后将基址与后偏移相加,读取后数。 + 将前数存到后数的内存区,将后数存到前数的内存区,完成一轮交换。之后将前偏移值加8字节, + 将后偏移值加8字节。 + 循环退出的条件是前偏移地址大于等于后偏移地址。大于即n为偶数的情况,此时最中间的数不用移动。 + 等于即n为奇数的情况,此时所有数均已交换,并且没有最中间的数。 + */ + cmp $0, %rsi //检查len参数是否为0,是则直接返回函数 + je .LUINT64_NUMLIST_REVERSE_L1_END + + /* + 这段代码中的基址寄存器是rdi,前偏移寄存器是rcx,后偏移寄存器是rsi + */ + + dec %rsi //%rsi中储存着len参数 + imulq $8, %rsi //这一条指令和上一条是在计算最后一个数字的偏移量,减去1是避免差一错误 + movq $0, %rcx //rcx用于计数 +.LUINT64_NUMLIST_REVERSE_L1: + movq (%rdi, %rcx), %r14 //读取前数 + movq (%rdi, %rsi), %r15 //读取后数 + movq %r15, (%rdi, %rcx) //后数存至前数内存区域 + movq %r14, (%rdi, %rsi) //前数存至后数内存区域 + addq $8, %rcx //前偏移地址加8字节 + subq $8, %rsi //后偏移地址减8字节 + cmp %rsi, %rcx //比较前指针和后指针的值,如果前指针大于或等于后指针,则 + jl .LUINT64_NUMLIST_REVERSE_L1 +.LUINT64_NUMLIST_REVERSE_L1_END: + ret + + + .globl lsffi_cdel_intargsx__ +lsffi_cdel_intargsx__: + movq %rcx, %rbx //rbx保存前6个参数指针 + movq %rdx, %r10 //r10保存其余参数指针 + movq %r8, %r11 //r11保存函数指针 + movq %r9, %r12 //r12保存其余参数个数 + + //调用uint64_numlist_reverse函数 + movq %r10, %rdi + movq %r12, %rsi + call uint64_numlist_reverse + + //调整rsp位置 + movq $6, %r15 + addq %r12, %r15 + imulq $8, %r15 + subq %r15, %rsp + + //检查是否有要通过栈传递的参数 + cmp $0, %r12 + je .L1_END + + //通过栈传递参数 + movq %r12, %rcx + movq $0, %r13 //相对r10的参数寻址偏移 + movq %r15, %r14 //参数的目的偏移,即在栈中的偏移 +.L1: + movq (%r10, %r13), %rdx //从内存读取参数 + addq $8, %r13 //增加参数的源内存偏移 + subq $8, %r14 + movq %rdx, (%rsp, %r14) //将参数移入栈中 + loop .L1 //循环 +.L1_END: + + //按寄存器传递的参数 + movq 0(%rbx), %rcx + movq 8(%rbx), %rdx + movq 16(%rbx), %r8 + movq 24(%rbx), %r9 + + movq 32(%rbx), %r12 //X86架构不允许内存直接直接传递数据 + movq %r12, 32(%rsp) + movq 40(%rbx), %r12 + movq %r12, 40(%rsp) + + call *%r11 //函数调用 + addq %r15, %rsp //恢复栈桢 + + ret + +/* + lsffi_cdel_floatargs8 +*/ + + .globl lsffi_cdel_floatargs8 +lsffi_cdel_floatargs8: + //保存数据 + movq %rcx, %rbx //rbx存储参数指针 + movq %rdx, %r10 //r10存储函数指针 + + //传参 + movq 56(%rbx), %xmm7 + movq 48(%rbx), %xmm6 + movq 40(%rbx), %xmm5 + movq 32(%rbx), %xmm4 + movq 24(%rbx), %xmm3 + movq 16(%rbx), %xmm2 + movq 8(%rbx), %xmm1 + movq 0(%rbx), %xmm0 + + movq %r10, %rax + + //调整栈帧 + subq $64, %rsp + + //函数调用 + call *%r10 + + //调整栈帧 + addq $64, %rsp + + ret diff --git a/bridge/Windows/makefile b/bridge/Windows/makefile new file mode 100644 index 0000000000000000000000000000000000000000..16bb0a515966e8e0844a4dea0d1a4c52aff9e2ee --- /dev/null +++ b/bridge/Windows/makefile @@ -0,0 +1,11 @@ +T = ElsLib_bridge.lsd +CFLAGS = -O2 -std=c99 -DELS_CONF_OS_WINDOWS -I ../buildenv -L ../buildenv -fPIC -s -l:libeasylosu.dll +CPPFLAGS = -O3 -std=c++11 -DELS_CONF_OS_WINDOWS -I ./include -I ../buildenv + +all: $T + +$T: + gcc lsffi.c lsffi_asm_win.S bridge.c -o $(T) -shared $(CFLAGS) + +clean: + rm *.o diff --git a/bridge/bridge.c b/bridge/bridge.c new file mode 100644 index 0000000000000000000000000000000000000000..3d3273a09d6e1e89e01571781c1e4399908bdbe0 --- /dev/null +++ b/bridge/bridge.c @@ -0,0 +1,303 @@ +#include "els.h" +#include "bridge.h" +#include "lsffi.h" + +#include +#include +#include + +#define unit_arg(x) x+1 + +static double lsptr_to_c(els_VmObj *vm, LosuObj *p) +{ + double output; + void *ptr = obj_toptr(vm, p); + output = *((double*)&ptr); + return output; +} + +// int + +int ELSAPI_bridge_bridge_c_cint8(els_VmObj* vm) // bridge_c_cint8() +{ + LosuObj output; + int type = arg_gettype(vm, unit_arg(1)); + + if (type == ELS_API_TYPE_NUMBER) + { + int64_t n = (int8_t)arg_getnum(vm, unit_arg(1)); + output = obj_newbyte(vm, (char*)&n, 8); + } + else if (type == ELS_API_TYPE_PTR) + { + output = obj_newnum(vm, lsptr_to_c(vm, arg_get(vm, unit_arg(1)))); + } + else + { + output = obj_newnull(vm); + } + + arg_return(vm, output); + + return 1; +} + +int ELSAPI_bridge_bridge_c_cint16(els_VmObj* vm) // bridge_c_cint16() +{ + LosuObj output; + int type = arg_gettype(vm, unit_arg(1)); + + if (type == ELS_API_TYPE_NUMBER) + { + int64_t n = (int16_t)arg_getnum(vm, unit_arg(1)); + output = obj_newbyte(vm, (char*)&n, 8); + } + else if (type == ELS_API_TYPE_PTR) + { + output = obj_newnum(vm, lsptr_to_c(vm, arg_get(vm, unit_arg(1)))); + } + else + { + output = obj_newnull(vm); + } + + arg_return(vm, output); + + return 1; +} + +int ELSAPI_bridge_bridge_c_cint32(els_VmObj* vm) // bridge_c_cint32() +{ + LosuObj output; + int type = arg_gettype(vm, unit_arg(1)); + + if (type == ELS_API_TYPE_NUMBER) + { + int64_t n = (int32_t)arg_getnum(vm, unit_arg(1)); + output = obj_newbyte(vm, (char*)&n, 8); + } + else if (type == ELS_API_TYPE_PTR) + { + output = obj_newnum(vm, lsptr_to_c(vm, arg_get(vm, unit_arg(1)))); + } + else + { + output = obj_newnull(vm); + } + + arg_return(vm, output); + + return 1; +} + +int ELSAPI_bridge_bridge_c_cint64(els_VmObj* vm) // bridge_c_cint64() +{ + LosuObj output; + int type = arg_gettype(vm, unit_arg(1)); + + if (type == ELS_API_TYPE_NUMBER) + { + int64_t n = (int64_t)arg_getnum(vm, unit_arg(1)); + output = obj_newbyte(vm, (char*)&n, 8); + } + else if (type == ELS_API_TYPE_PTR) + { + output = obj_newnum(vm, lsptr_to_c(vm, arg_get(vm, unit_arg(1)))); + } + else + { + output = obj_newnull(vm); + } + + arg_return(vm, output); + + return 1; +} + +// float + +int ELSAPI_bridge_bridge_c_cfloat32(els_VmObj* vm) // bridge_c_cint8() +{ + LosuObj output; + int type = arg_gettype(vm, unit_arg(1)); + + if (type == ELS_API_TYPE_NUMBER) + { + float n = arg_getnum(vm, unit_arg(1)); + uint64_t tmp = *((uint64_t*)&n); + output = obj_newbyte(vm, (char*)&n, 8); + } + else if (type == ELS_API_TYPE_PTR) + { + output = obj_newnum(vm, lsptr_to_c(vm, arg_get(vm, unit_arg(1)))); + } + else + { + output = obj_newnull(vm); + } + + arg_return(vm, output); + + return 1; +} + +int ELSAPI_bridge_bridge_c_cfloat64(els_VmObj* vm) // bridge_c_cint8() +{ + LosuObj output; + int type = arg_gettype(vm, unit_arg(1)); + + if (type == ELS_API_TYPE_NUMBER) + { + double n = arg_getnum(vm, unit_arg(1)); + output = obj_newbyte(vm, (char*)&n, 8); + } + else if (type == ELS_API_TYPE_PTR) + { + output = obj_newnum(vm, lsptr_to_c(vm, arg_get(vm, unit_arg(1)))); + } + else + { + output = obj_newnull(vm); + } + + arg_return(vm, output); + + return 1; +} + +// string + +int ELSAPI_bridge_bridge_c_cstr(els_VmObj* vm) // bridge_c_cint8() +{ + LosuObj output; + int type = arg_gettype(vm, unit_arg(1)); + + if (type == ELS_API_TYPE_STRING) + { + char* p = (char*)arg_getstr(vm, unit_arg(1)); + output = obj_newbyte(vm, (char*)&p, 8); + } + else if (type == ELS_API_TYPE_PTR) + { + output = obj_newnum(vm, lsptr_to_c(vm, arg_get(vm, unit_arg(1)))); + } + else + { + output = obj_newnull(vm); + } + + arg_return(vm, output); + + return 1; +} + +// ptr +int ELSAPI_bridge_bridge_c_cptr(els_VmObj* vm) // bridge_c_cint8() +{ + LosuObj output; + int type = arg_gettype(vm, unit_arg(1)); + + if (type == ELS_API_TYPE_STRING) + { + char* p = (char*)arg_getstr(vm, unit_arg(1)); + output = obj_newbyte(vm, (char*)&p, 8); + } + else if (type == ELS_API_TYPE_BYTE) + { + char* p = (char*)arg_getbyte(vm, unit_arg(1)); + output = obj_newbyte(vm, (char*)&p, 8); + } + else if (type == ELS_API_TYPE_PTR) + { + char* p = (char*)arg_getptr(vm, unit_arg(1)); + output = obj_newbyte(vm, (char*)&p, 8); + } + else + { + output = obj_newnull(vm); + } + + arg_return(vm, output); + + return 1; +} + +int ELSAPI_bridge_bridge_c_iif(els_VmObj* vm) // bridge_c_iaf() #int arg function +{ + /* + 多参函数 + 第一个参数恒为ptr类型的c函数指针 + 其余参数均为number类型的参数 + */ + uint32_t argn = arg_num(vm) - 1; + char __tmp[8]; + LosuObj loutput = obj_newbyte(vm, (char*)__tmp, 8); + uint64_t *output = (uint64_t*)obj_tobyte(vm, &loutput); + arg_return(vm, loutput); + + switch (argn) + { + case 0: + { + arg_returnnull(vm); + return 1; + } + case 1: + { + uint64_t args[6] = {0}; + void *fp = arg_getptr(vm, unit_arg(1)); + *output = lsffi_cdel_intargs6(args, fp); + + arg_return(vm, loutput); + return 1; + } + default: + { + void *fp = arg_getptr(vm, unit_arg(1)); + + argn--; + + //函数调用 + if (argn <= 6) + { + uint64_t args[6] = {0}; + + //参数传递 + for (int i = 0; i < argn; i ++) + { + if (arg_gettype(vm, i + 3) != ELS_API_TYPE_BYTE) + { + return 0; + } + + void *p = (void*)arg_getbyte(vm, i + 3); + args[i] = *((uint64_t*)p); + } + + *output = lsffi_cdel_intargs6(args, fp); + } + else + { + uint64_t *args = malloc(sizeof(uint64_t) * argn); + //参数传递 + + for (int i = 0; i < argn; i ++) + { + if (arg_gettype(vm, i + 3) != ELS_API_TYPE_BYTE) + { + return 0; + } + + void *p = (void*)arg_getbyte(vm, i + 3); + args[i] = *((uint64_t*)p); + } + + *output = lsffi_cdel_intargsx(args, args + 6, fp, argn - 6); + free(args); + } + + } + } + + return 1; +} diff --git a/bridge/bridge.els b/bridge/bridge.els new file mode 100644 index 0000000000000000000000000000000000000000..1f9c74e9da574867d24f21b59fa4f120d436af73 --- /dev/null +++ b/bridge/bridge.els @@ -0,0 +1,45 @@ +#!declare + +bridge_c_cint8() +bridge_c_cint16() +bridge_c_cint32() +bridge_c_cint64() + +bridge_c_cfloat32() +bridge_c_cfloat64() + +bridge_c_cstr() +bridge_c_cptr() + +bridge_c_iif(...) #int output int arg function + +#!end + +#!script + +var bridge = { + +} + +bridge.c = { + #从洛书数据类型转换到C数据类型 + int = bridge_c_cint32, + int8 = bridge_c_cint8, + int16 = bridge_c_cint16, + int32 = bridge_c_cint32, + int64 = bridge_c_cint64, + char = bridge_c_cint8, + short = bridge_c_cint16, + float32 = bridge_c_cfloat32, + float64 = bridge_c_cfloat64, + float = bridge_c_cfloat32, + double = bridge_c_cfloat64, + str = bridge_c_cstr, + ptr = bridge_c_cptr, + + #接口函数 + iif = bridge_c_iif, #int返回值、int参数的函数(int int function) +} + +#!end + diff --git a/bridge/bridge.h b/bridge/bridge.h new file mode 100644 index 0000000000000000000000000000000000000000..9b388cc6cae386142803c55c5daaee256cb2c798 --- /dev/null +++ b/bridge/bridge.h @@ -0,0 +1,43 @@ +#include "els.h" +int ELSAPI_bridge_bridge_c_cint8(els_VmObj* vm); // bridge_c_cint8() +int ELSAPI_bridge_bridge_c_cint16(els_VmObj* vm); // bridge_c_cint16() +int ELSAPI_bridge_bridge_c_cint32(els_VmObj* vm); // bridge_c_cint32() +int ELSAPI_bridge_bridge_c_cint64(els_VmObj* vm); // bridge_c_cint64() +int ELSAPI_bridge_bridge_c_cfloat32(els_VmObj* vm); // bridge_c_cfloat32() +int ELSAPI_bridge_bridge_c_cfloat64(els_VmObj* vm); // bridge_c_cfloat64() +int ELSAPI_bridge_bridge_c_cstr(els_VmObj* vm); // bridge_c_cstr() +int ELSAPI_bridge_bridge_c_iif(els_VmObj* vm); // bridge_c_iif(...) #int output int arg function +#ifdef ELS_CONF_TOKEN_EN +static const char LibScript[]={ +10, +118,97,114,32,98,114,105,100,103,101,32,61,32,123,10, +10, +125,10, +10, +98,114,105,100,103,101,46,99,32,61,32,123,10, +32,32,32,32,105,110,116,32,61,32,98,114,105,100,103,101,95,99,95,99,105,110,116,51,50,44,10, +32,32,32,32,105,110,116,56,32,61,32,98,114,105,100,103,101,95,99,95,99,105,110,116,56,44,10, +32,32,32,32,105,110,116,49,54,32,61,32,98,114,105,100,103,101,95,99,95,99,105,110,116,49,54,44,10, +32,32,32,32,105,110,116,51,50,32,61,32,98,114,105,100,103,101,95,99,95,99,105,110,116,51,50,44,10, +32,32,32,32,105,110,116,54,52,32,61,32,98,114,105,100,103,101,95,99,95,99,105,110,116,54,52,44,10, +32,32,32,32,102,108,111,97,116,51,50,32,61,32,98,114,105,100,103,101,95,99,95,99,102,108,111,97,116,51,50,44,10, +32,32,32,32,102,108,111,97,116,54,52,32,61,32,98,114,105,100,103,101,95,99,95,99,102,108,111,97,116,54,52,44,10, +32,32,32,32,115,116,114,32,61,32,98,114,105,100,103,101,95,99,95,99,115,116,114,44,10, +32,32,32,32,105,105,102,32,61,32,98,114,105,100,103,101,95,99,95,105,105,102,44,10, +125,10, +10, +0}; +#endif +void ElsLib_bridge_libinit(els_VmObj *vm){ + vm_register(vm,"bridge_c_cint16",ELSAPI_bridge_bridge_c_cint16); + vm_register(vm,"bridge_c_cint8",ELSAPI_bridge_bridge_c_cint8); + vm_register(vm,"bridge_c_cstr",ELSAPI_bridge_bridge_c_cstr); + vm_register(vm,"bridge_c_cfloat32",ELSAPI_bridge_bridge_c_cfloat32); + vm_register(vm,"bridge_c_cint32",ELSAPI_bridge_bridge_c_cint32); + vm_register(vm,"bridge_c_cfloat64",ELSAPI_bridge_bridge_c_cfloat64); + vm_register(vm,"bridge_c_iif",ELSAPI_bridge_bridge_c_iif); + vm_register(vm,"bridge_c_cint64",ELSAPI_bridge_bridge_c_cint64); + #ifdef ELS_CONF_TOKEN_EN + vm_dostring(vm,LibScript); + #endif +}; diff --git a/bridge/demo.els b/bridge/demo.els new file mode 100644 index 0000000000000000000000000000000000000000..4d2c5dfef81423c3ae43d60d69e50fc43397e4dc --- /dev/null +++ b/bridge/demo.els @@ -0,0 +1,13 @@ +import "xkit" +import "bridge" + +var lib = xkit.system.sharedlib.load("demo.dll") +var fp = xkit.system.sharedlib.getprocaddress(lib, "puts") + +var n = bridge.c.int32(9) +xkit.system.io.println(n) + +var res = bridge.c.iif(fp, n) +var res = bridge.c.iif(fp, res) + +print("finish..") diff --git a/bridge/info b/bridge/info new file mode 100644 index 0000000000000000000000000000000000000000..88efee1ec7a8b601262db990f07e35d56566ac59 --- /dev/null +++ b/bridge/info @@ -0,0 +1,28 @@ +{ + type = "normal", + info = { + name = "bridge", + text = "洛书的其他语言接口", + version = "24.3.31" + }, + source = { + all = { + "info", + "bridge.c", + "bridge.h", + "bridge.els", + "demo.els", + "lsffi.c", + "lsffi.h", + "readme.md", + }, + Windows ={ + "makefile", + "lsffi_asm_linux.S", + "lsffi_asm_win.S" + }, + }, + target={ + Windows = "make ; cp ElsLib_bridge.lsd target/ElsLib_bridge.lsd_Windows ; make clean", + } +} diff --git a/bridge/lsffi.c b/bridge/lsffi.c new file mode 100644 index 0000000000000000000000000000000000000000..b84914b4d5ac419aaedae8e147f9800e6f4d1427 --- /dev/null +++ b/bridge/lsffi.c @@ -0,0 +1,8 @@ +#include "lsffi.h" + +extern uint64_t lsffi_cdel_intargsx__(uint64_t args[6], uint64_t *eargs, void *fun, uint64_t len); + +uint64_t lsffi_cdel_intargsx(uint64_t args[6], uint64_t *eargs, void *fun, uint64_t len) +{ + return lsffi_cdel_intargsx__(args, eargs, fun, len); +} diff --git a/bridge/lsffi.h b/bridge/lsffi.h new file mode 100644 index 0000000000000000000000000000000000000000..65710746636ae931358297980ba7ef5eed2bba40 --- /dev/null +++ b/bridge/lsffi.h @@ -0,0 +1,87 @@ +#ifndef LSFFI_H_ +#define LSFFI_H_ + +#include + +#define LSFFI_INTRET 0 +#define LSFFI_FLOATRET 1 + +/* + CDEL部分 + + CDEL在Linux的整形传参顺序: + 参数顺序(按C语言参数列表顺序从左到右) 传入的寄存器 + 1 rdi + 2 rsi + 3 rdx + 4 rcx + 5 r8 + 6 r9 + + 6个以上参数通过压栈传递,而且是从右自左压栈 + 如有如下几个要压栈的参数,...是前6个传入寄存器的参数 + (... , 1, 2, 3) + 汇编压栈方式如下 + pushq $3 + pushq $2 + pushq $1 + 这样函数在用pop将参数从栈中弹出时,就会将参数顺序恢复到自左向右的状态 + + CDEL在Windows的整形传参顺序: + 参数顺序(按C语言参数列表顺序从左到右) 传入的寄存器 + 1 rcx + 2 rdx + 3 r8 + 4 r9 + + 在Windows平台下,CDEL只有前面4个参数是传入寄存器的,其余参数均传入栈中 + Windows平台要求函数调用者调整栈帧位置并传参。如传递如下参数 + (1, 2, 3, 4, 5, 6) + 对应汇编代码如下 + subq $48, %rsp //调整栈帧位置,即将栈帧减去参数的总字节数,包括传入寄存器的参数 + + movq $40, 16(%rsp) //栈帧自上往下递增,即内存地址在递减 + movq $32, 8(%rsp) + movq $4, %r9 + movq $3, %r8 + movq $2, %rdx + movq $1, %rcx + + call FUNCTION //假设有一个叫FUNCTION的函数 + addq $48, %rsp //在函数结尾,函数要恢复栈帧 + ret //函数返回 +*/ + +uint64_t lsffi_cdel_intargs6(uint64_t args[6], void *fun); +/* + 此函数用于Linux cdel的整形传参,且最多传参数为6个 + + @arg args: + 要传入的参数,是一个长度为6的64位整形数组,不一定是无符号类型 + @arg fun: + 要调用的函数指针 + + @output: + 会将fun的值当做函数指针来调用,返回值即该函数的返回值 +*/ + +uint64_t lsffi_cdel_intargsx(uint64_t args[6], uint64_t *eargs, void *fun, uint64_t len); +/* + 此函数用于Linux cdel的整形传参,无参数传递上限。 + + @arg args: + 要传入的参数,是一个长度为6的64位整形数组,不一定是无符号类型 + @arg eargs: + 额外的参数,当len不为空时才会被使用 + @arg fun: + 要调用的函数指针 + @arg len: + 额外参数的个数,当无额外参数时需要设为0,否则会引发错误 + + @output: + 会将fun的值当做函数指针来调用,返回值即该函数的返回值 +*/ + +double lsffi_cdel_floatargs8(double args[8], void *fun); + +#endif \ No newline at end of file diff --git a/bridge/readme.md b/bridge/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..3bd37828f7d13d85886324df448d4fad37dce7a2 --- /dev/null +++ b/bridge/readme.md @@ -0,0 +1,54 @@ +# bridge模块文档 + +```python +bridge.c = { + #从洛书数据类型转换到C数据类型 + int = bridge_c_cint32, + int8 = bridge_c_cint8, + int16 = bridge_c_cint16, + int32 = bridge_c_cint32, + int64 = bridge_c_cint64, + char = bridge_c_cint8, + short = bridge_c_cint16, + float32 = bridge_c_cfloat32, + float64 = bridge_c_cfloat64, + float = bridge_c_cfloat32, + double = bridge_c_cfloat64, + str = bridge_c_cstr, + ptr = bridge_c_cptr, + + #接口函数 + iif = bridge_c_iif, #int返回值、int参数的函数(int int function) +} +``` + + +例程(Windows): + +```python +""" + 使用printf进行格式化输出 +""" + +import "bridge" +import "sharedlib" + +var lib = sharedlib.load("C:\\Windows\\System32\\msvcrt.dll") #加载动态库 +var function = sharedlib.sys(lib, "printf") #获取printf函数 + +#将洛书类型转换为C类型 +var pattern = bridge.c.str("str:\%s, number:\%d\n") +var s = bridge.c.str("Hello losu!") +var n = bridge.c.int(1024) + +#函数调用 +bridge.c.iif(function, pattern, s, n) + + +``` + +最后的输出 + +```shell +str:Hello losu!, number:1024 +``` \ No newline at end of file