ajax 导出文件给 文件重新命名_类静态成员变量导出及def文件

在上一文中我们采用对整个类导出不导入的方式来避免local vftable的问题,但是这也带来了另一个问题,那就是类静态成员变量在另一个模块无法导入使用。

首先还是在上一篇中的例子上稍作修改来说明问题吧。如下图:

ff3e39ef8b8992dbdb2dbd963f50c5f9.png

在TestA类上新增了一个static的int型成员_sTestInt,并在一个内联函数setTestInt中使用这个static成员

eda1616cf8a198d020ce286399852184.png

在另一个使用TestA类的模块中增加对setTestInt内联函数的调用

e5a3e08adb3217c6acc40638d976e9e4.png

编译链接,会发现报上面的链接错误

解决方法很简单,如下:

9325a52633290eec2bdf67db34352f33.png

在需要导出使用的静态成员变量上增加dllimport的声明就可以了

到这里本篇最主要的议题就结束了,下面探讨一下def导出静态变量引起的问题,我们知道在Windows平台另外一种导出的方式就是采用def文件,针对上面的例子,我们采用def导出类静态成员变量试试。

4cc0040c2649c0560f59d67791355679.png

9512db9ab00e4002559cddcf324e8138.png

去掉静态成员变量_sTestInt前面的导出宏,新建def文件,并在其中添加_sTestInt的导出符号

编译链接,很完美链接通过,接着启动运行,很不幸,程序崩溃了。

c4537cdd507bd1620d980a59c33f23f4.png

这是为什么呢?我们接着调试找找原因:

5988e5925a73da3a79d56ba45140c269.png

汇编代码直接看上去很正常,setTestInt函数被内联为直接对Test::_sTestInt成员赋值,可是这一句执行就会崩溃,那让我们看看Test::_sTestInt这个符号对应的地址中是什么吧。

e6ea82eb74205bcb9839addfc75737d0.png

我们发现Test::_sTestInt中存储的是到实际_sTestInt变量的跳转。我们对这个jmp指令赋值自然是不合法的。为什么会这样呢?

b8eac4b895736cdfcbd7b82c684c7d19.png

《加密与解密》一书上有上面一段话,意思就是如果导出的符号前没有dllimport暗示的话,编译器在编译时无法区分用到的符号是否来自其它模块,所以就会为其生成桩代码(stub),链接时在桩代码处填入到实际符号的跳转。

现在问题清晰了,要解决也很简单,在用def导出的静态变量前一样需要dllimport的声明。修改后我们再反汇编调试看一下:

0e27627192164a0b92929af8f3a41f72.png

现在的赋值就变成了对实际导出变量的赋值,程序运行的很正常

好了,这一篇就这样结束了,再来吐槽下微软吧。在用dllexport方式导出和def文件导出时效果还不一样,dllexport导出时如果没有dllimport导入会有链接错误,而def导出不需要dllimport也可以链接通过,但是运行崩溃。具体dllexport导出和def有什么区别,身边缺少资料,还没细细研究,就个人认为,你就让def导出就和dllexport一样,直接报链接错误好了撒,让它能链接通过,但是运行崩溃,这有点坑人。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值