LinuxQuestions.org
Visit Jeremy's Blog.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - Newbie
User Name
Password
Linux - Newbie This Linux forum is for members that are new to Linux.
Just starting out and have a question? If it is not in the man pages or the how-to's this is the place!

Notices


Reply
  Search this Thread
Old 03-21-2024, 07:31 PM   #1
DerPropeller
LQ Newbie
 
Registered: Mar 2024
Posts: 11

Rep: Reputation: 4
Question Tool like Dependency Walker for Linux that can show which funtion is imported from which .so file?


On Windows, tools like Dependency Walker, or its modern rewrite Dependencies, can be used to show which DLL files (shared libraries) a given EXE or DLL file depends on. These tools even show recursive dependencies. And, most important, these tools nicely show which exact function is imported from which exact DLL file. Is there any tool that can provide this information on Linux?

https://i.imgur.com/IsTmC1q.png

I know that a somewhat similar functionality is available on Linux via the ldd tool. Or, even better, lddtree from the pax-utils package, which shows recursive dependencies as a tree diagram. Those tools are nice, but they only show which .so files the given executable (or shared library) depends on. They do not show which exact functions are imported from each of those .so files! Meanwhile, objdump -T (or, alternatively, nm -D) can be used to show a list of all functions that the given executable (or shared library) imports from shared libraries, but it does not show from which exact .so file each function is imported.

Is there any tool available on Linux that shows both information combined

I searched on Google for a Linux tool that can show which exact function is imported from which exact .so file, but couldn't find anything. People either recommend using ldd or objdump -T (or, alternatively, nm -D). Unfortunately, as explained before, those tools only show half of the required information, but not the full picture. Since both information are available separately, it shouldn't be too hard to combine them...

Last edited by DerPropeller; 03-21-2024 at 07:43 PM.
 
Old 03-21-2024, 08:45 PM   #2
jmgibson1981
Senior Member
 
Registered: Jun 2015
Location: Tucson, AZ USA
Distribution: Debian
Posts: 1,141

Rep: Reputation: 392Reputation: 392Reputation: 392Reputation: 392
I haven't messed with either tool directly but if you cannot find something specific you can probably script something.
 
Old 03-21-2024, 08:54 PM   #3
DerPropeller
LQ Newbie
 
Registered: Mar 2024
Posts: 11

Original Poster
Rep: Reputation: 4
Quote:
Originally Posted by jmgibson1981 View Post
but if you cannot find something specific you can probably script something.
But how? ldd only outputs a list of the required .so files, with no information about the functions that are supposed to be imported from each file.

Meanwhile, objdump (or nm) only outputs a list of the required function names, with no information about the .so file from which each function is supposed to be imported.

So, there appears to be no way to match up the separate outputs

In theory it should be possible to parse the import table directly from the executable file, but I have no real idea how to do approach this...

Last edited by DerPropeller; 03-21-2024 at 09:04 PM.
 
Old 03-21-2024, 09:09 PM   #4
___
Member
 
Registered: Apr 2023
Posts: 139
Blog Entries: 1

Rep: Reputation: Disabled
Maybe like https://www.linuxquestions.org/quest...4/#post6490781
 
Old 03-21-2024, 09:16 PM   #5
DerPropeller
LQ Newbie
 
Registered: Mar 2024
Posts: 11

Original Poster
Rep: Reputation: 4
Quote:
Originally Posted by ___ View Post
I don't think so. If I understand it right, the script in question only shows the dependencies, in terms of .so files, differentiating between direct and indirect dependencies, just like lddtree from pax-utils.

It apparently does not show the functions that are to be imported from each .so file at all.

Again, what I'm looking for is a list of all the .so files that are required by an executable (or shared library), and for each of those .so files the list of functions that are supposed to be imported from the individual file.

TTBOMK, in the executable file, there is an "import table" that tells the loader which specific function shall be imported from which specific .so file. It must be possible to dump that table...

Last edited by DerPropeller; 03-21-2024 at 09:46 PM.
 
Old 03-22-2024, 03:59 PM   #6
teckk
LQ Guru
 
Registered: Oct 2004
Distribution: Arch
Posts: 5,138
Blog Entries: 6

Rep: Reputation: 1827Reputation: 1827Reputation: 1827Reputation: 1827Reputation: 1827Reputation: 1827Reputation: 1827Reputation: 1827Reputation: 1827Reputation: 1827Reputation: 1827
Best way to do that is, get the source code for the software that you are using.
Then look at the tree and see what it is doing.

What are you trying to accomplish? .so files are compiled code. You need to get the source tree and walk through it. Are you trying to reverse engineer an executable? That would be the real hard way to go.
 
Old 03-22-2024, 04:14 PM   #7
DerPropeller
LQ Newbie
 
Registered: Mar 2024
Posts: 11

Original Poster
Rep: Reputation: 4
Quote:
Originally Posted by teckk View Post
Best way to do that is, get the source code for the software that you are using.
Then look at the tree and see what it is doing.
No, looking at the source code does not help, I think

In the source code you'd see that a certain function gets called by the program. That function probably is declared in some header (.h) file. But that's it. You can not see at all, in the source code, which library actually provides the implementation of the function! It is the linker that figures out where each required function is located. If any required function can not be located by the linker, it will error out and the build process fails. Also, it is the linker that generates the "import table" of the executable file. At runtime, the loader reads the "import table" to know which specific function must be imported from which specific shared library (.so file).

Quote:
Originally Posted by teckk View Post
What are you trying to accomplish? .so files are compiled code. You need to get the source tree and walk through it. Are you trying to reverse engineer an executable? That would be the real hard way to go.
Given an existing executable file (or shared library), I want to check/analyze its dependencies.

On Windows, we can simply use Dependency Walker to see which DLL files a given executable file depends on, and also which specific functions are imported from each specific DLL file
https://i.imgur.com/IsTmC1q.png

On Linux, ldd shows which .so files a given executable file depends on, but it does not tell you which functions are imported!

Meanwhile, objdump or nm shows a list of all the functions that a given executable file imports, but it does not tell you from which specific .so file each of those functions is imported

Last edited by DerPropeller; 03-22-2024 at 05:08 PM.
 
Old 03-23-2024, 09:35 AM   #8
mysterious X
LQ Newbie
 
Registered: Mar 2024
Posts: 1

Rep: Reputation: 3
Quote:
Originally Posted by DerPropeller View Post
know that a somewhat similar functionality is available on Linux via the ldd tool. Or, even better, lddtree from the pax-utils package, which shows recursive dependencies as a tree diagram. Those tools are nice, but they only show which .so files the given executable (or shared library) depends on. They do not show which exact functions are imported from each of those .so files! Meanwhile, objdump -T (or, alternatively, nm -D) can be used to show a list of all functions that the given executable (or shared library) imports from shared libraries, but it does not show from which exact .so file each function is imported.

Is there any tool available on Linux that shows both information combined
Quote:
Originally Posted by DerPropeller View Post
TTBOMK, in the executable file, there is an "import table" that tells the loader which specific function shall be imported from which specific .so file. It must be possible to dump that table...
Not quite. Linux uses the ELF (Extensible Linking Format) format for executable files (and shared libraries).

In the ".dynamic" section of the ELF file, there is, amongst other things, one DT_NEEDED entry for each shared library that is needed. The DT_NEEDED entry just contains (a pointer to) the name of the shared library (*.so) file that needs to be loaded, but it does not indicate at all which symbols are to be "imported" from that shared library. To know which symbols need to be imported, we have to look at the ".dynsym" section.

The ".dynsym" section of the ELF file, contains the dynamic linking symbol table. Any symbols that are "undefined" (U) here will need to be resolved by the dynamic linker/loader. In other words, those "undefined" symbols are the ones that will be "imported" at runtime, e.g. from shared libraries. But the dynamic linking symbol table does not indicate at all which shared library contains a particular "undefined" symbol.

So, ldd pretty much dumps the DT_NEEDED entries from the ".dynamic" section. And nm -D dumps the ".dynsym" section; filter lines that start with U to get "imported" symbols.

Alternatively, readelf -d and readelf --dyn-syms provide the same information. Use readelf -a to dump all sections at once.

In conclusion, I think the information you are seeking can not be determined by just looking at the ELF file, because it is not specified from which shared library each "undefined" symbol will be resolved at runtime.

Last edited by mysterious X; 03-23-2024 at 11:20 AM.
 
3 members found this post helpful.
Old 03-23-2024, 02:25 PM   #9
DerPropeller
LQ Newbie
 
Registered: Mar 2024
Posts: 11

Original Poster
Rep: Reputation: 4
Now, that is very interesting information

After reading your post, I conducted a little test: I created a test program that calls foo() from libfoo.so and then calls bar() from libbar.so. As expected, ldd showed that my executable depends on both, libfoo.so and libbar.so. Then I changed my libfoo.so to additionally contain a "fake" function named bar(), which prints a different text than the original one. The executable file and the libbar.so were totally unchanged. Only the libfoo.so was re-built. Guess what, the program now suddenly calls the "fake" bar() from libfoo.so and does not use libbar.so at all! Interestingly, ldd still shows both library dependencies.

From this result I can only conclude that, indeed, Linux does not store which specific function shall be imported from which specific shared library, but only stores a "unspecific" list of shared libraries that need to be loaded. Apparently, the dynamic linker/loader searches all the loaded shared libraries and simply imports the required function from the first library where it is found – which is very different from Windows!

At least this explains why no tool shows the information that I was looking for. It just doesn't exist in Linux. Lesson learned

Last edited by DerPropeller; 03-24-2024 at 08:17 AM.
 
Old 03-24-2024, 10:13 AM   #10
DerPropeller
LQ Newbie
 
Registered: Mar 2024
Posts: 11

Original Poster
Rep: Reputation: 4
Small update:

After reading some more on the topic, I found that while Linux executables apparently do not store from which specific shared library a certain function shall be imported, we can still see from which specific shared library each function actually does get imported, at runtime, by setting the LD_DEBUG environment variable to "bindings":
Code:
$ LD_DEBUG=bindings ./a.out
      [...]
      4541:	binding file ./a.out [0] to /home/propeller/Desktop/libbar.so [0]: normal symbol `bar'
      4541:	binding file ./a.out [0] to /home/propeller/Desktop/libfoo.so [0]: normal symbol `foo'
      4541:	calling init: /home/propeller/Desktop/libfoo.so
      4541:	calling init: /home/propeller/Desktop/libbar.so
      [...]
Hello from foo!
Hello from bar!
Versus the modified libfoo.so file:
Code:
$ LD_DEBUG=bindings ./a.out
      [...]
      4722:	binding file ./a.out [0] to /home/propeller/Desktop/libfoo.so [0]: normal symbol `bar'
      4722:	binding file ./a.out [0] to /home/propeller/Desktop/libfoo.so [0]: normal symbol `foo'
      4722:	calling init: /home/propeller/Desktop/libfoo.so
Hello from foo!
Fake bar() funnction has been invoked !!!

Last edited by DerPropeller; 03-24-2024 at 11:04 AM.
 
2 members found this post helpful.
Old 03-28-2024, 03:15 PM   #11
DerPropeller
LQ Newbie
 
Registered: Mar 2024
Posts: 11

Original Poster
Rep: Reputation: 4
For what it's worth:
https://github.com/dEajL3kA/dependencies.py
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
LXer: RIP John Walker, software and hardware hacker extraordinaire LXer Syndicated Linux News 0 02-13-2024 05:30 PM
LXer: One on one with Shaun Walker, DotNetNuke LXer Syndicated Linux News 0 09-08-2010 06:41 PM
how to solve failed dependency when dependency exists dwcramer Linux - Newbie 2 08-24-2004 09:03 PM

LinuxQuestions.org > Forums > Linux Forums > Linux - Newbie

All times are GMT -5. The time now is 04:03 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration