wine can't load my custom build-in dll and report "call to unimplemented function" - wine

I can't login WINEHQ Bugzilla, so I ask here and this is the requirement:
We have a windows app which we have exe source code, and it used ATL. The dlls the exe depends require some special device, but mostly they have linux version. Now we need to port the windows app to linux.
My finally try: write a middle dll to wrap some lib which already is cross platform, the exe will call new middle dll, and I name the middle dll is "WINE custom build-in dll". CUSTOM means I compile this dll.so standalone by winemaker. Everything is fine until run it under wine64, the command line in linux shell:
wine64 portsome.exe
here is the output:
wine: Call from 0x7bc5eeec to unimplemented function wrapsome.dll.wrap_SOME_GetVersion, aborting
Backtrace:
=>0 0x000000007bc5eeec stub_entry_point+0x5c(dll=<is not available>, name=<is not available>, ret_addr=<is not available>) [/home/root0/src/wine/build/dlls/ntdll/../../../src/dlls/ntdll/loader.c:215] in ntdll (0x000000000023fbc0)
1 0x0000000140001022 in portsome (+0x1021) (0x000000000023fbc0)
2 0x00000001400012e2 in portsome (+0x12e1) (0x000000000023fd70)
3 0x000000007b47d02f start_process+0xbe(entry=0x140001418)
Modules:
Module Address Debug info Name (23 modules)
ELF 7b400000- 7b81a000 Dwarf kernel32<elf>
\-PE 7b420000- 7b81a000 \ kernel32
ELF 7bc00000- 7bd21000 Dwarf ntdll<elf>
\-PE 7bc20000- 7bd21000 \ ntdll
ELF 7c000000- 7c004000 Deferred <wine-loader>
PE 140000000- 140007000 Export portsome
ELF 7fbfe53b4000- 7fbfe56c6000 Deferred msvcr100<elf>
\-PE 7fbfe53e0000- 7fbfe56c6000 \ msvcr100
ELF 7fbfe5b48000- 7fbfe5f1d000 Deferred libhwaware.so
ELF 7fbfe5f1d000- 7fbfe6131000 Deferred wrapsome<elf>
\-PE 7fbfe5f20000- 7fbfe6131000 \ wrapsome
ELF 7fbfe66bc000- 7fbfe68ce000 Deferred libnss_files.so.2
ELF 7fbfe68ce000- 7fbfe6ada000 Deferred libnss_nis.so.2
ELF 7fbfe6ada000- 7fbfe6cf3000 Deferred libnsl.so.1
ELF 7fbfe6cf3000- 7fbfe6efc000 Deferred libnss_compat.so.2
ELF 7fbfe70fc000- 7fbfe7312000 Deferred libgcc_s.so.1
ELF 7fbfe7312000- 7fbfe761b000 Deferred libm.so.6
ELF 7fbfe761e000- 7fbfe7822000 Deferred libdl.so.2
ELF 7fbfe7822000- 7fbfe7bec000 Deferred libc.so.6
ELF 7fbfe7bed000- 7fbfe7e0a000 Deferred libpthread.so.0
ELF 7fbfe7e22000- 7fbfe81c8000 Dwarf libwine.so.1
ELF 7fbfe81ca000- 7fbfe83f2000 Deferred ld-linux-x86-64.so.2
ELF 7ffd8bbe1000- 7ffd8bbe2000 Deferred [vdso].so
Here is my question:
how do I compile a wine custom build-in dll to make windows native app can call its function when running, is it need to generate a fake dll by winebuilder?
Detail steps I working for port windows app to linux:
1. find the special dll which need contact with hardware directly, like CUDA, dongle access.
2. make a wrap dll, change the exe code to call this wrap dll function, and the wrap dll then call hardware aware dll.
3. create "wrapsome.spec" file with https://wiki.winehq.org/Winelib_User%27s_Guide#The_Spec_file requirements.
4. copy the wrap code to Ubuntu 16.04, switch to wrap code source directory and run below command in shell:
winemaker --dll --nosource-fix -DWRAPSOME_EXPORTS -I../deps/hdaware -L../deps/hdaware -lhdaware .
then I got the "Makefile" file and I append -fPIC to LDFLAGS.
5. continue to run "make", yea, I got the wrapsome.dll.so, and I copy it to wine build-in dlls directory.
6. finally I failed to run "wine64 portsome.exe", the question is mentioned above.
wine report "unimplemented function wrapsome.dll.wrap_SOME_GetVersion", I even confirmed with nm wrapsome.dll.so, and here is its output:
0000000000213291 B __bss_start
0000000000213298 b call_fini.9485
0000000000213294 b completed.7585
w __cxa_finalize
00000000000118b0 t deregister_tm_clones
0000000000011a20 t DisableThreadLibraryCalls
0000000000011bf0 t DllMain
0000000000011940 t __do_global_dtors_aux
0000000000212de8 t __do_global_dtors_aux_fini_array_entry
0000000000213040 d __dso_handle
0000000000212df8 d _DYNAMIC
0000000000213291 D _edata
00000000002132a0 B _end
0000000000011c88 t _fini
0000000000011980 t frame_dummy
0000000000212de0 t __frame_dummy_init_array_entry
0000000000011ec8 r __FRAME_END__
0000000000213000 d _GLOBAL_OFFSET_TABLE_
w __gmon_start__
0000000000011cb8 r __GNU_EH_FRAME_HDR
0000000000000810 t _init
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
0000000000212df0 d __JCR_END__
0000000000212df0 d __JCR_LIST__
w _Jv_RegisterClasses
00000000000118f0 t register_tm_clones
U SOME_GetVersion
U SOME_InitAwareSDK
U SOME_UninitAwareSDK
0000000000213298 d __TMC_END__
U __wine_dll_register##WINE_1.0
U __wine_main_argc##WINE_1.0
U __wine_main_argv##WINE_1.0
0000000000011ad0 t __wine_spec_dll_entry
0000000000011c94 r __wine_spec_file_name
0000000000011a20 t __wine_spec_import_thunks
0000000000011c20 t __wine_spec_init
0000000000011c40 t __wine_spec_init_ctor
000000000021329c b __wine_spec_init_state
0000000000213048 d __wine_spec_nt_header
000000000000082a t __wine_spec_pe_header
00000000000119b0 t __wine_spec_relay_entry_points
0000000000011ab9 T wrap_SOME_GetVersion
0000000000011a3c T wrap_SOME_InitAwareSDK
0000000000011a53 T wrap_SOME_UninitAwareSDK
0000000000011a26 T _Z7DllMainP11HINSTANCE__jPv
Notice: I have dismissed some word with common ones as it is not good to show to the public.
I even read the wine source code in github https://github.com/wine-mirror/wine/blob/fdac39f697e049ead215b164bfe6953269ffa7be/dlls/ntdll/loader.c#L660, it seems
exports = RtlImageDirectoryEntryToData( imp_mod, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size );
can't export the warpsome.dll.so file symbol table which I compile by winemaker+winegcc tool chain.

I changed the wrapsome.spec file to this content:
# stdcall wrap_SOME_InitAwareSDK(ptr) wrap_SOME_InitAwareSDK
# stdcall wrap_SOME_UninitAwareSDK(ptr) wrap_SOME_UninitAwareSDK
# stdcall wrap_SOME_GetVersion() wrap_SOME_GetVersion
and make again, then cp to wine dlls directory, it works! And I known there is no need to change the exe link to warp dll in windows, just build a dll.so with extract the same export name which need by exe, it should works too. I will try it later.

Related

ELF patching, binding issue

Currently I am trying to patch an ELF executable object file.
I am testing my utility, using the primitive hello-world application. Everything seems to remain fine after patching, but when it comes to execution, the application segfaults.
When patching, I also insert a new shared object dependency. To understand what goes wrong, in parallel I managed to link the shared object into my test application. So that I receive the well-formed g++-made result, which I can compare to my algorithm result (more or less).
The issue I ran into is that during execution my modified hello-world app cannot call std::cout routine, because the std::ostream::sentry::sentry(std::ostream&) ctor fails; I managed to dive into the problem, using the gdb. When debugging and comparing to the well-formed result, I managed to figure out what is wrong. It appears that the the symbol std::cout / _ZSt4cout relocation binding is sort of misused. Despite both results have exactly the same DT_NEEDED entries in the .dynamic section (in the same order as well), and despite they both have an import symbol entry for std::cout in the .dynsym section, with accordingly modified .gnu.version and .gnu.hash contents, - despite all these, - the std::ios_base::Init::Init() function, when resolving the std::cout object, operates differently for the both results. For the well-formed result - over the proper entry in the .bss section of the hello-world application, while for the my algo result - over the std::cout entry (as the readelf util verifies) in the .got section of the libstdc++ shared library.
Last, but not least, when executing with the LD_DEBUG=bindings option, I receive the following output for the well-formed result (added std::cin / _ZSt3cin for contrast):
...
10067: binding file /usr/lib/x86_64-linux-gnu/libstdc++.so.6 [0] to ./hello_world_wellformed [0]: normal symbol `_ZSt4cout' [GLIBCXX_3.4]
10067: binding file /home/user/Documents/Test/libmyexternal.so [0] to ./hello_world_wellformed [0]: normal symbol `_ZSt4cout' [GLIBCXX_3.4]
10067: binding file ./hello_world_wellformed [0] to /usr/lib/x86_64-linux-gnu/libstdc++.so.6 [0]: normal symbol `_ZSt4cout' [GLIBCXX_3.4]
...
10067: binding file /usr/lib/x86_64-linux-gnu/libstdc++.so.6 [0] to ./hello_world_wellformed [0]: normal symbol `_ZSt3cin' [GLIBCXX_3.4]
10067: binding file ./hello_world_wellformed [0] to /usr/lib/x86_64-linux-gnu/libstdc++.so.6 [0]: normal symbol `_ZSt3cin' [GLIBCXX_3.4]
...
While for the algo-modified result:
...
10027: binding file /usr/lib/x86_64-linux-gnu/libstdc++.so.6 [0] to /usr/lib/x86_64-linux-gnu/libstdc++.so.6 [0]: normal symbol `_ZSt4cout' [GLIBCXX_3.4]
10027: binding file /home/user/Documents/Test/libmyexternal.so [0] to /usr/lib/x86_64-linux-gnu/libstdc++.so.6 [0]: normal symbol `_ZSt4cout' [GLIBCXX_3.4]
10027: binding file ./hello_world_algotest [0] to /usr/lib/x86_64-linux-gnu/libstdc++.so.6 [0]: normal symbol `_ZSt4cout' [GLIBCXX_3.4]
...
10027: binding file /usr/lib/x86_64-linux-gnu/libstdc++.so.6 [0] to /usr/lib/x86_64-linux-gnu/libstdc++.so.6 [0]: normal symbol `_ZSt3cin' [GLIBCXX_3.4]
10027: binding file ./hello_world_algotest [0] to /usr/lib/x86_64-linux-gnu/libstdc++.so.6 [0]: normal symbol `_ZSt3cin' [GLIBCXX_3.4]
...
How can I fix the issue or what might be the reason for such behavior? How do glibc and libstdc++ deal with such situations and how come the algo-modified app's std::cout entry became 'invisible' for the libraries (despite the readelf, objdump, and nm utils show that everything is correct)?
Naturally, both glibc and libstdc++ versions and the same, both hello-world apps compiled under the same g++ version. .bss section resides properly, all sections and segments have proper flags set.
Digging inside the glibc source, using the gdb (and lost a couple days), I reached the _dl_lookup_symbol_x and do_lookup_x functions, defined in dl-lookup.c; arguments passed showed me the difference (between the well-formed and algo-derived results) was in hashes. Well, I forgot that the GNU hash table has been modified incorrectly. Once you add an import function, you have to change the GNU hash table indexes (luckily, you do not have to rebuild the whole hash table, just update indexes; do not forget that, when adding an import function, you still have to change the .dynsym and GNU version table contents) (one really cool explanation of the whole GNU hashing concept can be seen here: https://flapenguin.me/elf-dt-gnu-hash). By the way, I found and fixed a bug with the obsolete .bss section number (happened because of sections rebuilding).

dlopen failed: cannot locate symbol "signal"

I am developing an Android app using NDK.
I have built OpenSSL as static libraries, libcrypto.a and libssl.a, which I linked with my custom C code.
When I try to load the library at runtime I get:
dlopen failed: cannot locate symbol "signal"...
Any idea how to fix this?
Thanks!
Update:
This comes from libcrypto:
libcrypto.a:
00000000 *UND* 00000000 signal
In my .so I see:
libtest.so:
NEEDED libc.so
...
00040240 <signal#plt>:
40240: e28fc601 add ip, pc, #1048576 ; 0x100000
40244: e28cca80 add ip, ip, #128, 20 ; 0x80000
40248: e5bcfd64 ldr pc, [ip, #3428]! ; 0xd64
So why is it complaining about "signal"?

clang memory sanitizer; how to make it print source line numbers

I'm compiling my program with clang++ -fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer -g -O0 and when I run it, the output is:
matiu#matiu-laptop:~/projects/json++11/build$ ./tests
.......==10534== WARNING: MemorySanitizer: use-of-uninitialized-value
#0 0x7fe7602d4a51 (/home/matiu/projects/json++11/build/tests+0x106a51)
#1 0x7fe7602dfca6 (/home/matiu/projects/json++11/build/tests+0x111ca6)
...
#31 0x7fe75edbaec4 (/lib/x86_64-linux-gnu/libc.so.6+0x21ec4)
#32 0x7fe7602808dc (/home/matiu/projects/json++11/build/tests+0xb28dc)
Uninitialized value was created by a heap allocation
#0 0x7fe76026e7b3 (/home/matiu/projects/json++11/build/tests+0xa07b3)
#1 0x7fe7602ee7da (/home/matiu/projects/json++11/build/tests+0x1207da)
...
#18 0x7fe7602c1c4c (/home/matiu/projects/json++11/build/tests+0xf3c4c)
#19 0x7fe7602873fa (/home/matiu/projects/json++11/build/tests+0xb93fa)
SUMMARY: MemorySanitizer: use-of-uninitialized-value ??:0 ??
Exiting
How can I make it show line numbers like in the beautiful examples: http://clang.llvm.org/docs/MemorySanitizer.html
I'm suspecting it might not be possible, due to my pragram being one giant nested bunch of lambdas: https://github.com/matiu2/json--11/blob/master/tests.cpp
With the address sanitizer I noticed that I needed to have these environment variables defined:
ASAN_OPTIONS=symbolize=1 (only needed when compiled with GCC > 4.8) and
ASAN_SYMBOLIZER_PATH=$(which llvm-symbolizer) I think the symbolizer is what you're looking for. It transforms symbols to file names with line numbers and columns.
On the memory sanitizer project website it reads:
Symbolization
Set MSAN_SYMBOLIZER_PATH environment variable to the path to
llvm-symbolizer binary (normally built with LLVM). MemorySanitizer
will use it to symbolize reports on-the-fly.
So you need MSAN_SYMBOLIZER_PATH to be set analogous to ASAN_SYMBOLIZER_PATH.

shared library loading

My app shows that that dynamic linking is ok.
[root#centos udpfltr_fork]# ldd udpfltr
linux-gate.so.1 => (0x00dbe000)
libnfnetlink.so.0 => /usr/lib/libnfnetlink.so.0 (0x005de000)
libnetfilter_queue.so.1 => /usr/lib/libnetfilter_queue.so.1 (0x004a5000)
libnglogc.so.0 => /usr/lib/libnglogc.so.0 (0x00a51000)
libc.so.6 => /lib/libc.so.6 (0x001b9000)
/lib/ld-linux.so.2 (0x0019a000)
but when its invoked it stops with following error:
./udpfltr: error while loading shared libraries: libnglogc.so.0: cannot open shared object file: No such file or directory
I'm clueless about what's actually happening. I've tried with setting $LD_LIBRARY_PATH, reloading ldcache by ldconfig etc.
This might be the reason:-
1)check $LD_LIBRARY_PATH - this path may not have location where libglogc.so.0 resides
unset $LD_LIBRARY_PATH and then set this to .so location

Can I add a library refence to existing Shared Object?

I have a system "fsimage.so" that requires mkdirp, which just happens to live in libgen.so. But fsimage.so does not know this. For example:
# ldd /usr/lib/python2.4/vendor-packages/fsimage.so
libfsimage.so.1.0 => /usr/lib/libfsimage.so.1.0
libxml2.so.2 => /lib/libxml2.so.2
libgcc_s.so.1 => /usr/sfw/lib/libgcc_s.so.1
libpthread.so.1 => /lib/libpthread.so.1
libz.so.1 => /lib/libz.so.1
libm.so.2 => /lib/libm.so.2
libsocket.so.1 => /lib/libsocket.so.1
libnsl.so.1 => /lib/libnsl.so.1
libc.so.1 => /lib/libc.so.1
libmp.so.2 => /lib/libmp.so.2
libmd.so.1 => /lib/libmd.so.1
# ./test
Traceback (most recent call last):
File "./test", line 26, in ?
import fsimage
ImportError: ld.so.1: isapython2.4: fatal: relocation error: file /usr/lib/python2.4/vendor-packages/fsimage.so: symbol mkdirp: referenced symbol not found
# LD_PRELOAD=/usr/lib/libgen.so ./test
Usage: ./test
Naturally, if I had the sources etc, I could simply link it again, and add "-lgen", and it will add libgen.so as a dependency.
But as an exercise in hackery, say I do not have any sources, and simply wanted to add that fsimage.so needs to also load libgen.so. Using elfedit/objcopy etc, is this not possible? I don't suppose I can use "ld" to use .so as input, and write a new .so with extra library?
# elfdump /usr/lib/python2.4/vendor-packages/fsimage.so|grep NEEDED
[0] NEEDED 0x5187 libfsimage.so.1.0
[1] NEEDED 0x5152 libxml2.so.2
[2] NEEDED 0x5171 libgcc_s.so.1
First attempt at stackoverflow, go easy on me :)
Thank you "Employed Russian", you gave me the information needed to search deeper. Solaris already ships with "elfedit", so if others wants to know, these are the instructions
# elfedit libfsimage.so.1.0.0 libfsimage.so.1.0.0-new
> dyn:value DT_NEEDED
index tag value
[0] NEEDED 0x4f81 libpthread.so.1
[1] NEEDED 0x4fac libxml2.so.2
[2] NEEDED 0x4fc2 libgcc_s.so.1
> dyn:value -add -s DT_NEEDED libscf.so
index tag value
[35] NEEDED 0x500d libscf.so
> dyn:value DT_NEEDED
index tag value
[0] NEEDED 0x4f81 libpthread.so.1
[1] NEEDED 0x4fac libxml2.so.2
[2] NEEDED 0x4fc2 libgcc_s.so.1
[35] NEEDED 0x500d libscf.so
> :write
> :quit
# ldd libfsimage.so.1.0.0-new
libpthread.so.1 => /lib/libpthread.so.1
libxml2.so.2 => /lib/libxml2.so.2
libgcc_s.so.1 => /usr/sfw/lib/libgcc_s.so.1
libscf.so => /lib/libscf.so
libz.so.1 => /lib/libz.so.1
libm.so.2 => /lib/libm.so.2
libsocket.so.1 => /lib/libsocket.so.1
libnsl.so.1 => /lib/libnsl.so.1
libc.so.1 => /lib/libc.so.1
libuutil.so.1 => /lib/libuutil.so.1
libgen.so.1 => /lib/libgen.so.1
libnvpair.so.1 => /lib/libnvpair.so.1
libsmbios.so.1 => /usr/lib/libsmbios.so.1
libmp.so.2 => /lib/libmp.so.2
libmd.so.1 => /lib/libmd.so.1
Not easily.
Most UNIX systems (AIX is a notable exception) consider *.so a "final" link product, and it is not suitable as an input for any further link.
To add a new DT_NEEDED tag to the dynamic section of fsimage.so, you would need to rewrite its .dynamic section. Removing an entry from .dynamic is relatively easy -- you can just "slide" the other entries up, and replace the last entry with DT_NULL.
On the other hand, adding a new entry requires that you append a whole new .dynamic section to the file, and then update all pointers (offsets) within fsimage.so to point to the new section. This requires "deep" understanding of the ELF format.
There are existing tools to do this, e.g. rpath but I've had mixed success with it.
You can use PatchELF. Release 0.9 is out since 29 Feb 2016 and lets you:
Change the dynamic loader ("ELF interpreter") of executables
Change the RPATH of executables and libraries
Shrink the RPATH of executables and libraries
Remove declared dependencies on dynamic libraries (DT_NEEDED
entries)
Add a declared dependency on a dynamic library (DT_NEEDED)
Replace a declared dependency on a dynamic library with another one (DT_NEEDED)
Change SONAME of a dynamic library
In your case:
$ patchelf --add-needed /usr/lib/libgen.so /usr/lib/python2.4/vendor-packages/fsimage.so

Resources