DLL中函数的静态调用和动态调用到底有什么差别?
这个差别不是说,动态调用是要LoadLibrary,静态的不用
我是想知道在二进制代码上的区别,也就是说特别是静态调用,到底怎么解释,比如,一般情况下,我们在VC中如果要使用CreateWindow函数,只要包含一个Windows.h,然后就可以在在代码中写入CreateWindow(...),这是静态调用,
也可以LoadLibrary(...),然后GetProcAddress(),然后CreateWindow,
在代码上是不同的,但是如果是在二进制代码级别上是否也有差别,还是一样的。
我现在的想法是应该是一样的,如果不一样那么是否就意味着微软在win9x的时候就确定了每一个API的地址,一直保持到win2k,winXP呢?好像是有难度的?静态调用只是实现形成了Lib,我们每次不用手动LoadLibray(),但是有产生了另一个问题,我们每调用一次API,如果使用静态调用那么是不是就要LoadLibrary,GetProcAddress一次呢,因为在它形成Lib的时候,它也不知道我们调用GreateWindow的时候是不是已经LoadLibray了,所以每次都要这么做的
大家说说我这种想法到底是错是对啊,已经困扰我很久了
问题点数:20、回复次数:9Top
1 楼darkread(黑色阅读)回复于 2004-05-04 16:50:58 得分 0
这个是静态调用的反汇编
#include "stdafx.h"
#include "Windows.h"
int main(int argc, char* argv[])
{
MessageBox(NULL,"Somebody Help!",NULL,MB_OK);
printf("Hello World!\n");
return 0;
}
7: int main(int argc, char* argv[])
8: {
00401010 push ebp
00401011 mov ebp,esp
00401013 sub esp,40h
00401016 push ebx
00401017 push esi
00401018 push edi
00401019 lea edi,[ebp-40h]
0040101C mov ecx,10h
00401021 mov eax,0CCCCCCCCh
00401026 rep stos dword ptr [edi]
9: MessageBox(NULL,"Somebody Help!",NULL,MB_OK);
00401028 mov esi,esp
0040102A push 0
0040102C push 0
0040102E push offset string "Somebody Help!" (0042002c)
00401033 push 0
00401035 call dword ptr [__imp__MessageBoxA@16 (0042528c)]
0040103B cmp esi,esp
0040103D call __chkesp (00401100)
10: printf("Hello World!\n");
00401042 push offset string "Hello World!\n" (0042001c)
00401047 call printf (00401080)
0040104C add esp,4
11: return 0;
Top
2 楼mynameisno1(no.1)回复于 2004-05-04 16:56:02 得分 0
静态调用的话,编译时要包含lib文件和头文件,动态调用就不用这两个东东
我想主要的一点区别就是,静态调用的库在程序启动时就装载,动态调用则是要用的时候手工装载,用完了还可以卸载(什么函数来的,忘了)
从函数执行效率等方面来看应该没什么区别
Top
3 楼darkread(黑色阅读)回复于 2004-05-04 17:07:34 得分 0
这个是在我同学的机器上编译的XP+VC7
--- f:\vc70\test_del\test_del\main.cpp -----------------------------------------
#include "stdio.h"
#include "windows.h"
int main()
{
00411A40 push ebp
00411A41 mov ebp,esp
00411A43 sub esp,0C0h
00411A49 push ebx
00411A4A push esi
00411A4B push edi
00411A4C lea edi,[ebp-0C0h]
00411A52 mov ecx,30h
00411A57 mov eax,0CCCCCCCCh
00411A5C rep stos dword ptr [edi]
MessageBox(NULL,"123",NULL,MB_OK);
00411A5E mov esi,esp
00411A60 push 0
00411A62 push 0
00411A64 push offset string "123" (424024h)
00411A69 push 0
00411A6B call dword ptr [__imp__MessageBoxA@16 (42A314h)]
00411A71 cmp esi,esp
00411A73 call @ILT+935(__RTC_CheckEsp) (4113ACh)
printf("OKKKKK");
00411A78 push offset string "OKKKKK" (42401Ch)
00411A7D call @ILT+1170(_printf) (411497h)
00411A82 add esp,4
return 0;
00411A85 xor eax,eax
}Top
4 楼darkread(黑色阅读)回复于 2004-05-04 17:13:36 得分 0
这个又是另外一个同学的
XP+VC6
--- G:\test_del\test_del.cpp ---------------------------------------------------------------------------------------------
1: // test_del.cpp : Defines the entry point for the console application.
2: //
3:
4: #include "stdafx.h"
5: #include "windows.h"
6: int main(int argc, char* argv[])
7: {
00401010 push ebp
00401011 mov ebp,esp
00401013 sub esp,40h
00401016 push ebx
00401017 push esi
00401018 push edi
00401019 lea edi,[ebp-40h]
0040101C mov ecx,10h
00401021 mov eax,0CCCCCCCCh
00401026 rep stos dword ptr [edi]
8: MessageBox(NULL,"123",NULL,MB_OK);
00401028 mov esi,esp
0040102A push 0
0040102C push 0
0040102E push offset string "123" (0042002c)
00401033 push 0
00401035 call dword ptr [__imp__MessageBoxA@16 (0042528c)]
0040103B cmp esi,esp
0040103D call __chkesp (00401100)
9: printf("Hello World!\n");
00401042 push offset string "Hello World!\n" (0042001c)
00401047 call printf (00401080)
0040104C add esp,4
10: return 0;
0040104F xor eax,eax
11: }
00401051 pop edi
00401052 pop esi
00401053 pop ebx
00401054 add esp,40h
00401057 cmp ebp,esp
00401059 call __chkesp (00401100)
0040105E mov esp,ebp
00401060 pop ebp
00401061 ret
Top
5 楼darkread(黑色阅读)回复于 2004-05-04 17:17:45 得分 0
这个是XP+VC7的
00411A6B call dword ptr [__imp__MessageBoxA@16 (42A314h)]
这个是XP + VC6的
00401035 call dword ptr [__imp__MessageBoxA@16 (0042528c)]
很奇怪吧?我晕了,42A314h和0042528c应该是MessageBoxA◎16的地址吧,怎么就不一样呢?Top
6 楼ahu9870(阿胡9870)回复于 2004-05-04 18:28:29 得分 10
正如你已经提到的,动态装载DLL与静态装载的主要区别是:
对于静态链接的DLL,主程序所引用的DLL的所有导出函数都会在LINK时建立一张引入表(见PE文件格式);在装载主程序时,同时会装入DLL,并由操作系统对其进行重定位。如果这时DLL在搜索路径中不存在,主程序将出现装载错误而失败,根本不能运行;而且,在整个主程序的运行期中,DLL不能卸载;
而对于动态链接的DLL,则是由显式的 LoadLibrary->GetProcAddress来进行调用的。主程序在装载时,并不会同时装入DLL,如果这时DLL在搜索路径中不存在,主程序不会出现装载错误。只有当LoadLibrary执行时,才真正开始主程序与DLL的引用和依赖关系。而且,当该DLL的导出函数不再需要时,可以随时卸载DLL。Top
7 楼jiang89f(new think)回复于 2004-05-04 19:28:19 得分 0
恩,我觉得初学用静态的好点,过一段用动态好Top
8 楼darkread(黑色阅读)回复于 2004-05-04 19:33:37 得分 0
我问的是动态和静态实现,在二进制代码上是否有差别??
请看清楚题目!!!!
Top
9 楼fbmsf(FBM)回复于 2004-05-05 10:33:19 得分 10
没有区别。只是用两种不同的方式来获得 api 的地址,
这个是XP+VC7的
00411A6B call dword ptr [__imp__MessageBoxA@16 (42A314h)]
这个是XP + VC6的
00401035 call dword ptr [__imp__MessageBoxA@16 (0042528c)]
42A314h)],,,0042528c)]这儿分别还有一条jmp 77xxxxxx的代码,这才是关键。Top




