ELF patching, binding issue - linux

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).

Related

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

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.

How can i make the busybox1.23.2 Compile success?

package: busybox
version: 1.23.2
when i make busybox , it produces unexpected results.
the crosschaintool i use is ARM/uClinux Toolchain arm-2010q1-189-arm- uclinuxeabi-i686-pc-linux-gnu,but i can't make the busybox,like this:
root#ubuntu:/busybox/busybox-1.23.2# make
SPLIT include/autoconf.h -> include/config/*
GEN include/bbconfigopts.h
HOSTCC applets/usage
applets/usage.c: In function ‘main’:
applets/usage.c:52:3: warning: ignoring return value of ‘write’, declared with attribute warn_unused_result [-Wunused-result]
write(STDOUT_FILENO, usage_array[i].usage, strlen(usage_array[i].usage) + 1);
^
GEN include/usage_compressed.h
HOSTCC applets/applet_tables
applets/applet_tables.c: In function ‘main’:
applets/applet_tables.c:161:4: warning: ignoring return value of ‘fgets’, declared with attribute warn_unused_result [-Wunused-result]
fgets(line_old, sizeof(line_old), fp);
^
GEN include/applet_tables.h
CC applets/applets.o
LD applets/built-in.o
HOSTCC applets/usage_pod
applets/usage_pod.c: In function ‘main’:
applets/usage_pod.c:74:3: warning: format not a string literal and no format arguments [-Wformat-security]
printf(usage_array[i].aname);
^
CC libbb/appletlib.o
CC libbb/vfork_daemon_rexec.o
AR libbb/lib.a
CC shell/hush.o
shell/hush.c: In function 'builtin_source':
shell/hush.c:8901: warning: 'sv.sv_g_malloced' may be used uninitialized in this function
shell/hush.c:8901: warning: 'sv.sv_g_argc' may be used uninitialized in this function
shell/hush.c:8901: warning: 'sv.sv_g_argv' may be used uninitialized in this function
shell/hush.c:8901: warning: 'sv.sv_argv0' may be used uninitialized in this function
AR shell/lib.a
LINK busybox_unstripped
Trying libraries: crypt m
Library crypt is not needed, excluding it
Library m is not needed, excluding it
Final link with: <none>
arm-uclinuxeabi-strip:busybox_unstripped: File format not recognized
Makefile:723: recipe for target 'busybox' failed
make: *** [busybox] Error 1
how should i do? is the busybox can't use the ARM/uClinux Toolchain? how should i do ?we'll really appreciate it if you can give us some advice and some pieces of guidance,thanks!
LINK busybox_unstripped Trying libraries: crypt m Library crypt
is not needed, excluding it Library m is not needed, excluding it
Final link with: arm-uclinuxeabi-strip:busybox_unstripped: File
format not recognized Makefile:723: recipe for target 'busybox' failed
make: *** [busybox] Error 1
As there is only a piece of the whole compiling log, some suggestions are:
1) Please check the compiling log from the beginning whether there are other important warnings or errors.
2) busybox_unstripped file is generated or not? Check the makefile dependencies to find out whether all dependencies files are successfully generated. From the log, some libraries are excluded so that you may have to check the busybox configuration file.
3) If busybox_unstripped file is generated, check the makefile about the link grammar of "Final link with:". For the cross-tool chain to link successfully, please make sure the link command is correct.
Good luck!

GHC RTS runtime errors when using hs_init with profiling of shared cabal library

I have a large C project which must be compiled with gcc. So I link the main executable with a file like this:
#include <HsFFI.h>
static void my_enter(void) __attribute__((constructor));
static void my_enter(void) {
static char *argv[] = { "Pointer.exe", 0 };
//static char *argv[] = { "Pointer.exe", "+RTS", "-N", "-p", "-s", "-h", "-i0.1", "-RTS", 0 };
static char **argv_ = argv;
static int argc = 1; // 8 for profiling
hs_init(&argc, &argv_);
//hs_init_with_rtsopts(&argc, &argv_);
}
static void my_exit(void) __attribute__((destructor));
static void my_exit(void) { hs_exit(); }
which works as expected - the GHC runtime system gets initialized and I'm able to use the FFI to call Haskell code from C.
I then attempt to enable profiling (mainly for stack traces with Debug.Trace) and code coverage (HPC) using the "+RTS", "-N", "-p", "-s", "-h", "-i0.1", "-RTS" flags on the line commented out above. However I get error messages about threading and profiling during initialization:
Pointer.exe: the flag -N requires the program to be built with -threaded
Pointer.exe: the flag -p requires the program to be built with -prof
Pointer.exe: Most RTS options are disabled. Use hs_init_with_rtsopts() to enable them.
Pointer.exe: newBoundTask: RTS is not initialised; call hs_init() first
I configured the cabal package with:
"--enable-library-profiling"
"--enable-executable-profiling"
"--enable-shared"
"--enable-tests"
"--enable-coverage"
which has properly given me stack traces and code coverage when running executables compiled as part of the cabal project.
If I try to use hs_init_with_rtsopts as recommended by the error message, I get a SIGSEGV during the GHC rts initialization:
Using host libthread_db library "/usr/lib/libthread_db.so.1".
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff6a2d0ca in strlen () from /usr/lib/libc.so.6
(gdb) bt
#0 0x00007ffff6a2d0ca in strlen () from /usr/lib/libc.so.6
#1 0x00007ffff798c5f6 in copyArg (
arg=0x657372615062696c <error: Cannot access memory at address 0x657372615062696c>) at rts/RtsFlags.c:1684
#2 0x00007ffff798c679 in copyArgv (argc=8, argv=0x555555554cee) at rts/RtsFlags.c:1696
#3 0x00007ffff798dbe2 in setFullProgArgv (argc=<optimized out>, argv=<optimized out>) at rts/RtsFlags.c:1780
#4 0x00007ffff798e773 in hs_init_ghc (argc=0x555555756090 <argc>, argv=0x5555557560a0 <argv>, rts_config=...)
at rts/RtsStartup.c:162
#5 0x00007ffff798e7cc in hs_init_with_rtsopts (argc=<optimized out>, argv=<optimized out>)
at rts/RtsStartup.c:121
#6 0x0000555555554c7d in __libc_csu_init ()
#7 0x00007ffff69cc59f in __libc_start_main () from /usr/lib/libc.so.6
#8 0x0000555555554b29 in _start ()
So how can I enable runtime profiling from a program compiled with gcc?
So the segfault was due to a typo which was not included in the question. Sneaky!
To enable threading and profiling and so on you must link your final program against the appropriate RTS flavor. This is one effect of GHC's -prof flag, and the only effect of its -threaded flag, and various other flags like -debug.
The RTS flavors are in different libraries with names of the form
libHSrts.a libHSrts-ghc7.8.4.so (vanilla)
libHSrts_debug.a libHSrts_debug-ghc7.8.4.so (debug)
libHSrts_thr.a libHSrts_thr-ghc7.8.4.so (threaded)
libHSrts_p.a - (profiling)
libHSrts_thr_p.a - (threaded+profiling)
libHSrts_l.a libHSrts_l-ghc7.8.4.so (eventlog)
...
On the left are static libraries; on the right are dynamic libraries, whose library names include the GHC version to make it easier for the runtime dynamic loader to find the correct version if you have multiple versions of GHC installed. You can see the full list for your GHC installation under "RTS ways" in ghc --info.
There are no dynamic profiling libraries installed by default but I think there is no fundamental problem with having them and you can configure the GHC build system to build them. (They are not especially useful now because ghci does not support profiling, though that is hopefully changing very soon.)

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.

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