随想录(windows静态库和动态库)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】

    在软件编程当中,动态库还是很有意思的。相比较静态库而言,动态库不管是开发、还是升级等方面都比较方便。当然为了适应动态库的这种动态加载的特点,编译器在生成动态库的时候,对于外面的数据和函数访问都不是直接访问,一般都是间接调用的,这是有动态库本身的特点决定的。我们可以做一个简单的例子,

1、首先在vs2010或者vs2015上面创建一个动态库工程,

extern "C" _declspec(dllexport) int add(int a, int b);
extern "C" _declspec(dllexport) int value = 10;

int add(int a, int b) 
{
	return a + b;
}

2、编译生成对应的lib文件和dll文件,姑且称之为add.lib & add.dll。

3、创建一个app工程,准备调用这个dll文件,

#include "stdafx.h"

#pragma comment(lib,"../Debug/add.lib")

extern "C" _declspec(dllimport) int add(int a, int b);
extern "C" _declspec(dllimport) int value;

int main()
{
    printf("%d\n", add(1,2));
    printf("%d\n", value);
    return 0;
}

4、编译app工程,可以正常运行,说明app成功执行。

5、分别在main函数的第1行、第2行,dll工程的DllMain添加断点,

a,首先DllMain被断住,继续运行

b,接着main的第一行被断住,继续运行

c,接着main的第二行被断住,继续运行

d,最后DllMain被断住,可以观察到DllMain被断住两次。

6、分析远程函数的调用方法,可以观察是间接调用,观察反汇编代码,

	printf("%d\n", add(1,2));
001317CE  mov         esi,esp  
001317D0  push        2  
001317D2  push        1  
001317D4  call        dword ptr ds:[13A0ECh]  

    在0x001317D4后面还有一个jmp跳转,

_add:
79BC10D2  jmp         add (79BC15A0h)  

7、分析全局变量的调用,

	printf("%d\n", value);
001317F2  mov         eax,dword ptr ds:[0013A0E8h]  
001317F7  mov         ecx,dword ptr [eax]  
001317F9  push        ecx  
001317FA  push        136B30h  
001317FF  call        _printf (0131325h)  
00131804  add         esp,8  

    这里value数值的获取,很明显是首先获取eax地址,再从eax获取ecx而来,ecx就是value的数值。

8、静态库

  如果是静态库,代码就比较简单了,

//a.cpp

extern "C" int sub(int data)
{
    return 1;
}

// b.cpp

#pragma comment(lib,"../Debug/sub.lib")

extern "C" int sub(int);

9、总结

    既然是动态库,涉及到外部的函数和变量,总是要多绕一点弯。linux下面使用.got & .got.plt来完成的。或者大家在名称上面有一点不同,但是其实原理都是一致的。动态库的正确执行还需要加载器和操作系统的积极配合,主要是loader的工作做的更多一些。

发布了556 篇原创文章 · 获赞 3622 · 访问量 473万+

猜你喜欢

转载自blog.csdn.net/feixiaoxing/article/details/102557931