From: Roumen P. <bug...@ro...> - 2007-11-18 16:03:43
|
Hello MinGW community, I encounter a problem when I build some open-source libraries and programs . As example I open a request to improve mingw build in libxml2: http://bugzilla.gnome.org/show_bug.cgi?id=454388 Now I have spare time to prepare a test case for issue in error.c (libxml2) : The pointer to function fprintf in shared library(dll) differ from the pointer to same function in executable. The test case (see below in e-mail body) show that pointer to imported function differ if __declspec(dllimport) is not specified. As I understand it is not so important to specify __declspec(dllimport) for imported functions and the things should work with and without. Cross-compilation environment: - mingw-runtime-3.12 - w32api-3.9 $ gcc -v Reading specs from /opt/mingw/lib/gcc/i386-mingw32msvc/3.4.5/specs Configured with: /work/download/w32/mingw/cross/source/gcc-3.4.5-20060117-1/configure -v --prefix=/opt/mingw --target=i386-mingw32msvc --with-headers=/opt/mingw/i386-mingw32msvc/include --with-gnu-as --with-gnu-ld --without-newlib --disable-multilib Thread model: single gcc version 3.4.5 (mingw special) $ ld -v GNU ld version 2.17.50 20070129 Test case: $ cat main.c #include <stdio.h> #include <string.h> #include <stdlib.h> extern void* __declspec(dllimport) get_pointerA(void); extern void* __declspec(dllimport) get_pointerB(void); extern void* __declspec(dllimport) get_pointerC(void); extern void* __declspec(dllimport) get_pointerD(void); extern void* __declspec(dllimport) get_pointer1(void); extern void* __declspec(dllimport) get_pointer2(void); extern void* __declspec(dllimport) get_pointerA1(void); extern void* get_pointerA2(void); int main() { fprintf(stderr, "prg=%p dll=%p - get_pointerA\n" , get_pointerA , get_pointerA()); fprintf(stderr, "prg=%p dll=%p - fprintf\n" , fprintf , get_pointerB()); fprintf(stderr, "prg=%p dll=%p - strcmp\n" , strcmp , get_pointerC()); fprintf(stderr, "prg=%p dll=%p - malloc\n" , malloc , get_pointerD()); fprintf(stderr, "prg=%p dll=%p dllA=%p - get_pointerA1\n", get_pointerA1, get_pointer1(), get_pointerA1()); fprintf(stderr, "prg=%p dll=%p dllA=%p - get_pointerA2\n", get_pointerA2, get_pointer2(), get_pointerA2()); return(0); } $ cat shared.c #include <stdio.h> #include <string.h> #include <stdlib.h> extern void* __declspec(dllexport) get_pointerA(void) { return(get_pointerA); } extern void* __declspec(dllexport) get_pointerB(void) { return(fprintf ); } extern void* __declspec(dllexport) get_pointerC(void) { return(strcmp ); } extern void* __declspec(dllexport) get_pointerD(void) { return(malloc ); } /* dllimport may impact function pointer (library A)*/ extern void* __declspec(dllimport) get_pointerA1(void); extern void* get_pointerA2(void); extern void* __declspec(dllexport) get_pointer1(void) { return(get_pointerA1); } extern void* __declspec(dllexport) get_pointer2(void) { return(get_pointerA2); } $ cat sharedA.c extern void* __declspec(dllexport) get_pointerA1(void) { return(get_pointerA1); } extern void* __declspec(dllexport) get_pointerA2(void) { return(get_pointerA2); } $ cat Makefile #always different (!): #CFLAGS=-mnop-fun-dllimport #without effect: #CFLAGS="-Wl,-Bsymbolic" #CFLAGS="-Wl,--disable-auto-import" all: main.exe LD_LIBRARY_PATH=. ./main.exe main.exe: main.c shared.dll sharedA.dll $(CC) $(CFLAGS) -o $@ $< shared.dll sharedA.dll shared.dll: shared.c sharedA.dll $(CC) $(CFLAGS) -shared -o $@ $< sharedA.dll sharedA.dll: sharedA.c $(CC) $(CFLAGS) -shared -o $@ $< clean: rm -f *.exe *.dll *.o Test result (wine emulation but on native result is similar): $ make clean; make rm -f *.exe *.dll *.o cc -shared -o sharedA.dll sharedA.c cc -shared -o shared.dll shared.c sharedA.dll cc -o main.exe main.c shared.dll sharedA.dll LD_LIBRARY_PATH=. ./main.exe prg=6EB01210 dll=6EB01210 - get_pointerA prg=00402B50 dll=6EB027C0 - fprintf prg=00402B40 dll=6EB027B0 - strcmp prg=00402B30 dll=6EB027A0 - malloc prg=68A41210 dll=68A41210 dllA=68A41210 - get_pointerA1 prg=00402C10 dll=6EB02850 dllA=68A4121A - get_pointerA2 Results is correct only for functions get_pointerA and get_pointerA2 (declared as "__declspec(dllimport)" ). I would like to know is this issue related only to my build environment ? Why pointers to imported function differ if __declspec(dllimport) is not specified. Can I specify one or more compiler/linker flags to avoid problem ? Is this compiler/linker bug ? According to the test case problem in libxml could be avoided I fprintf is declared as __declspec(dllimport) in all cases. This mean that in all environments (where we build libxml and where we build applications that use libxml) fprintf should be declared as dllimport. Regards, Roumen |
From: Tor L. <tm...@ik...> - 2007-11-18 16:33:40
|
This very issue has been discussed on this list last week. Read the archives. > Is this compiler/linker bug ? No. This is documented behaviour (I hope) and should be reasonably common knowledge among programmers targeting Windows. I don't know if the C standard says anything about what one can expect from comparing function pointers passed between separately compiled and linked units. Presumably the standard leaves enough leeway for this to be compliant behaviour. > problem in libxml could be avoided [if] fprintf > is declared as __declspec(dllimport) in all cases. Well, duh. Look in stdio.h: _CRTIMP int __cdecl fprintf (FILE*, const char*, ...); What do you think the _CRTIMP means? Where else do you declare fprintf if not in stdio.h? --tml |
From: Roumen P. <bug...@ro...> - 2007-11-18 19:11:38
|
"Tor Lillqvist" wrote: > This very issue has been discussed on this list last week. Read the archives. 10x My email was prepared long time ago and since today at least I succeed to subscribe to the list(after some atemts during the past month) I post to it without to check what happen last month. Еxcuse me :) >> > Is this compiler/linker bug ? > No. This is documented behaviour (I hope) and should be reasonably > common knowledge among programmers targeting Windows. > I don't know if the C standard says anything about what one can expect > from comparing function pointers passed between separately compiled > and linked units. Presumably the standard leaves enough leeway for > this to be compliant behaviour. > I agree with you that passing function pointers 'between separately compiled and linked units' is bad design. In comment related to the libxml bug #454388 I wrote 'I dont understand why should call channel if it differ from fprintf or xmlGenericErrorDefaultFunc.' I think with you about comparison of function pointers but I need more strong arguments to explain this to *Daniel Veillard (author and maintainer).* >> > problem in libxml could be avoided [if] fprintf >> > is declared as __declspec(dllimport) in all cases. > Well, duh. Look in stdio.h: > _CRTIMP int __cdecl fprintf (FILE*, const char*, ...); > > What do you think the _CRTIMP means? Where else do you declare fprintf > if not in stdio.h? > > --tml > [SNIP] So there is bug in mingw headers : $ i386-mingw32msvc-gcc -E -DHAVE_CONFIG_H -I. -I.. -I. -I./include -I../include -DHAVE_WIN32_THREADS -D_REENTRANT -I/opt/mingw/include -DWIN32 -g -O2 ... -c ../error.c -DDLL_EXPORT -DPIC -o .libs/error.i $ grep dllimport .libs/error.i extern __attribute__ ((__dllimport__)) FILE _iob[]; extern __attribute__((dllimport)) int _libiconv_version; extern __attribute__ ((__dllimport__)) int __mb_cur_max; extern __attribute__ ((__dllimport__)) int _sys_nerr; extern __attribute__ ((__dllimport__)) char* _sys_errlist[]; extern __attribute__ ((__dllimport__)) unsigned int _osver; extern __attribute__ ((__dllimport__)) unsigned int _winver; extern __attribute__ ((__dllimport__)) unsigned int _winmajor; extern __attribute__ ((__dllimport__)) unsigned int _winminor; extern __attribute__ ((__dllimport__)) int _fmode; If somebody is interested I could post the whole preprocessed file(214497 bites, prefered off list). As I understand _CRTIMP is defined in _mingw.h only for gcc compilers if __USE_CRTIMP is defined. Since __USE_CRTIMP is not defined I think that authors don't expect function pointers to differ with and without __dllimport. If -D__USE_CRTIMP is only solution we should convince authors of libxml, libxslt, xmlsec and etc. always to use __dllimport. But at moment I could not remember what was problem with __dllimport ( may be incompatibility with auto-import :-/ ). Roumen |
From: Roumen P. <bug...@ro...> - 2007-11-18 19:38:28
|
Roumen Petrov wrote: > If -D__USE_CRTIMP is only solution we should convince authors of libxml, libxslt, xmlsec and etc. always to use __dllimport. But at moment I could not remember what was problem with __dllimport ( may be incompatibility with auto-import :-/ ). > > I remember it. With __dllimport we could not cross-compile xmlsec: http://svn.gnome.org/viewvc/xmlsec/trunk/include/xmlsec/exports.h?revision=982&view=markup Roumen |
From: Tor L. <tm...@ik...> - 2007-11-18 22:20:33
|
I wrote > > Well, duh. Look in stdio.h: > > _CRTIMP int __cdecl fprintf (FILE*, const char*, ...); Roumen wrote: > So there is bug in mingw headers : Eek... you are right. I should have checked whether _CRTIMP actually normally expands to anything or not before posting my reply. But I naturally assumed that, as there as far as I know is no static C library one could use with gcc on windows (mingw) anyway, the whole point of these _CRTIMPs used in the w32api headers is that they expand to dllimport decorations. So yes, I think this is a bug, or at least misfeature. gcc or _mingw.h should in the future make sure that _CRTIMP always gets defined as the proper dllimport attribute. Or am I missing something? --tml |
From: Greg C. <gch...@sb...> - 2007-11-19 00:48:13
|
[_CRTIMP is empty by default] On 2007-11-18 22:20Z, Tor Lillqvist wrote: > > So yes, I think this is a bug, or at least misfeature. gcc or _mingw.h > should in the future make sure that _CRTIMP always gets defined as the > proper dllimport attribute. Or am I missing something? Here are some references I found: http://sources.redhat.com/cgi-bin/cvsweb.cgi/src/winsup/mingw/include/_mingw.h.diff?r1=1.16&r2=1.17&cvsroot=src http://cygwin.com/ml/cygwin-apps/2003-03/msg00784.html |