Preloading import libraries with MSVC
Hi! As discussed earlier[1], there are problems with preloading import libraries when using Microsoft Visual C/C++. This series is a polished version of the previously posted rough cut. However, the first two patches are largely unrelated to the topic, but they help visualize what the meat in the third patch is all about. So, I guess they are related after all, which is why I posted them as a series. :-) This version will not create an @INIT@ symbol in the preloader table unless one is neaded, i.e. an actual data import item is needed to trigger the creation of the lt_syminit function and the fake @INIT@ symbol providing its address. Also, the "cost" in preopen.c is neglectable, as the loops from the proof of concept first draft are gone. With: .../configure \ CC="`pwd`/build-aux/compile cl -nologo" \ CFLAGS="-MD -Zi -EHsc" \ CXX="`pwd`/build-aux/compile cl -nologo" \ CXXFLAGS="-MD -Zi -EHsc" \ NM="dumpbin -symbols -headers" \ LD=link \ STRIP=: \ AR="`pwd`/build-aux/ar-lib lib" \ RANLIB=: \ F77=no FC=no GCJ=no from MSYS with Microsoft Visual C/C++ 2010 on $PATH, I get: ## - ## ## Test results. ## ## - ## 139 tests behaved as expected. 29 tests were skipped. So, all failures are fixed. The testsuite is also clean on Cygwin and MinGW (which makes me confident that the added special caseing doesn't mess up systems that don't make use of them). Is it unintrusive enough? Ok to push? (confession: I did a few last minute trivial changes just before posting which (drumroll) shouldn't affect things. Anyway, the testsuite is part way through with thouse changes and the patch has been somewhat exercised so it is looking good, but I will naturally post a followup if anything untoward surfaces) Cheers, Peter [1] http://lists.gnu.org/archive/html/libtool-patches/2012-10/msg00055.html
[PATCH 2/3] libtool: unify the global symbol transformations
Since it is safe for $lt_cv_sys_global_symbol_to_cdecl to match with a simple /^T .* .*$/ type expression, it is ok for the other transformations as well. At least if you require at least one $symcode at the start of the line, so that the just generated output doesn't match the next sed expression. * m4/libtool.m4 (_LT_CMD_GLOBAL_SYMBOLS): Unify the matching expressions in the sed programs that transform the extracted symbol lines. Signed-off-by: Peter Rosin --- m4/libtool.m4 | 14 +++--- 1 files changed, 7 insertions(+), 7 deletions(-) diff --git a/m4/libtool.m4 b/m4/libtool.m4 index 79a4222..e59e0fb 100644 --- a/m4/libtool.m4 +++ b/m4/libtool.m4 @@ -3654,19 +3654,19 @@ esac # so use this general approach. lt_cv_sys_global_symbol_to_cdecl="sed -n"\ " -e 's/^T .* \(.*\)$/extern int \1();/p'"\ -" -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" +" -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'" # Transform an extracted symbol line into symbol name and symbol address lt_cv_sys_global_symbol_to_c_name_address="sed -n"\ -" -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p'"\ -" -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'" +" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ +" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'" # Transform an extracted symbol line into symbol name with lib prefix and # symbol address. lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n"\ -" -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p'"\ -" -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'"\ -" -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"lib\2\", (void *) \&\2},/p'" +" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ +" -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\ +" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"lib\1\", (void *) \&\1},/p'" # Handle CRLF in mingw tool chain opt_cr= @@ -3771,7 +3771,7 @@ lt__PROGRAM__LTX_preloaded_symbols[[]] = { { "@PROGRAM@", (void *) 0 }, _LT_EOF - $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext + $SED "s/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext cat <<\_LT_EOF >> conftest.$ac_ext {0, (void *) 0} }; -- 1.7.9
[PATCH 1/3] libtool: break up long lines
* m4/libtool.m4 (_LT_CMD_GLOBAL_SYMBOLS): Break up long lines when assigning the sed scripts that transform the extracted symbol lines. Signed-off-by: Peter Rosin --- m4/libtool.m4 | 16 +--- 1 files changed, 13 insertions(+), 3 deletions(-) diff --git a/m4/libtool.m4 b/m4/libtool.m4 index 37f7d7c..79a4222 100644 --- a/m4/libtool.m4 +++ b/m4/libtool.m4 @@ -3652,11 +3652,21 @@ esac # Transform an extracted symbol line into a proper C declaration. # Some systems (esp. on ia64) link data and code symbols differently, # so use this general approach. -lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" +lt_cv_sys_global_symbol_to_cdecl="sed -n"\ +" -e 's/^T .* \(.*\)$/extern int \1();/p'"\ +" -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" # Transform an extracted symbol line into symbol name and symbol address -lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'" -lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"lib\2\", (void *) \&\2},/p'" +lt_cv_sys_global_symbol_to_c_name_address="sed -n"\ +" -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p'"\ +" -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'" + +# Transform an extracted symbol line into symbol name with lib prefix and +# symbol address. +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n"\ +" -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p'"\ +" -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'"\ +" -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"lib\2\", (void *) \&\2},/p'" # Handle CRLF in mingw tool chain opt_cr= -- 1.7.9
[PATCH 3/3] libtool: add @INIT@ to the preloader, for data imports on Windows
* m4/libtool.m4 (_LT_CMD_GLOBAL_SYMBOLS) [dumpbin]: Adjust lt_cv_sys_global_symbol_to_cdecl so that it declares imported data symbols as __declspec(dllimport). Adjust lt_cv_sys_global_symbol_to_c_name_address and lt_cv_sys_global_symbol_to_c_name_address_lib_prefix so that they fill in "(void*) 0" for imported data symbols. Add new lt_cv_sys_global_symbol_to_import which finds imported data symbols if non-empty and export this variable to the libtool script in the global_symbol_to_import variable. Adjust lt_cv_sys_global_symbol_pipe so that data imports can be located. * build-aux/ltmain.in (func_generate_dlsyms): When data imports are present, as indicated by global_symbol_to_import, generate a relocation function lt_syminit that fills in the addresses of data imports at runtime and point to the new function with a new virtual @INIT@ entry in the symbol list. * libltdl/loaders/preopen.c (add_symlist): Look for the virtual @INIT@ symbol (i.e. lt_syminit) and call it. (vm_sym): Step past the @INIT@ symbol, if present. * tests/demo.at (dlmain.c): Call the @INIT@ symbol, if present. * NEWS: Update. Signed-off-by: Peter Rosin --- NEWS |2 ++ build-aux/ltmain.in | 32 libltdl/loaders/preopen.c | 12 m4/libtool.m4 | 28 +--- tests/demo.at |2 ++ 5 files changed, 69 insertions(+), 7 deletions(-) diff --git a/NEWS b/NEWS index 081e82f..bb33202 100644 --- a/NEWS +++ b/NEWS @@ -60,6 +60,8 @@ NEWS - list of user-visible changes between releases of GNU Libtool in import libraries using the -headers option of dumpbin. Also fix a bug in the dumpbin wrapper which could lead to broken symbol listings in some corner cases. + - Use the improved Microsoft dumpbin support to mend preloading of +import libraries for Microsoft Visual C/C++. ** Important incompatible changes: diff --git a/build-aux/ltmain.in b/build-aux/ltmain.in index 6151ee9..9e790db 100644 --- a/build-aux/ltmain.in +++ b/build-aux/ltmain.in @@ -2798,6 +2798,11 @@ extern \"C\" { echo '/* NONE */' >> "$output_objdir/$my_dlsyms" fi + func_show_eval '$RM "${nlist}I"' + if test -n "$global_symbol_to_import"; then + eval "$global_symbol_to_import"' < "$nlist"S > "$nlist"I' + fi + echo >> "$output_objdir/$my_dlsyms" "\ /* The mapping between symbol names and symbols. */ @@ -2806,11 +2811,30 @@ typedef struct { void *address; } lt_dlsymlist; extern LT_DLSYM_CONST lt_dlsymlist -lt_${my_prefix}_LTX_preloaded_symbols[]; +lt_${my_prefix}_LTX_preloaded_symbols[];\ +" + + if test -s "$nlist"I; then + echo >> "$output_objdir/$my_dlsyms" "\ +static void lt_syminit(void) +{ + LT_DLSYM_CONST lt_dlsymlist *symbol = lt_${my_prefix}_LTX_preloaded_symbols; + for (; symbol->name; ++symbol) +{" + $SED 's/.*/ if (!strcmp (symbol->name, \"&\")) symbol->address = (void *) \&&;/' < "$nlist"I >> "$output_objdir/$my_dlsyms" + echo >> "$output_objdir/$my_dlsyms" "\ +} +}" + fi + echo >> "$output_objdir/$my_dlsyms" "\ LT_DLSYM_CONST lt_dlsymlist lt_${my_prefix}_LTX_preloaded_symbols[] = -{\ - { \"$my_originator\", (void *) 0 }," +{ {\"$my_originator\", (void *) 0}," + + if test -s "$nlist"I; then + echo >> "$output_objdir/$my_dlsyms" "\ + {\"@INIT@\", (void *) <_syminit}," + fi case $need_lib_prefix in no) @@ -2869,7 +2893,7 @@ static const void *lt_preloaded_setup() { func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?' # Clean up the generated files. - func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"' + func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T" "${nlist}I"' # Transform the symbol file into the correct name. symfileobj=$output_objdir/${my_outputname}S.$objext diff --git a/libltdl/loaders/preopen.c b/libltdl/loaders/preopen.c index 1670085..5c1bd55 100644 --- a/libltdl/loaders/preopen.c +++ b/libltdl/loaders/preopen.c @@ -210,6 +210,11 @@ vm_sym (lt_user_data LT__UNUSED loader_data, lt_module module, const char *name) { lt_dlsymlist*symbol = (lt_dlsymlist*) module; + if (symbol[1].name && STREQ (symbol[1].name, "@INIT@")) +{ + symbol++;/* Skip optional init entry. */ +} + symbol +=2; /* Skip header (originator then libname). */ while (symbol->name) @@ -273,6 +278,13 @@ add_symlist (const lt_dlsymlist *symlist) tmp->symlist = symlist; tmp->next = preloaded_symlists; preloaded_symlists = tmp; + + if (symlist[1].name && STREQ (symlist[1].name, "@INIT@")) + { + void (*init_symlist)(void); + *(void **)