MinGW gcc generates a summary of some issues with the dynamic link library dll, mingwgcc

Source: Internet
Author: User

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.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.