| #
32934d5b |
| 08-May-2022 |
Pali Rohár <[email protected]> |
libpci: Add support for building versioned shared Windows DLL library libpci3.dll
PE/COFF format, used by DLL libraries, does not support version symbols like ELF format. Recommendation from Microso
libpci: Add support for building versioned shared Windows DLL library libpci3.dll
PE/COFF format, used by DLL libraries, does not support version symbols like ELF format. Recommendation from Microsoft for DLL symbol versioning is to use DLL API sets. But DLL API sets scheme requires for every API change to generated a new slim forwarding DLL library, which is unsuitable for distribution which wants just one DLL library with all version symbols.
So instead of Microsoft recommended scheme for DLL versioning, use new different versioning scheme: Symbol is composed by function name, at (@) character and version string (version is same as for ELF targets). Symbol name without version information is added only into the DLL DEF file as alias to symbol with higest version. So linker at application link time resolves "unversioned" symbol to the versioned one via this alias and puts "versioned" symbol into final executable. This works fine if GNU LD is linking application via import library libpci3.dll.a generated from that DLL DEF file libpci3.def. But does not work when linking directly to the DLL library because library itself does not contain aliases. Note that GNU LD does not support linking to DEF file (it is required to first generated import library from DEF file).
Note that older GNU LD versions have bug which cause generation of corrupted DLL files if some symbol contains dot (.) character. Hopefully this bug was fixed in GNU LD 2.21.
At the end application lspci.exe requires library libpci3.dll with symbols pci_alloc@LIBPCI_3.0, pci_init@LIBPCI_3.5, pci_fill_info@LIBPCI_3.8 and therefore libpci3.dll stays backward compatible with future changes.
PE/COFF executables can reference symbols either via name or via its ordinal number. Because DLL DEF files are generated from libpci version script and generator ver2def.pl preserves order of symbols, it means that ordinal numbers stay backward compatible unless order of lines in version script is changed.
WARNINGS:
GCC an GNU LD for Windows target have some bugs which cause that -fvisibility=hidden switch and __attribute__((visibility("default"))) does not work. Seems that they are broken and ignored when building DLL library. So instead use -Wl,--exclude-all-symbols switch with explicit DLL DEF file for building DLL library, which seems to work. This switch is supported since GNU LD 2.21.
GNU LD has also another bug which results in broken DLL library if input DLL DEF file which describes symbols for exports, contains also symbol aliases via == operator.
So do not specify symbol aliases in input DLL DEF file for building DLL library. Instead construct separate DLL DEF file for building libpci3.dll without symbol aliases and separate DLL DEF file libpci3.def with symbol aliases for building import library libpci3.dll.a suitable for linking into target applications. Note that operator == for symbol aliases is supported since GNU dlltool 2.21.
Generate those two DLL DEF files via new script ver2def.pl from libpci.ver version script. So exported functions and version symbols would be defined only at one place in file libpci.ver.
Note that GNU LD for Windows targets has also broken support for version scripts, it exports nonsense data and completely ignores version information. So always use only DLL DEF files generated by ver2def.pl script and never pass original version script to GNU LD.
Due to another bugs in GNU dlltool, ordinals for aliased symbols from DLL DEF file are calculated incorrectly when building import library. So calculate ordinals manually in ver2def.pl script and explicitly put then into generated libpci3.def DLL DEF file for every symbol, including aliases.
And because aliases are stored only in libpci3.def file (and in import library libpci3.dll.a generated from that DEF file) and not in DLL library libpci3.dll itself, it is required to link all libpci applications via import library and not directly to libpci3.dll. This is limitation of PE/COFF format used by DLL libraries.
So for building Windows DLL library libpci3.dll is needed to use GNU binutils 2.21 or new.
show more ...
|