[Fwd: SUMMARY: Dynamic linking]

Alexander Mader mader@kapp-coburg.de
Thu Dec 2 05:44:00 GMT 1999


Hallo,

some time ago James Stern posted this summary.

Alexander.
-- 
Alexander Mader <mader@niles.de>	Fon: +49-30-92797-556
NILES Werkzeugmaschinenfabrik GmbH


To : cygwin at sourceware dot cygnus dot com
Subject : SUMMARY:  Dynamic linking
>From : James Stern <jsternitg at yahoo dot com>
Date : Thu, 26 Aug 1999 11:07:01 -0700 (PDT)
Reply-To : stern at itginc dot com

I've posted several questions to this group recently
about Cygwin dynamic linking.  My problems arose in an
attempt to port an application from Solaris to Cygwin
on NT.

The application links dynamically on Solaris and runs
with no problems so I naively expected a smooth NT
port.  However, Windows's dynamic linking works
differently from Solaris's and Cygwin had to adopt the
Windows rules.

I haven't finished the port but I've been able to
solve all the errors I've seen for the last few days.

That's thanks to this list, especially to Mumit Khan
and Paul Sokolovsky.  Clark Sims, John R. Hanson and
Chris Faylor provided some good background
information.

I thought now would be a good time to post a summary. 
I am writing this for Unix folk who are as clueless
about Windows "Dynamic Link Libraries (DLLs)" as I
was.   I.e., completely.  :-)  That's why this
"summary" is so long.

The easiest way I know to build a DLL is via Mumit
Khan's dllwrap command.

But however you do it, three files are produced in a
library's march toward DLL-hood:
=================================================

   1. A DEF file, dll.def, which lists the exported
symbols.  The Windows linker requires this.

   The DEF file can be discarded after you've built
the other two files.  You can build the DEF file
yourself or let dllwrap build it for you.  I prefer
the latter.

   I couldn't get dllwrap's --export-all-symbols to
export everything for me from my original module but
the solution was easy.  I wrote a few lines of bash +
gawk to generate:

      // export_everything.cc -- Generated file
      extern "C" {
			
         __declspec (dllexport) int f();
         __declspec (dllexport) int g();
         __declspec (dllexport) extern char v;
      }
      void never_called (void) {
         // Use everything to force the compiler to
         // generate references
         f();
         g();
         v = 'a';
      }

   Compile this and feed export_everything.o to
dllwrap along with the DLL's other object modules. 
The __declspec (dllexport) tag tells dllwrap to put
the symbol in its generated DEF file.

   I use extern "C" above because the output of nm
lists the mangled names and I don't want them mangled
again.  This would not be necessary for a C
application.

   I had to compile a call to every function and an
assignment to every variable to persuade the compiler
to generate the desired external references.  Also, I
give every function a void argument list and declare
every extern as char but that doesn't matter since the
statements in never_called don't get executed.

   2. The DLL proper, dll.dll.  This contains the
actual code and data you are linking to.  dllwrap
creates this.

   3. An "import library," libdll.a, used to link
clients.  The import library contains two stubs for
every function f():  _f and __imp__f.  The real code
for f() is in dll.dll.

   As I understand it, a call to f() branches to the
_f stub, which then calls __imp__f.  __imp__f branches
to the real f(), which is in dll.dll.  Someone (I'm
not sure who -- This may happen at program startup),
ensures that dll.dll is loaded before the first call
to it is made.

  If you declare f():

	__declspec (dllimport) TYPE f(arguments);

a call to f() will go directly to __imp__f, thus
saving a few machine instructions.  However, function
calls work even without the __declspec (dllimport)
tag.

   The situation is sadly different for variables.  An
extern variable, v, used in a client and defined in a
DLL must be declared like this in every client source
file that uses it:

   __declspec (dllimport) extern int v;

   Every DLL source file that uses it must declare it
as:

   extern int v;

   And of course, one DLL source file must define the
variable, e.g., as:

      int v = 42;

   An "extern" declarations usually appears in a
header file, say v.h. Generally, client and DLL source
files both #include "v.h" to get the declaration of v.

   You end up coding something like this inside v.h:

      VISIBILITY int v;

   A client source file does this:

      #define VISIBILITY __declspec (dllimport)
      #include "v.h"

   A DLL source file does this:
      #define VISIBILITY
      #include "v.h"

   If your application has a lot of extern variables,
this can mean a lot of source changes.  Sadly, my
application does.

   Mumit noted that applications should avoid extern
variables wherever possible.  I heartily agree but I
have to port the code as it is.

==================================================

Summary:

   * Declare every exported symbol __declspec
(dllexport) in at least one DLL source file.

   * Declare every imported variable __declspec
(dllimport) in every client source file that uses it.

   * __declspec (dllimport) is optional for functions.
 If used, it will save a few machine instructions per
call.

   * Say you have a client, main.exe, that uses
dll1a.dll and dllb.dll.  If you move function f() from
dlla to dllb, it appears you have to:

      * Regenerate dlla and dllb via dllwrap.

      * Relink main.exe with the new libdlla.a and
libdllb.a files.  Otherwise, main.exe will try to get
f() from dlla.

   * Don't do it yourself.  Use dllwrap.

I welcome any corrections to the above.


===
-- 
Opinions expressed above are not necessarily my employer's.
James M. Stern
ITG Inc.  Culver City, CA (213) 270-7955
__________________________________________________
Do You Yahoo!?
Bid and sell for free at http://auctions.yahoo.com


--
Want to unsubscribe from this list?
Send a message to cygwin-unsubscribe@sourceware.cygnus.com




More information about the Cygwin mailing list