I happened to need to work out which symbols were exported by which library from a flat list of exported shared library symbols. There were just enough symbols (20 or so) in the list that I wasn't going to manually cross-reference each one.
I found that nm -A -D -f sysv <library-name>
seemed to produce useful output - I could search for lines containing FUNC
that also listed an address in the second column. So I ran this command on everything in /usr/lib
, redirecting it to a file.
To my surprise, the sanity-checking in the script I made to parse the file reported that there were duplicate symbols! Upon investigation and found that libraries appeared to be exporting duplicate symbols?!?
I verified this using some shell scripting, and I was able to turn the commands I used into this (technically) one-liner:
readlink -f /lib/* /usr/lib/* \
| grep -F .so. | sort | uniq \
| while read x; do nm -A -D -f sysv $x; done \
| grep FUNC | cut -d'|' -f1 | sort -g | uniq -c | sort -g \
| sed -n '/^ \+1/!{s/^ \+[0-9]\+ \+//p}' | sed 's/ //g' \
| tr '\n' '\v' \
| sed ':1;s/\([^ ]\+\):\([^\v$]\+\)\v\1:/\1:\2|/g;t1' \
| tr '\v' '\n' \
| while IFS=: read -a x; do \
nm -A -D -f sysv "${x[0]}" | grep ":\\(${x[1]//|/\\|}\\).*FUNC"; \
done
The command above will make your disk seek for a short period of time. You can break it into chunks that redirect to temporary files if you want. Also the output will be very wide (~150 cols).
I initially ran the original script on a Debian Squeeze chroot I was working within, but out of curiosity I ran the above on my host system to find out if the chroot was somehow not sane.
Well... the chroot reported just over 90 duplicates, but my host (Arch) system apparently has about 267.
The command works by grepping nm
's output so the results are a bit noisy, but it looks like this:
/usr/lib/libasound.so.2.0.0:snd_pcm_hw_params_get_access|00043700| T | FUNC|00000037| |.text
/usr/lib/libasound.so.2.0.0:snd_pcm_hw_params_get_access|000436c0| T | FUNC|0000003c| |.text
/usr/lib/libasound.so.2.0.0:snd_pcm_hw_params_get_access_mask|000458f0| T | FUNC|00000058| |.text
/usr/lib/libasound.so.2.0.0:snd_pcm_hw_params_get_buffer_size|000432a0| T | FUNC|00000037| |.text
/usr/lib/libasound.so.2.0.0:snd_pcm_hw_params_get_buffer_size|00043260| T | FUNC|0000003c| |.text
/usr/lib/libasound.so.2.0.0:snd_pcm_hw_params_get_buffer_size_max|00044ff0| T | FUNC|0000003c| |.text
/usr/lib/libasound.so.2.0.0:snd_pcm_hw_params_get_buffer_size_max|00045030| T | FUNC|00000037| |.text
/usr/lib/libasound.so.2.0.0:snd_pcm_hw_params_get_buffer_size_min|000453c0| T | FUNC|00000037| |.text
/usr/lib/libasound.so.2.0.0:snd_pcm_hw_params_get_buffer_size_min|00045380| T | FUNC|0000003c| |.text
Notice how there are two of each symbol. The address is different, yes, but... I thought dynamic linking worked by symbol name, and that was it. My confusion is compounded by the fact that (if you scroll rightwards in the listing above) the symbols are all of type FUNC
and from the .text
section.
I'm posting this to learn what interesting magic is going on under the hood here. (Since my system is working...)
If anyone has any good ideas where I could dump about 600 lines of text - Pastebin doesn't seem in vogue anymore, and I don't use GitHub - I'd be happy to share the full output.