This section describes some of the win32 specific ld issues. See Command Line Options for detailed description of the command line options mentioned here.
If, however, --export-all-symbols is not given explicitly on the command line, then the default auto-export behavior will be disabled if either of the following are true:
gcc -o <output> <objectfiles> <dll name>.def
Using a DEF file turns off the normal auto-export behavior, unless the --export-all-symbols option is also used.
Here is an example of a DEF file for a shared library called xyz.dll:
LIBRARY "xyz.dll" BASE=0x20000000 EXPORTS foo bar _bar = bar another_foo = abc.dll.afoo var1 DATA
This example defines a DLL with a non-default base address and five
symbols in the export table. The third exported symbol _bar
is an
alias for the second. The fourth symbol, another_foo
is resolved
by "forwarding" to another module and treating it as an alias for
afoo
exported from the DLL abc.dll. The final symbol
var1
is declared to be a data object.
The optional LIBRARY <name>
command indicates the internal
name of the output DLL. If <name> does not include a suffix,
the default library suffix, .DLL is appended.
When the .DEF file is used to build an application, rather than a
library, the NAME <name>
command should be used instead of
LIBRARY
. If <name> does not include a suffix, the default
executable suffix, .EXE is appended.
With either LIBRARY <name>
or NAME <name>
the optional
specification BASE = <number>
may be used to specify a
non-default base address for the image.
If neither LIBRARY <name>
nor NAME <name>
is specified,
or they specify an empty string, the internal name is the same as the
filename specified on the command line.
The complete specification of an export symbol is:
EXPORTS ( ( ( <name1> [ = <name2> ] ) | ( <name1> = <module-name> . <external-name>)) [ @ <integer> ] [NONAME] [DATA] [CONSTANT] [PRIVATE] ) *
Declares <name1> as an exported symbol from the DLL, or declares <name1> as an exported alias for <name2>; or declares <name1> as a "forward" alias for the symbol <external-name> in the DLL <module-name>. Optionally, the symbol may be exported by the specified ordinal <integer> alias.
The optional keywords that follow the declaration indicate:
NONAME
: Do not put the symbol name in the DLL's export table. It
will still be exported by its ordinal alias (either the value specified
by the .def specification or, otherwise, the value assigned by the
linker). The symbol name, however, does remain visible in the import
library (if any), unless PRIVATE
is also specified.
DATA
: The symbol is a variable or object, rather than a function.
The import lib will export only an indirect reference to foo
as
the symbol _imp__foo
(ie, foo
must be resolved as
*_imp__foo
).
CONSTANT
: Like DATA
, but put the undecorated foo
as
well as _imp__foo
into the import library. Both refer to the
read-only import address table's pointer to the variable, not to the
variable itself. This can be dangerous. If the user code fails to add
the dllimport
attribute and also fails to explicitly add the
extra indirection that the use of the attribute enforces, the
application will behave unexpectedly.
PRIVATE
: Put the symbol in the DLL's export table, but do not put
it into the static import library used to resolve imports at link time. The
symbol can still be imported using the LoadLibrary/GetProcAddress
API at runtime or by by using the GNU ld extension of linking directly to
the DLL without an import library.
See ld/deffilep.y in the binutils sources for the full specification of other DEF file statements
While linking a shared dll, ld is able to create a DEF file
with the --output-def <file> command line option.
__declspec(dllexport) int a_variable __declspec(dllexport) void a_function(int with_args)
All such symbols will be exported from the DLL. If, however, any of the object files in the DLL contain symbols decorated in this way, then the normal auto-export behavior is disabled, unless the --export-all-symbols option is also used.
Note that object files that wish to access these symbols must not decorate them with dllexport. Instead, they should use dllimport, instead:
__declspec(dllimport) int a_variable __declspec(dllimport) void a_function(int with_args)
This complicates the structure of library header files, because when included by the library itself the header must declare the variables and functions as dllexport, but when included by client code the header must declare them as dllimport. There are a number of idioms that are typically used to do this; often client code can omit the __declspec() declaration completely. See --enable-auto-import and automatic data imports for more information.
auto-import of variables does not always work flawlessly without additional assistance. Sometimes, you will see this message
"variable '<var>' can't be auto-imported. Please read the
documentation for ld's --enable-auto-import
for details."
The --enable-auto-import documentation explains why this error occurs, and several methods that can be used to overcome this difficulty. One of these methods is the runtime pseudo-relocs feature, described below.
For complex variables imported from DLLs (such as structs or classes), object files typically contain a base address for the variable and an offset (addend) within the variable–to specify a particular field or public member, for instance. Unfortunately, the runtime loader used in win32 environments is incapable of fixing these references at runtime without the additional information supplied by dllimport/dllexport decorations. The standard auto-import feature described above is unable to resolve these references.
The --enable-runtime-pseudo-relocs switch allows these references to be resolved without error, while leaving the task of adjusting the references themselves (with their non-zero addends) to specialized code provided by the runtime environment. Recent versions of the cygwin and mingw environments and compilers provide this runtime support; older versions do not. However, the support is only necessary on the developer's platform; the compiled result will run without error on an older system.
--enable-runtime-pseudo-relocs is not the default; it must be explicitly enabled as needed.
Linking directly to a dll uses no extra command-line switches other than -L and -l, because ld already searches for a number of names to match each library. All that is needed from the developer's perspective is an understanding of this search, in order to force ld to select the dll instead of an import library.
For instance, when ld is called with the argument -lxxx it will attempt to find, in the first directory of its search path,
libxxx.dll.a xxx.dll.a libxxx.a xxx.lib cygxxx.dll (*) libxxx.dll xxx.dll
before moving on to the next directory in the search path.
(*) Actually, this is not cygxxx.dll but in fact is <prefix>xxx.dll, where <prefix> is set by the ld option --dll-search-prefix=<prefix>. In the case of cygwin, the standard gcc spec file includes --dll-search-prefix=cyg, so in effect we actually search for cygxxx.dll.
Other win32-based unix environments, such as mingw or pw32, may use other <prefix>es, although at present only cygwin makes use of this feature. It was originally intended to help avoid name conflicts among dll's built for the various win32/un*x environments, so that (for example) two versions of a zlib dll could coexist on the same machine.
The generic cygwin/mingw path layout uses a bin directory for applications and dll's and a lib directory for the import libraries (using cygwin nomenclature):
bin/ cygxxx.dll lib/ libxxx.dll.a (in case of dll's) libxxx.a (in case of static archive)
Linking directly to a dll without using the import library can be done two ways:
1. Use the dll directly by adding the bin path to the link line
gcc -Wl,-verbose -o a.exe -L../bin/ -lxxx
However, as the dll's often have version numbers appended to their names (cygncurses-5.dll) this will often fail, unless one specifies -L../bin -lncurses-5 to include the version. Import libs are generally not versioned, and do not have this difficulty.
2. Create a symbolic link from the dll to a file in the lib directory according to the above mentioned search pattern. This should be used to avoid unwanted changes in the tools needed for making the app/dll.
ln -s bin/cygxxx.dll lib/[cyg|lib|]xxx.dll[.a]
Then you can link without any make environment changes.
gcc -Wl,-verbose -o a.exe -L../lib/ -lxxx
This technique also avoids the version number problems, because the following is perfectly legal
bin/ cygxxx-5.dll lib/ libxxx.dll.a -> ../bin/cygxxx-5.dll
Linking directly to a dll without using an import lib will work even when auto-import features are exercised, and even when --enable-runtime-pseudo-relocs is used.
Given the improvements in speed and memory usage, one might justifiably wonder why import libraries are used at all. There are three reasons:
1. Until recently, the link-directly-to-dll functionality did not work with auto-imported data.
2. Sometimes it is necessary to include pure static objects within the import library (which otherwise contains only bfd's for indirection symbols that point to the exports of a dll). Again, the import lib for the cygwin kernel makes use of this ability, and it is not possible to do this without an import lib.
3. Symbol aliases can only be resolved using an import lib. This is critical when linking against OS-supplied dll's (eg, the win32 API) in which symbols are usually exported as undecorated aliases of their stdcall-decorated assembly names.
So, import libs are not going away. But the ability to replace
true import libs with a simple symbolic link to (or a copy of)
a dll, in many cases, is a useful addition to the suite of tools
binutils makes available to the win32 developer. Given the
massive improvements in memory requirements during linking, storage
requirements, and linking speed, we expect that many developers
will soon begin to use this feature whenever possible.
LIBRARY "xyz.dll" BASE=0x61000000 EXPORTS foo _foo = foo
The line _foo = foo maps the symbol foo to _foo.
Another method for creating a symbol alias is to create it in the source code using the "weak" attribute:
void foo () { /* Do something. */; } void _foo () __attribute__ ((weak, alias ("foo")));
See the gcc manual for more information about attributes and weak
symbols.
LIBRARY "xyz.dll" BASE=0x61000000 EXPORTS _foo = foo
The line _foo = foo maps the exported symbol foo to _foo.
Note: using a DEF file disables the default auto-export behavior, unless the --export-all-symbols command line option is used. If, however, you are trying to rename symbols, then you should list all desired exports in the DEF file, including the symbols that are not being renamed, and do not use the --export-all-symbols option. If you list only the renamed symbols in the DEF file, and use --export-all-symbols to handle the other symbols, then the both the new names and the original names for the renamed symbols will be exported. In effect, you'd be aliasing those symbols, not renaming them, which is probably not what you wanted.