luajit利用ffi结合C语言实现面向对象的封装库

luajit中,利用ffi可以嵌入C,目前luajit的最新版是2.0.4,在这之前的版本我还不清楚这个扩展库具体怎么样,不过在2.04中,真的很爽。

既然是嵌入C代码,那么要说让lua支持面向对象,不如说是让C语言模拟面向对象编程,然后让luajit的ffi嵌入。

要文字彻底来描述清楚这个问题,我的表达能力很有限,说不清楚,所以直接用代码来说吧。

//C++
class foo_type{
public:
    void foo1()
    {
        printf("%d", a + b);
    }

    void foo2(int n)
    {
        printf("%d", a + b + n);
    }
    int a;
    int b;
};

foo_type obj;
obj.foo1();
obj.foo2(100);



//在C语言要做到同样的事,最简单的做法如下。

typedef struct{
    int a;
    int b;
}foo_type;
void foo1(foo_type *obj)
{
    printf("%d", obj->a + obj->y);
}

void foo2(foo_type *obj, int n)
{
    printf("%d", obj->a + obj->y + n);
}

foo_type obj;
foo1(&obj);
foo2(&obj, 100);

/*****************************************
//C++从汇编语言的角度看
obj.foo1();
lea ecx, obj
call foo1
-----------------------

obj.foo2(100);
push 100
lea ecx, obj
call foo1
-----------------------


//C语言从汇编语言的角度看
foo1(&obj);
lea eax, obj
push eax
call foo1
-----------------------


foo2(&obj, 100);
push 100
lea eax, obj
push eax
call foo2

那么就可以看到,C和C++在实现这种功能时的区别之处主要在于thiscall使用了ecx寄存器向下传递对象指针
而在C语言,只能把结构指针push下去,这就有点像微软的COM包装类的stdcall的类成员了。

*****************************************/

//从汇编看到问题所在之后,要解决这个问题,也就在可以考虑写一个shellcode,这个shellcode实现将向下传递上层传入的参数,并且直接将结构指针以push参数的方式最后入栈,然后call即可。
typedef struct{
    int a;
    int b;
}foo_type;
void foo1(foo_type *obj)
{
    printf("%d", obj->a + obj->y);
}

void foo2(foo_type *obj, int n)
{
    printf("%d", obj->a + obj->y + n);
}

typedef struct{
    void (*foo1)();
    void (*foo2)(int n);
}foo_class;

foo_type ft;
foo_class obj;
//与foo1对应的shellcode模板
BYTE scT1[] = {
    0x68, 0, 0, 0, 0, //push CONST
    0xE8, 0, 0, 0, 0, //call CONST
    0x83, 0xC4, 0x04, //add esp, 4
    0xC3              //ret
};

BYTE *psc = (BYTE*)VirtualAlloc(NULL, sizeof(scT1), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(psc, scT1, sizeof(scT1));
*(ULONG*)(psc + 1) = (ULONG)&ft;
*(ULONG*)(psc + 6) = (ULONG)&foo1 - (ULONG)(psc + 5) - 5;
*(ULONG*)&(obj.foo1) = psc;

//到这里之后,就已经能够这样用了
obj.foo1();

//与foo2对应的shellcode模板
BYTE scT2[] = {
        0xFF, 0x74, 0x24, 0x04,   //push dword ptr [esp + 4]
        0x68, 0, 0, 0, 0,         //call CONST
        0xE8, 0, 0, 0, 0,         //call CONST
        0x83, 0xC4, 0x08,         //add esp, 8
        0xC3                      //ret
};
BYTE *psc = (BYTE*)VirtualAlloc(NULL, sizeof(scT2), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(psc, scT2, sizeof(scT2));
*(ULONG*)(psc + 5) = (ULONG)&ft;
*(ULONG*)(psc + 10) = (ULONG)&foo2 - (ULONG)(psc + 5) - 5;
*(ULONG*)&(obj.foo2) = psc;

obj.foo2(100);

//这样就模拟了面向对象形式的调用,之后就需要考虑的就是一些如何整合管理资源之类的问题,还需要将代码尽可能的利用一些宏来简化,这些东西就不在这里说了,这个思路深入下去,相信大家都会知道该怎么做了。

下面是一套我封装的luajit使用ODBC访问数据库的代码,没有注释,将就着看吧。

//luaodbc.h**************************************************
#pragma once

extern "C"{
    typedef struct{
        void (*close)();
        bool (*set)(int i, int type, char *data, int size);
        bool (*get)(int i, int type);
        void *(*data)();
        bool (*next)();
        char *(*getstr)(int i);
        int (*getint)(int i);
        char *(*getstr_fn)(const char *name);
        char *(*getint_fn)(const char *name);
        bool (*setstr)(int i, const char *str);
        bool (*setint)(int i, int num);
        bool (*setstr_fn)(const char *name, const char *str);
        bool (*setint_fn)(const char *name, int num);
    }luastmt_class;

    typedef struct{
        bool (*open)(const char*dsn);
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值