Math.c { __declspec (dllexport) double Add (xx, xx) {...}}
MathApp.c { __declspec(dllimport) double Add (xx, xx); }
1.生成dll
cl /LD Math.c =>
Math.obj -
- 因为保存dllexport而保存了/EXPORT:_Add的linker directive,
- 如果没有dllexport,也可以通过link Math.obj /DLL /EXPORT:_Add 导出符号生成dll文件。
Math.dll -
- (与PE格式基本相同, 头文件中符号位标示不同, 默认load addr不同, 其他扩展名: .OCX, .CPL, etc)
- 在不同进程中data是私有的
- ??load以后的代码段不是地址无关的,所以只有在某些情况下可以多进程共享dll代码 (与linux的elf不同)
Math.lib (import lib, MathApp.c需要与之link) , 对Add有两个符号-
- Add : stub code, 形如: [XXX2] Add: JMP DWORD PTR [XXX1] , 其中XXX1为IAT中的一项 (??在load的时候XXX1里面的内容会被改写)
-_imp_add: 直接指向IAT中的所在项,值为XXX1
[Math.exp 临时保存export symbol table,与obj格式相同, 也可能直接保存在dll的.rdata段] -
[ - 导出符号的形式: 形如 _Add@n n为参数堆栈大小,可以通过def文件定义别名实现多语言兼容, 如__stdcall的name修饰也是_Add@n (e.g. WINAPI), _cdecl 不修饰]
2. 生成 MathApp.exe
- 有一个IMAGE_IMPORT_DESCRIPTOR结构,对应于一个被导入的dll,指向该dll相关的一个IAT表和一个INT表
-这里的IAT表: 符号位1: 跟导入符号序号, 符号位0: 跟导入符号的序号hint和符号名
cl /c MathApp.c =>
MathApp.obj
link MathApp.obj Math.lib =>
MathApp.exe
3. dllimport
3.1 cl /LD Math.c 在生成.lib文件时,会在.lib中为Add生成两个符号名Add与_imp_Add
- Add : stub code, 形如: [XXX2] Add: JMP DWORD PTR [XXX1] , 其中XXX1为IAT中的一项 (??在load的时候XXX1里面的内容会被改写)
-_imp_add: 直接指向IAT中的所在项,值为XXX1
3.2 如果MathApp引入Add符号的时候
-有 __declspec(dllimport), 则complile实际生成的符号名为_import_Add, 与Math.lib中的_imp_add对应, link的时候生成形如 CALL DWORD PTR [XXX1]的code
-没有__declspec(dllimport), 则complie的生成的符号名为Add, obj中找不到以后,与Math.lib中的Add对应, link的时候生成形如 CALL XXX2的code, 则运行时先CALL XXX2,再JMP DWORD PTR [XXX1],比 CALL DWORD PTR [XXX1] 多了一次跳转。