How to tell the MinGW linker not to export all sym

2019-04-19 07:53发布

问题:

I'm building a Windows dynamic library using the MinGW toolchain.

To build this library I'm statically linking to other 2 which offer an API and I have a .def file where I wrote the only symbol I want to be exported in my library.

The problem is that GCC is exporting all of the symbols including the ones from the libraries I'm linking to. Is there anyway to tell the linker just to export the symbols in the def file?

I know there is the option --export-all-symbols but there seems not to be the opposite to it.

Right now the last line of the build script has this structure:

g++ -shared CXXFLAGS DEFINES INCLUDES -o library.dll library.cpp DEF_FILE \
OBJECT_FILES LIBS -Wl,--enable-stdcall-fixup

EDIT: In the docs about the linker it says that --export-all-symbols is the default behavior and that it's disabled when you don't use that option explicitly if you provide a def file, except when it doesn't; the symbols in 3rd party libs are being exported anyway.

EDIT: Adding the option --exclude-libs LIBS or –exclude-symbols SYMBOLS doesn't prevent the symbols from the libraries from being exported.

回答1:

You can use dllwrap if your distribution of binutils (either native or cross compiling) provides it.

It can produce DLLs using the interface in a DEF file (under the hood it calls gcc, ld and dlltool to do so). The difference between using this and passing a DEF file to GCC directly is that the definitions in the file are treated differently.

For example, if you have a symbol rename in the export file:

_SomeFuntion = _SomeFunction@12

GCC will create 2 exports, one by the name of _SomeFunction and the other one with the decorated name while dllwrap will only export _SomeFuntion. So if you only add to the DEF file the symbols you want to be exported you will end up only with them in the library.

dllwrap by default uses the C compiler driver since it has no way of knowing otherwise. As you're linking C++ code, you have to use the option --driver-name c++ to set the driver. If you happen to have the MinGW executables with a prefix you have to include it too in the driver name (e.g. i686-mingw32-c++ instead of c++) and you may need to use the option --dlltool-name too.

Try using these two lines instead of the one you posted:

g++ -c CXXFLAGS DEFINES INCLUDES -o library.o library.cpp
dllwrap -o library.dll --driver-name c++ --def DEF_FILE OBJECT_FILES LIBS -Wl,--enable-stdcall-fixup

The first one generates an object file from the code of library.cpp and the second one assembles the dynamic library. The OBJECT_FILES thing (which I assume to be other object files you generated previously) should have library.o there too.

That said, I have to tell you dllwrap was already deprecated in 2006 and there is no documentation on it in the official binutils package; to get some info you may call it with --help as usual. It can generate an import library in case you need it too.



回答2:

Not sure why there's no real answer to this, but here's what worked for me:

  1. Compilation of your object files:

    g++ -O0 -gdwarf-4 dll\dllmain.cpp -c -o dllmain.o
    
  2. Linking (-Wl,--exclude-all-symbols is important):

    g++ -Wl,--enable-auto-import -Wl,--out-implib,libsomelib.a -Wl,--exclude-all-symbols -shared dllmain.o -o somelib.dll
    

Then you choose which functions to export directly in source code of your DLL:

#include <windows.h>

__declspec(dllexport) void someExportedFunction() {
    MessageBox(NULL, "msgbox", "msgbox", MB_OK);
}

void nonExportedFunction() {
    MessageBox(NULL, "notexported", "notexported", MB_OK);
}

Verification:

C:\libtest>pedump -E somelib.dll

=== EXPORTS ===

# module "somelib.dll"
# flags=0x0  ts="2014-02-20 08:37:48"  version=0.0  ord_base=1
# nFuncs=1  nNames=1

  ORD ENTRY_VA  NAME
    1     1570  _Z20someExportedFunctionv

(pedump = http://pedump.me)



回答3:

This is a recurrent issue. Here are two related questions in SO:

  • Removing exported symbols from a DLL and its associated import library (VS8)
  • https://stackoverflow.com/questions/9586262/how-to-know-exported-symbols-for-windows-dll-from-linux-mingw/9600759#9600759 (DEAD)

and outside SO:

  • http://boost.2283326.n4.nabble.com/unwanted-exported-symbols-in-a-DLL-which-statically-links-to-Boost-Library-td2590169.html
  • http://sourceforge.net/p/mingw/bugs/1134/

i.e. global / local exporting on the Windows platform is not handled at the linker level but but the provision of a .def file to complement the .dll.

Lacking a good answer, I did a python script that takes care of removing stuff from the dll export table, you can find it here .



回答4:

Did you read this on the page you supplied alink to, regarding behaviour if --export-all-symbols is not used explicitly - auto export is disabled if:

Any symbol in any object file was marked with the __declspec(dllexport) attribute.

Have you tried explicitly exporting only the functions you are interested in? It's very easy to get names wrong in DEF file, because of mangling, so this method should be more reliable.



回答5:

You can use the option -Wl,--retain-symbols-file=file and then list the symbols you want to keep (one per line) in file. This will cause the linker to discard all other symbols, keeping just the ones you want.



回答6:

Disclaimer: I've only done this on Linux, but AFAIK it should work on Windows as well

You can use the -fvisibility=hidden option; for more info see http://gcc.gnu.org/wiki/Visibility