MinGW gcc generates a summary of some issues with the dynamic link library dll, mingwgcc
There are many articles on using MinGW gcc to generate dynamic link libraries on the network. The methods described are also slightly different. This time I used it in a project, so I spent some time experimenting with the various methods introduced on the Internet. In addition, I tried some methods that were not mentioned on the Internet based on my own understanding. Here, I will summarize the results obtained in the past two days.
First, let's talk about my development environment:
Gcc version 4.9.2 (Rev1, Built by MSYS2 project)
Target: i686-w64-mingw32
Thread model: posix
-- Disable-sjlj-exceptions -- with-dwarf2
In addition, to test whether the generated dll is common. Visual Stdio 2010 is also used for testing code.
When experimenting with a new feature, I usually start with the simplest code.
//dlltest.cint Double(int x){ return x * 2;}
The following command line compiles the code into a dll.
Gcc dlltest. c-shared-o dlltest. dll-Wl, -- out-implib, dlltest. lib
Among them,-shared tells the gcc dlltest. c file to be compiled into a dynamic link library. -Wl indicates that the following content is the ld parameter and must be passed to the ld. -- Out-implib, dlltest. lib indicates that the ld will generate a import database named dlltest. lib.
If the. def file is also required, the preceding command line can be written as follows:
Gcc dlltest. c-shared-o dlltest. dll-Wl, -- output-def, dlltest. def, -- out-implib, dlltest.
//main.c#include <stdio.h>int Double(int x);int main(void){ printf("Hello :%d\n", Double(333)); return 0;}
Gcc main. c dlltest. lib-o main.exe
The running result is:
Hi: 666
The generated dlltest. dll is correct. In addition, you can use dependecy walker to view the mutual call relationship.
In fact, if our dll file is only used by MinGW gcc. Do not need to generate dlltest. lib. Add dlltest. dll directly during compilation.
Gcc main. c dlltest. dll-o main.exe
If dll is dynamically loaded in the program. The code can be written as follows:
//m2.cdefine UNICODE 1#include <windows.h>#include <stdio.h>typedef int (*INT_FUNC)(int);int main(void){INT_FUNC db;HINSTANCE hInstLibrary = LoadLibrary(L"dlltest.dll");printf("LoadLibrary\n");db = (INT_FUNC)GetProcAddress(hInstLibrary, "Double");printf("Hello :%d\n", db(333));FreeLibrary(hInstLibrary); return 0;}
Dlltest. lib is not required during compilation, or even dlltest and dll are not required.
Gcc m2.c-o m2.exe
The running result is correct.
Can this dll be used by other c compilers? The test using VC 2010 shows that the exe file can be generated. If the Debug mode exe file is generated, the execution is normal. But after changing to the release mode, an error is reported every time you run the command.
Use the debug function of VS2010 to view the disassembly result. It seems to be normal.
int _tmain(int argc, _TCHAR* argv[]){int a;a = Double(333);01021000 push 14Dh 01021005 call _Double (1021024h) printf("Hello :%d\n", a);0102100A push eax 0102100B push offset string "Hello :%d\n" (10220F4h) 01021010 call dword ptr [__imp__printf (10220A0h)] 01021016 add esp,0Ch getchar();01021019 call dword ptr [__imp__getchar (102209Ch)] return 0;0102101F xor eax,eax }
The following is the result of one step following the _ Double function:
_Double:01021024 jmp dword ptr ds:[1020000h] 0102102A nop 0102102B nop
After the Jmp statement:
00905A4D ??? 00905A4E ??? 00905A4F ??? 00905A50 ??? 00905A51 ??? 00905A52 ??? 00905A53 ???
However, in Debug mode:
_Double:011B144C jmp dword ptr [__imp__Double (11B8340h)] 011B1452 nop 011B1453 nop 011B1454 int 3 011B1455 int 3
After the Jmp statement:
6C101560 push ebp 6C101561 mov ebp,esp 6C101563 mov eax,dword ptr [ebp+8] 6C101566 add eax,eax 6C101568 pop ebp 6C101569 ret
As you can see, it is correct that dlltest. dll is loaded to 6C100000.
I have not figured out why this is the case. It seems that I still need to work hard. So far, I have succeeded in a small step. However, if the dll is called dynamically, there is no problem.
#include <windows.h>typedef int (*INT_FUNC)(int);int _tmain(int argc, _TCHAR* argv[]){INT_FUNC db;HINSTANCE hInstLibrary = LoadLibrary(L"dlltest.dll");printf("LoadLibrary ");db = (INT_FUNC)GetProcAddress(hInstLibrary, "Double");printf("Hello :%d\n", db(333));FreeLibrary(hInstLibrary); getchar();return 0;}
This code is compiled and executed using VC2010 without any problems. Very strange. I searched online and found that the lib file generated by MinGW gcc is slightly different from the lib file generated by VC. As a result, the debugging mode works normally in the VC environment, the Release mode does not work normally. To verify this conclusion, I found some information to learn how to generate available lib files under VC from dll files.
The following methods refer to this blog:
Http://blog.sina.com.cn/s/blog_4f183d960100gqfj.html
The def file is required to generate the lib files available under VC. As mentioned earlier,-Wl, -- output-def, and dlltest. def can generate corresponding def files.
With the def file, you can use lib.exe of VS2010 to generate the corresponding lib file.
Lib/machine: ix86/def: dlltest. def
Copy the generated dlltest. lib file to the VC project. Compile and run. Everything is normal.
We know that WinAPI functions comply with Pascal's function call conventions, that is, the so-called stdcall. The function in the generated dll is the C language function call Convention (_ cdecl ). If you change it to Pascal function calling conventions, You need to modify the program code.
//dlltest.cint _stdcall Double(int x){ return x * 2;}//main.c#include <stdio.h>int _stdcall Double(int x);int main(void){ printf("Hello :%d\n", Double(333)); return 0;}
The compilation Command remains unchanged. However, the function name in the generated dll file changes. See. It turns out that Double is now converted to Double @ 4, which is the name of a function similar to C ++. However, this does not affect usage.
All online articles about generating and using dll will be written. Generating dll is a function declaration that requires _ declspec (dllexport). When using dll, the function declaration must use _ declspec (dllimport ). As you can see, none of the above Code has been used. So what are the purposes of these two statements. The following is a test.
First, add the following to the dll Generation Code:
//dlltest.cint __declspec(dllexport) _stdcall Double(int x);int _stdcall Double(int x){ return x * 2;}
The compilation command is as follows:
Gcc dlltest. c-shared-o dlltest. dll-Wl, -- output-def, dlltest. def, -- out-implib, dlltest.
The M. c file remains unchanged:
//m.c#include <stdio.h>int _stdcall Double(int x);int main(void){ printf("Hello :%d\n", Double(333)); return 0;}
The compilation command is as follows:
Gcc m. c dlltest. a-o m2.exe
Compilation is fine, and execution is fine.
Modify m. c.
//m.c#include <stdio.h>int __declspec(dllimport) _stdcall Double(int x);int main(void){ printf("Hello :%d\n", Double(333)); return 0;}
The compilation command is as follows:
Gcc m. c dlltest. a-o m2.exe
Compilation is fine, and execution is fine.
Modify main. c.
//main.c#include <stdio.h>int __declspec(dllexport) _stdcall Double(int x);int main(void){ printf("Hello :%d\n", Double(333)); return 0;}
The compilation command is as follows:
Gcc main. c dlltest. a-o m2.exe
Compilation is fine, and execution is fine. This experiment shows that _ declspec (dllexport) has no effect on function declaration. I have also compared the decompiling results of the generated code. The code generated after _ declspec (dllexport) is not as refined as some people have said. Of course, this may also be the result of increasing Compiler Optimization capabilities. Early compilers cannot keep up, but there may be a difference.
But _ declspec (dllexport) has an impact on the output variable. See the following test code:
//dlltest.cint Double(int x);int xxx = 123;int Double(int x){ return x * 2;}//m.c#include <stdio.h>int Double(int x);extern int xxx;int main(void){ printf("Hello :%d\n", Double(333)); printf("%d", xxx); return 0;}
Compile:
Gcc dlltest. c-shared-o dlltest. dll-Wl, -- output-def, dlltest. def, -- out-implib, dlltest.
Lib/machine: ix86/def: dlltest. def
Gcc m. c dlltest. a-o mm.exe
This can be compiled and executed, indicating that dlltest. a contains sufficient information.
But the third sentence is changed:
Gcc m. c dlltest. lib-o mm.exe
There will be the following errors, which also shows that there are some minor differences between dlltest. a and dlltest. lib.
Undefined reference to 'xxx'
Collect2.exe: error: ld returned 1 exit status
VS2010 compilation is similar and cannot find the definition of the symbol xxx. Even if the following declaration is added to main. c: extern int _ declspec (dllimport) xxx;
The result is similar: error LNK2001: the external symbol _ imp _ xxx that cannot be parsed.
It means that there is no xxx information in dlltest. lib, and it is impossible to access xxx in dlltest. dll.
If _ declspec (dllexport) is added to the dll global variable declaration, the results will be different.
//dlltest.cint Double(int x);int __declspec(dllexport) xxx = 123;int Double(int x){ return x * 2;}//m.c#include <stdio.h>int Double(int x);extern int xxx;int main(void){ printf("Hello :%d\n", Double(333)); printf("%d", xxx); return 0;}
Gcc dlltest. c-shared-o dlltest. dll-Wl, -- output-def, dlltest. def, -- out-implib, dlltest.
Lib/machine: ix86/def: dlltest. def
Gcc m. c dlltest. a-o mm.exe
Compiled successfully,
Gcc m. c dlltest. lib-o mm.exe
Still failed.
Compiling m. c In VS2010 still fails. The error message is:
Error LNK2001: external symbol _ xxx that cannot be parsed
M. c. Make some modifications. Add _ declspec (dllimport)
//m.c#include <stdio.h>int Double(int x);int __declspec(dllimport) xxx;int main(void){ printf("Hello :%d\n", Double(333)); printf("%d", xxx); return 0;}
Compile in VS2010. In addition, I would like to say that the test results show that __declspec (dllimport) and _ declspec (dllexport) are no different for compilation, the literal difference is entirely for programmers themselves.
Now, the common problems of dll generation by MinGW gcc are all solved.