* 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 <p...@lysator.liu.se> --- 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 **)(&init_symlist) = symlist[1].address; + (*init_symlist)(); + } } else { diff --git a/m4/libtool.m4 b/m4/libtool.m4 index e59e0fb..3cf14e7 100644 --- a/m4/libtool.m4 +++ b/m4/libtool.m4 @@ -3649,21 +3649,41 @@ case `$NM -V 2>&1` in symcode='[[ABCDGIRSTW]]' ;; esac +if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Gets list of data symbols to import. + lt_cv_sys_global_symbol_to_import="sed -n -e 's/^I .* \(.*\)$/\1/p'" + # Adjust the below global symbol transforms to fixup imported variables. + lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'" + lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'" + lt_c_name_lib_hook="\ + -e 's/^I .* \(lib.*\)$/ {\"\1\", (void *) 0},/p'\ + -e 's/^I .* \(.*\)$/ {\"lib\1\", (void *) 0},/p'" +else + # Disable hooks by default. + lt_cv_sys_global_symbol_to_import= + lt_cdecl_hook= + lt_c_name_hook= + lt_c_name_lib_hook= +fi + # 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"\ +$lt_cdecl_hook\ " -e 's/^T .* \(.*\)$/extern int \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"\ +$lt_c_name_hook\ " -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"\ +$lt_c_name_lib_hook\ " -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ " -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/ {\"lib\1\", (void *) \&\1},/p'" @@ -3684,8 +3704,8 @@ for ac_symprfx in "" "_"; do # Write the raw and C identifiers. if test "$lt_cv_nm_interface" = "MS dumpbin"; then - # Fake it for dumpbin and say T for any non-static function - # and D for any global variable. + # Fake it for dumpbin and say T for any non-static function, + # D for any global variable and I for any imported variable. # Also find C++ and __fastcall symbols from MSVC++, # which start with @ or ?. lt_cv_sys_global_symbol_pipe="$AWK ['"\ @@ -3694,7 +3714,7 @@ for ac_symprfx in "" "_"; do " /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ " /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\ " /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\ -" /^ *Type *: data/{print \"D\",si,substr(si,length(prfx))};"\ +" /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ @@ -3841,6 +3861,8 @@ _LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1], [Take the output of nm and produce a listing of raw symbols and C names]) _LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1], [Transform the output of nm in a proper C declaration]) +_LT_DECL([global_symbol_to_import], [lt_cv_sys_global_symbol_to_import], [1], + [Transform the output of nm into a list of symbols to manually relocate]) _LT_DECL([global_symbol_to_c_name_address], [lt_cv_sys_global_symbol_to_c_name_address], [1], [Transform the output of nm in a C name address pair]) diff --git a/tests/demo.at b/tests/demo.at index c86e1e9..eb8a97f 100644 --- a/tests/demo.at +++ b/tests/demo.at @@ -295,6 +295,8 @@ int main () if (s->address) { const char *name = s->name; printf ("found symbol: %s\n", name); + if (STREQ ("@INIT@", name)) + ((void(*)())s->address)(); if (STREQ ("hello", name)) phello = (int(*)())s->address; else if (STREQ ("foo", name)) -- 1.7.9