I am not MinGW developer, but your question is very common and not really depend on how you create the DLL. Such problems will by typically solved with the usage of three techniques:
- choosing of unique base addresses of the DLLs
- binding the DLLs and exe (during installation of the application)
- usage of DLL delay loading technique
- a little improve the loading time the call of DisableThreadLibraryCalls inside of
DLL_PROCESS_ATTACH
part of DllMain
The exact switches of linker or other tools which you can use depend on your development environment.
To understand the problem you should know how executable or DLL will be loaded. First of all the EXE or DLL will be mapped in the memory. Memory mapped file (section) will be created which points to the EXE/DLL. So you will have some addresses in the process which access will corresponds to the EXE/DLL file. If you link the DLL you can choose the base address. If the address is unused in the process address space then nothing will be done. If the first line of code will be used (you call some function from the DLL) then the page of memory 8K near the used address will be loaded in memory from the file. If two processes use the same DLL then the physical memory for the code will be shared between processes. Even if you hold initialized variables the page with the variables will be shared till the first changes of the variable. On modification will be made the copy of the page of memory for the process which did the modification.
After the DLL is loaded in the process some small parts of the caller (the EXE for example) have to be modified to include the actual addresses of the functions used from the DLL. The same will be done with the DLLs which use functions from another DLL.
Everything sound perfect, but if you don't set any linker options during DLL compilation (if you don't use --image-base
or --enable-auto-image-base
linker option) you will have all your DLLs with the same base address (default value for the linker). So the first DLL could be loaded at the address. During loading of the second DLL which are linked with the same (or some overlapped address) the relocation of the DLL will be done. During the relocation the code of DLL sill be modified and so 1) the loading of the DLL will be slowly 2) the modified copy of the code will be made in the process (which include the memory used by DLL) 3) the modified copy will be not shared between multiple instances of the DLL (even if all instances will be modified in the same way).
I recommend you first of all to use Process Explorer for example to verify which DLLs will be relocated in your application. You should choose the option "DLLs" in the "View"/"Lower Pain View" menu and select "Relocation DLLs" checkbox in "Configure Highlighting" of the "Options" menu. You can additionally customize which information about every DLL will be displayed. The more information like below you will see the more slow the program will be loaded and the more address space will be not shared between instances of your application or between different applications which use the same DLL:

In the above example you see that tree Lenovo DLLs TPOSDSVC.dll
, HKVOLKEY.dll
and TPLHMM.dll
are linked with the same base address 0x10000000
and only one DLL (TPOSDSVC.dll
here) will be loaded at the address. Two other DLLs have to re relocated.
I can't write a book here about the subject. I recommend you to examine your application on the relocation problem. You can either use linker options (--image-base
or --enable-auto-image-base
seems be what you need). You can use dumpbin.exe tool (from Visual Studio also in the free edition) to examine the PE image.
After all your DLLs will have unique base address you can use another tool bind.exe
with option -u
to bind the EXE and your DLLs to its dependent DLLs. It will additionally reduce the memory size and improved the starting time of the application. It will update IMAGE_DIRECTORY_ENTRY_IMPORT
and IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT
parts of your DLL and EXE (see the answer). Bind.exe
uses BindImageEx
API internally. Many Windows Installer setups use BindImage action and BindImage table to make the binding at the end of installation of EXE and DLLs.
You can consider other techniques (see here) to reduce the size of DLL and EXE.
I don't know exactly how you can use delay-load technique in MinGW, but it should be definitively possible. The Visual Studio you need to do two steps: include Delayimp.lib
as additional library and use /DELAYLOAD
option (see here) to specify which from the DLLs should be loaded at the first usage instead of directly. Using very helpful Tool Dependency Walker you can see that most standard Microsoft DLLs uses the technique. You can improve the start time of your application and reduce the used memory if you would use the technique too.