This is the mail archive of the cygwin mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

cygwin, libtool, dlpreopen, and .rdata


[cygwin list: I'm CC'ing this so that it goes into the archives, but it's pretty technical about the innards of libtool...]

With newer gcc's (cygwin version numbers 3.3.3-3, 3.4.1-1, but not 3.3.1-3), const variables are placed in an .rdata section. This causes problems when those variables contain references to OTHER vars that are imported from a dll -- because the runtime relocation machinery can't fixup the address, since the variable holding the address is const -- and is in .rdata!

Concrete example: the demo test program from libtool itself. When building helldl, libtool creates the following virtual lookup table:

helldl.exeS.c (important bits only):
*************************************
/* External symbol declarations for the compiler. */
extern int foo;
extern int hello;
extern int nothing;

/* The mapping between symbol names and symbols. */
const struct {
  const char *name;
  lt_ptr address;
}
lt_preloaded_symbols[] =
{
  {"libhello.a", (lt_ptr) 0},
  {"hello", (lt_ptr) &hello},
  {"foo", (lt_ptr) &foo},
  {"nothing", (lt_ptr) &nothing},
  {0, (lt_ptr) 0}
};
*************************************

Because lt_preloaded_symbols[] is an array of const structs, it is placed in .rdata. However, the "nothing" symbol is a DATA export from cyghello-2.dll -- so the runtime psuedo-reloc machinery needs to fixup the address stored in "lt_preloaded_symbols[3].address" to point to the actual, relocated memory location of the "nothing" variable.

But it can't, because .rdata is non-writable. However, this is a *runtime* error; the *link* succeeds. But when you run the app, you get a popup window declaring:

"The application failed to initialize properly (0xc0000005). Click on OK to terminate the application."

Note that
(1) the "nothing" relocation works fine for "normal" links; hell.exe works ok, and imports "nothing" correctly.


(2) the lt_preloaded_symbol[] object works fine, as long as it doesn't contain references to DATA items imported from DLL's: staticly linked helldl.exe works ok, and dynamically linked helldl.exe works IF "nothing" is expunged from the application code (manually removed from helldl.exeS.c, and from dlmain.c)

(3) even with newer compilers, if lt_preloaded_symbol[] is in .data (by changing its definition from "const struct" to "struct") then everything works fine. Note that you only need to do this in helldl.exeS.c; the application (dlmain.c, in this case) can still declare 'extern const struct ....').

*************************************
I see two solutions: a short term libtool-focused workaround, and a longer term general solution.


The short term workaround is to simply change lt_preloaded_symbol[]'s constness in the *.exeS.c file, so that it goes in the .data section. Mabye this could be done for cygwin/mingw only (but application code can remain unchanged, declaring 'extern const struct ...'). But that won't fix any OTHER problems out there which put the address of DLL DATA imports into const variables.

The long term solution is...er...hard. Somehow, ld/(gcc?) should be modified to detect that a dllreloc is being put into an .rdata, and move the entire enclosing variable into .data. This is difficult: lt_preloaded_symbol[3].address can be flagged easily, but how can the linker figure out that the whole lt_preloaded_symbol variable should be moved from .rdata to .data? And didn't the compiler put the symbol into .rdata in the first place -- so maybe gcc is the one who should detect this? But gcc doesn't know how the link will be performed: it doesn't know that "nothing" is a DATA import from a DLL, but "foo" is a function import from a DLL! (Worse, you might link to a STATIC library and not a DLL at all, so lt_preloaded_symbol could STAY in .rdata in that case.)

This might be one of those "doctor, it hurts when I do this/OK, don't do that" situations.

Note, I found this problem in libtool-1.5.x, but it exists in HEAD, too. The following patch is against HEAD...

--
Chuck


2004-09-21  Charles Wilson  <cwilson@spam.protected>

	* config/ltmain.in (func_generate_dlsyms): addresses
	in _preloaded_symbols[] cannot go into .rdata section
	if symbols are DATA imported from DLL, on windows,
	because runtime relocations must happen.
	* m4/libtool.m4 (_LT_LINKER_SHLIBS([TAGNAME])):
	build exports for symbols in .rdata sections

Index: config/ltmain.in
===================================================================
RCS file: /cvsroot/libtool/libtool/config/ltmain.in,v
retrieving revision 1.24
diff -u -r1.24 ltmain.in
--- config/ltmain.in	17 Sep 2004 17:12:17 -0000	1.24
+++ config/ltmain.in	22 Sep 2004 05:23:32 -0000
@@ -1064,7 +1064,26 @@
 	  $echo >> "$output_objdir/$my_dlsyms" "\
 
 /* The mapping between symbol names and symbols.  */
+"
+
+	    case $host in
+	    *cygwin* | *mingw* )
+	  $echo >> "$output_objdir/$my_dlsyms" "\
+/* DATA imports from DLLs on WIN32 can't be const, because
+   runtime relocations are performed -- see ld's documentation
+   on pseudo-relocs */
+struct {
+"
+	      ;;
+	    * )
+	  $echo >> "$output_objdir/$my_dlsyms" "\
 const struct {
+"
+	      ;;
+	    esac
+
+
+	  $echo >> "$output_objdir/$my_dlsyms" "\
    const char *name;
    void *address;
 }
Index: m4/libtool.m4
===================================================================
RCS file: /cvsroot/libtool/libtool/m4/libtool.m4,v
retrieving revision 1.106
diff -u -r1.106 libtool.m4
--- m4/libtool.m4	17 Sep 2004 13:54:05 -0000	1.106
+++ m4/libtool.m4	22 Sep 2004 05:23:37 -0000
@@ -3414,7 +3414,7 @@
     _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds"
   ;;
   cygwin* | mingw*)
-    _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGS]] /s/.* \([[^ ]]*\)/\1 DATA/;/^.* __nm__/s/^.* __nm__\([[^ ]]*\) [[^ ]]*/\1 DATA/;/^I /d;/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols'
+    _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]] /s/.* \([[^ ]]*\)/\1 DATA/;/^.* __nm__/s/^.* __nm__\([[^ ]]*\) [[^ ]]*/\1 DATA/;/^I /d;/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols'
   ;;
   *)
     _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
@@ -3530,7 +3530,7 @@
       _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
       _LT_TAGVAR(always_export_symbols, $1)=no
       _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
-      _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGS]] /s/.* \([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols'
+      _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]] /s/.* \([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols'
 
       if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
         _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib'

--
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple
Problem reports:       http://cygwin.com/problems.html
Documentation:         http://cygwin.com/docs.html
FAQ:                   http://cygwin.com/faq/

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]