Subject: RE: exported variables from dll
From: [email-masked] (Colin Peters)

15 Jun 1997 03:22:59 -0700
Approved: [email-masked]
Distribution: cygnus
Message-ID: <01BC7986.94EA68A0.cygnus.gnu-win32@gbird0>
Mime-Version: 1.0
Content-Type: text/plain; charset="us-ascii"
Content-Transfer-Encoding: 7bit
Original-To: "'Philippe GIACINTI'" <[email-masked]>
Original-Cc: "'GNU-Win32'" <[email-masked]>
Original-Sender: [email-masked]

Philippe GIACINTI[SMTP:[email-masked]] wrote:
>I wish to define some variables in a dll and use them in another, on Unix I
>have no problems: the variable is defined global in one .cc and extern in
>another.
>If I use the same code in Cygwin32, it seems that each dll have a local copy of
>this variable ( ie: the addresses are different ).
>I tried to do this with VisualC++, and it works if I use the directive
>DllImport instead of extern.
>
>( in fact I have this problem in a dll which uses stdout, I found that
>"_impure_ptr" was correctly initialized in main, but was null in the dll )
>
>I'm really new in Cygwin32 and Windows environment, and I think (hope) it comes
>from my ignorance.

It's a little hard to be sure from the information you have given, but I
think your problem is related to the way dlltool builds import libraries.
Basically lets say you have a DLL with a function "Foo" and a variable
"bar". Your .def file will look something like this:

EXPORTS
 Foo
 bar

First thing you should notice: dlltool cannot tell that one of these is
a function and the other is a variable. Dlltool builds a import library
basically consisting of functions which do something like this:

Foo ()
{
 return __imp_Foo();
}

bar ()
{
 return __imp_bar();
}

__imp_Foo and __imp_bar are symbols in a special table that gets filled
in with the *real* addresses of the Foo and bar symbols when the DLL that
contains them is loaded at run time.

So when you call Foo, you are actually calling a thunk function statically
linked into your own code, which effectively looks up the real address of
the function you wanted and calls it (all the arguments just pass straight
through).

But what happens to the variable? Well, if you do something like this in
your code:

 x = bar;

The symbol bar is defined and all that, but it's defined as a pointer to
the *thunk function*! Thus, every dll or program that uses the bar
variable will, indeed, have it's own copy, because they all have their
own thunk. And, of course, that value will have absolutely nothing to
do with what you wanted to do.

In Visual C++ the __dllimport (or __dllexport, whatever) keyword tells
the compiler directly that the given variable or function is imported
from a DLL. The compiler can generate the appropriate code directly
where any reference is made to the given symbol, whether it is a
function call or variable reference. Thus, no thunks are necessary
and variable references are correct. You also don't need a .def file
or an import library at all.

Gcc, as far as I know, does not have a mechanism for doing this (yet), so
we have to use dlltool to fool the compiler into putting our function
calls through a thunk. Unfortunately this messes up variable references.

Here is a workaround that I use with the current system:

  In your header file do something like this:

     #ifdef DEFINING_DLL
     int bar;
     #else
     extern int* __imp_bar;
     #define bar (*__imp_bar)
     #endif

  This way when DEFINING_DLL is set (which you only do in the DLL
  which actually contains the variable) you get the normal int
  variable. In the other code which uses the variable any
  reference to bar becomes an indirect reference through the
  __imp_bar variable created by dlltool.

This is a temporary solution of course. What *should* happen (IMHO)
is that gcc should learn how to do that itself and generate the
appropriate code for shared libraries (I would have thought they
would do it for UNIX shared libraries anyway). We could then do
away with dlltool and .def files altogether. Instead your headers
might look like this:

  #ifdef DEFINING_DLL
  #define DLLSYMBOL __attribute__(__dllexport__);
  #else
  #define DLLSYMBOL __attribute__(__dllimport__);
  #endif

  int DLLSYMBOL Foo();
  int DLLSYMBOL bar;

or possibly even this:

  __dllexport int Foo();
  __dllexport int bar;

As a special wish list item I would like to be able to do something
like this in C++:

__dllexport class MyClass
{
 ...
};

And have all the member functions (and static variables) of the
class reside in a dll. This would save me the hassle of generating
..def files for C++ classes, and the worries about the internals
of virtual functions and inheritance from the exported class (and
run time type information too, if supported). If this ever happens
I will be an extremely happy camper. :)

(By the way, I am not really suggesting syntax here, because I
might have the attribute thing wrong, but I do think it would
be nice to make it so that, either with a #define or directly,
headers using MSVC __dllexport type constructs could be used
with GCC.)

As I said though, this is not yet the case, so you have to
resort to the above trickery, which is ugly and dependent on
the undocumented inner workings of dlltool.

Would someone else on the list like to take up the question about
_impure_ptr? I pretty much only use Mingw32, which has it's own
DLL startup code that initializes stdout and so on (and doesn't
use _impure_ptr), so I'm not in a position to know exactly what
the problem there is.

Anyway, good luck,
Colin.

-- Colin Peters - [email-masked]
-- Saga University Dept. of Information Science
-- http://www.fu.is.saga-u.ac.jp/~colin/index.html
-- http://www.geocities.com/Tokyo/Towers/6162/

-
For help on using this list (especially unsubscribing), send a message to
"[email-masked]" with one line of text: "help".