Environment: vs2005 + xpsp3
Author: magictong
Time: 2010-09-08
Note: In the demo, the compilation in the debug mode is used. In the release mode, there are some differences in the process due to some optimizations, but the final conclusion is the same.
_ Declspec itself is Microsoft's extension to C ++, so the subsequent discussions refer to the results compiled under vs2005, and_ Declspec (dllimport)The relative combination is _ declspec (dllexport), __declspec (dllexport) Acts on the PE File Export function, class, variable, and so on (if you do not need to use the def File Export function, you must use _ declspec (dllexport) for export ). _ Declspec (dllimport) is vague in msdn, as shown in the following importing
Into an application using _ declspec (dllimport ):
English:
Using _ declspec (dllimport) is optional on function declarations, but the compiler produces more efficient code if you use this keyword. however, you must use _ declspec (dllimport) for the importing executable to access the DLL's public data symbols and objects.
Note that the users of your DLL still need to link with an import library.
Chinese:
Using _ declspec (dllimport) in function declaration is optional. However, if this keyword is used, the compiler generates more effective code. However, _ declspec (dllimport) must be used to allow the imported executable file to access the common data symbols and objects of the DLL ). Note that the DLL user still needs to connect with the import/export link.
The so-called optional operation is optional, but if used, the compiler will generate more efficient code. Well, this is what the compiler means. Then I tested four cases to see what the situation was.
Scenario 1: EXE calls its own SWAp function internally. The swap function does not use the _ declspec (dllimport) modifier.
int swap(int& a, int& b);int swap(int& a, int& b){ a = a ^ b; b = a ^ b; a = a ^ b; return 0;}
The assembly code generated by the call to swap is:
Swap (m, n );
00411423 Lea eax, [N]
00411426 push eax
00411427 Lea ECx, [m]
0041142a push ECx
0041142b call swap (411113 H)
00411430 add ESP, 8
Let's take a look at the address 411113 h as a JMP command to jump to the real address of swap:
0x00411113 E9 98 04 00 00
00411113 JMP swap (4115b0h)
Int swap (Int & A, Int & B)
{
004115b0 push EBP
004115b1 mov EBP, ESP
004115b3 sub ESP, 0c0h
Therefore, this is only a normal function call.
Scenario 2: EXE calls its own SWAp function internally, and swap function uses _ declspec (dllimport) to modify
This situation is basically the same as the code generated in a lifetime. The only difference is that the following warning will appear at the implementation of swap during compilation (which means that the Declaration is somewhat inconsistent, it is a little different from the expectation of the compiler, because the compiler is expected to be a DLL export function. Well, this is probably the case and you don't need to go into it ):
Warning c4273: 'SWAp ': inconsistent DLL Linkage
Case 3: EXE calls the DLL add function internally. The add function does not use the _ declspec (dllimport) modifier.
#if IMPORTDLLDLL_EXPORTS#define API_DECLSPEC __declspec(dllexport)#else #define API_DECLSPEC#endif // ------------------------------------------------------------------------- API_DECLSPEC int __stdcall add(int a, int b); int __stdcall add(int a, int b){ return a + b;}
The assembly code generated by calling add is:
Add (m, n );
004113fc mov eax, dword ptr [N]
004113ff push eax
00411400 mov ECx, dword ptr [m]
00411403 push ECx
00411404 call add (411127 H)
Check that the address 41120.h is also a JMP command, jump to 411620 H
0x00411127 E9 F4 04 00 00
00411127 JMP add (411620 H)
After redirecting to 42.1620h, we found that it was not the Add address,
00411620 jmp dword ptr [_ imp_add (4181e0h)]
Still a JMP command, jump to a location directed to 4181e0h. Check the memory, it should jump to 0x100110f0 to execute: 0x004181e0 F0 10 01 10
In the past, it was still a jump command. This time it was redirected to 0x10011340:
100110f0 JMP add (10011340 H)
Again, this is the last time:
Int _ stdcall add (int A, int B)
{
10011340 push EBP
10011341 mov EBP, ESP
10011343 sub ESP, 0c0h
10011349 push EBX
This is a tangle. There are several more JMP commands in the middle. Let's leave it blank. Let's take a look at situation 4 and discuss it later.
Scenario 4: EXE calls the DLL add function internally, and the Add function is modified using _ declspec (dllimport ).
#if IMPORTDLLDLL_EXPORTS#define API_DECLSPEC __declspec(dllexport)#else #define API_DECLSPEC __declspec(dllimport)#endif // ------------------------------------------------------------------------- API_DECLSPEC int __stdcall add(int a, int b); int __stdcall add(int a, int b){ return a + b;}
The assembly code generated by calling add is:
Add (m, n );
004113fc mov ESI, ESP
004113fe mov eax, dword ptr [N]
00411401 push eax
00411402 mov ECx, dword ptr [m]
00411405 push ECx
00411406 call dword ptr [_ imp_add (4181e0h)]
This time it seems a little different. I directly called a location pointing to 4181e0h and looked at the memory:
0x004181e0 F0 10 01 10
That is to say, jump to 0x100110f0 to execute, follow the past:
100110f0 JMP add (10011340 H)
Directly run a JMP command to 10011340 h, and then use the real address of add:
Int _ stdcall add (int A, int B)
{
10011340 push EBP
10011341 mov EBP, ESP
10011343 sub ESP, 0c0h
In this case, Case 3: Case 4: Two JMP commands are missing ......
Conclusion:
It seems that msdn is right about O (Short _ sort) O. After _ declspec (dllimport) is used, the generated code is more efficient. In the view of the release code, we found that a JMP command is missing.
In fact, the entire process is quite understandable. For the compiler, you do not have the _ declspec (dllimport) to modify the function declaration, at the beginning, it will regard the function as a local function to generate the Call Code (for example, call add (411127 H )), however, at the end of the link, we found that this function is a function in the dynamic link library. The actual address will exist in the input table, so there is at least one JMP command in the middle to be used for intermediate transmission. If _ declspec (dllimport) is used for modification, the compiler knows that, oh, it is an external function. The address of the function is in the input table. Although we do not know the real address of the function, however, after loading, the function address is fixed in the input table, so the compiler directly generates code that calls the function address somewhere in the input table (for example, call
Dword ptr [_ imp_add (4181e0h)]).
[End]