Subject: More DLL issues
From: [email-masked] (Roger René Kommer)

10 Mar 1998 09:15:42 -0800
Message-ID: <01bd4b86$82373940$60040d8d.cygnus.gnu-win32@ROGKOMUN>
Mime-Version: 1.0
Content-Type: text/plain;
	charset="iso-8859-1"
Content-Transfer-Encoding: 7bit
To: <[email-masked]>

Hi,
In my spare time I still try to play with DLLs using cygwin.
Here some of my experiances:
I have improved my script cygshared (I'll append it as file attachment,
including a test suite with sample Makefile), now supporting calling
constructor and destructor of global classes inside a DLL for b18.
It also works with the new b19.
Now I'm able to compile some parts of the kde package as shared library.
Of course there are still problems with global exported objects using cpp to
map it to _imp__label, because in the context of C++ often the label is also
be used as member variable/function. It is also not very comfortable to
include the mydll_dll.h in the sources. Unfortunately, if you forget to
include this in the c files, which uses some of the global dll data, the
linker doesn't complain about unresolved symbols. It would helpful, if the
original 'label' (instead of _imp__label) doesn't appear in libmydll.a. (I
solved this, see below.)
A better solutions would be a method like this:
gcc -c myc.cc --imports mydll.def
which does following:
myc.cc is passed to the cpp, and after this, it is passed to a parser/lexer,
which looks for imported c/c++ global symbols, defined in the mydll.def and
patch the sources regarding global imported data. This would have the
advantage, that you haven't to touch the sources (which has always problems,
if you want to maintain a port like the KDE package) and you can also
provide a .def file, which only exports symbols, which really should visible
outside the DLL. I think the solution like MS it does, using extensions
__declspec(dll[ex|im]port), etc. doesn't fit to cygnus needings, because it
does also needs modifications of sourcecode. I would prefer a standard,
which looks like more transparent .so solution.

(Just a note: in Qt global defined classes are exported (and used) with the
name 'red', 'blue', 'green'. Puh!, C++ and cpp is incompatible by design and
I understand the language designers of java that they doesn't integrate a
cpp.)
There is another problem with gcc:
In sources we can often found this construction:
/* dummy.c: */
#include <stdio.h>
FILE *yyin = stdin;
int
main()
{
  return 0;
}
Actually, because stdin is defined in stdio.h this way:
#define stdin (_impure_ptr->_stdin)

the compiler complains:
'initializer element is not constant'.
If I compile the stuff with g++ the indirection can be resolve.

Is there an option of gcc to compile the .c files with enhanced
initialization syntax, but without other C++ features? Or can this problem
be solved on another way?
In C++ there is another problem:
mydll.h:
class AClass {
public :
 //...
 int getsomething() { return 42; }
};
class BClass {
public :
 static AClass aclass;
 //...
};
mydll.cc:
#include "mydll.h"
AClass BClass::aclass;
//...
myexe.cc:
#include "mydll.h"
void
foo()
{
 BClass bclass;
 bclass.aclass.getsomething();
}
To resolve this, you have to replace bclass.aclass with
(*__imp__6BClass$aclass).
This cannot be solved by cpp macros, but the sources must be modified. In
most cases it helps to wrap the access to this static members in non inlined
normal or static member functions.
If anybody would try to write an integration of linking DLLs into gcc (in a
first step what cygshared does as script) I would try to write the
lexer/parser to automatically patch sources regarding importing global data.
But probably a better way is to enhance cc1.exe and cc1plus.exe, try to
patch code generation after yyparse() the sources, before generating asm
output. I've tried to take a look at cc1.exe, but although I generally
understand how the compiler works, I was not able to find exact place
(somewhere between generating the Parse tree and setting up the rtx
structure), where I can do the necessary patches. Either I need advice from
a gcc guru, or even such a gcc guru had to do the work.

TASKS
- Do not export global data directly via label 'label' in libDLL.a. It
should not be visible! Only '__imp_label' should be visible outside the DLL.
I've wrote a patch to dlltool, with a new option --ie <label>
/ --ignore-exports <filename>. This option ignores <label> (all label are
listed in <filename> when building a libDLL.a. In my script cygshared I do
ignore all global data while building libDLL.a. So at least, you cannot link
to DLL-global data via <label> by accident, only <__imp_label> is
accessible. Better an error at compile/link time, then a runtime error which
is only confusing.
Compiling a source
- patch sources at compile time or objects at linking time to map imported
'label' to (*_imp__label).
For C++-Sources there is an handcrafted solution:
Create a stub for each dll and link it to libDLL.a:
dll_globals.h:
extern int &dllglobal;
DLL_global_stub.cc:
extern int *__imp_dllglobal;
int &dllglobal = *__imp_dllglobal;
// just for demonstration
extern "C" void printDLLstup()
{
  printf("proxy: dllglobal: %i\n", dllglobal);
  *__imp_dllglobal = 42;
  printf("proxy: dllglobal(42): %i\n", dllglobal);
}
Unfortunatelly this only works for C++ sources, but has the advantage, that
you need no preprocessor redefining of label 'dllglobal'. Another problem
is, how to generate this stub automatically, because you do need the exact
type of 'dllglobal'.

- Integrating dlltool and other tools inside gcc/ld

Roger

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