Shared libaray : Why muliple versions of GLIBC_ in a single binary - c

Context: I am currently debugging an issue where the binaries generated in one machine (liked with lpthread) causes pthread related bugs when tried in another machine.
libtest.so is a shared library which seems to contain multiple versions of GLIBC_ . Is that expected ?. How it happens ? It was linked using "-shared -lpthread -fPIC -soname=xxxx" option.
$objdump -T libtest.so | grep GLIBC_
...
00000000 DF *UND* 0000008d GLIBC_2.1 popen
...
00000000 DF *UND* 0000002c GLIBC_2.0 syslog
00000000 DF *UND* 00000020 GLIBC_2.0 pthread_exit
00000000 DF *UND* 0000009f GLIBC_2.0 __xstat
00000000 DF *UND* 000000bb GLIBC_2.3.2 pthread_cond_signal
00000000 DF *UND* 000000c9 GLIBC_2.0 vsprintf
...

Each symbol has its own history.
When a symbol hasn't be modified (signature, behavor) it keeps the default version eg. GLIBC_2.0.
Symbols modified are attributed the current version of the library at that time, for example popen() behavor was modified in GLIBC_2.1, pthread_cond_signal() was modified in GLIBC_2.3.2.
Your program get linked with the latest version of each symbol. The version is recorded, and if you run your program against a newer GLIBC, your program will not use newer symbol version, but the one available at link time: this ensure to have the expected behavor at runtime: no surprise.

That is because those methods exist in different .so's. glibc is a collection of .so's. I believe pthread_exit is in libpthread.so and popen is in libc.so

Related

objdump format for a function written in C vs asm [duplicate]

When assembling an object using nasm, I'm finding that all labels are included as symbols in the resultant .o file, as well as the final binary.
This makes sense for function entry points that I've declared GLOBAL, and for section start parts (e.g., for the .text section), but it seems odd that labels simply used as loop entry points and such all near to appear in the output file. In addition to leaking internal implementation details, it wastes space in the symbol table.
For example, given this short assembly program:
GLOBAL _start
_start:
xor eax, eax
normal_label:
xor eax, eax
.local_label:
xor eax, eax
xor edi, edi
mov eax, 231 ; exit(0)
syscall
... built using:
nasm -f elf64 label-test.s
ld label-test.o -o label-test
Results in l (i.e., local) symbols in both the object file and linked executable:
objdump --syms label-test.o
label-test.o: file format elf64-x86-64
SYMBOL TABLE:
0000000000000000 l df *ABS* 0000000000000000 label-test.s
0000000000000000 l d .text 0000000000000000 .text
0000000000000002 l .text 0000000000000000 normal_label
0000000000000004 l .text 0000000000000000 normal_label.local_label
0000000000000000 g .text 0000000000000000 _start
Note that both normal_label and the local label local_label ended up in the symbol table. All of them end up in the symbol table of the executable also.
I don't want to emit these symbols to the final executable. Can I tell nasm not to include them? There are some options I could pass to ld, such as --strip-all, which will remove those symbols, but also every other symbol in the executable. That makes it quite the cudgel: it eliminates the symbols I really want to keep for readable stack traces, debugging, etc.
FWIW, as mentioned by Peter Cordes, yasm doesn't have exactly the same issue. With an elf64 .o file built in exactly the same way as above (but with yasm substituted for nasm, we get:
objdump --syms label-test-yasm.o
label-test-yasm.o: file format elf64-x86-64
SYMBOL TABLE:
0000000000000000 l df *ABS* 0000000000000000 label-test.s
0000000000000004 l .text 0000000000000000
0000000000000002 l .text 0000000000000000
0000000000000000 l d .text 0000000000000000 .text
0000000000000000 g .text 0000000000000000 _start
The global _start label is still included, but the other two labels aren't named - they are still there though, they are the unnamed symbols at offset 4 and 2 (lines 2 and 3 in the list above). This is confirmed by adding more labels - more unnammed symbols are produced.
As far as I can tell, it's just a limitation in nasm. See for example this forum post where the poster has approximately the same issue (although 32-bit rather than 64-bit ELF), and no solution is provided other than using a stripping tool.
In my case, it seems stripping the object file like:
strip --discard-all label-test.o
should do the trick. Despite the name of the --discard-all option, it only strips local symbols and leaves global symbols alone. Here's the symbol table before stripping the file:
SYMBOL TABLE:
0000000000000000 l df *ABS* 0000000000000000 label-test.s
0000000000000000 l d .text 0000000000000000 .text
0000000000000002 l .text 0000000000000000 normal_label
0000000000000004 l .text 0000000000000000 normal_label.local_label
0000000000000000 g .text 0000000000000000 _start
and after:
SYMBOL TABLE:
0000000000000000 l df *ABS* 0000000000000000 label-test.s
0000000000000000 l d .text 0000000000000000 .text
0000000000000000 g .text 0000000000000000 _start
Note in particular that it was smart enough to leave the .text section symbol alone, even though it is local. Of course this strip option can't really distinguish between useless (loop label) and potentially useful symbols, for example local function entry points which are needed to give correct stack traces with various tools.
If you wanted to be smarter about it, you could selectively strip only the asm-local (i.e., labels starting with a .) using the --wildcard and --strip-symbol options to selectively strip only labels with an embedded ..
I'm still looking for a better answer if one is lurking out there.
A little late, but I had this problem and wrote a patch for nasm 2.15 that fixes this. It adds a command-line switch called —discard-labels. You can get it here: https://forum.nasm.us/index.php?topic=2666.0

Why does clang create a linking problem when the symbols are present?

I have a strange linking problem. I have a bunch files that I am trying to compile, but I am running into an undefined symbol error. Below is the error:
clang U_outsup.o U_OUTSUR.o
Undefined symbols for architecture x86_64:
"U_outsup(surface*, __sFILE*)", referenced from:
U_outsur(surface*, char*) in U_OUTSUR.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
The same happens when I compile trying to with the source files to an out executable. If I look at those object files (clang -c U_outsup.c U_OUTSUR.C), I see the following:
U_outsup.o: file format Mach-O 64-bit x86-64
SYMBOL TABLE:
0000000000000420 l __DATA,__data _rname
0000000000000000 g F __TEXT,__text _U_outsup
0000000000000000 *UND* _A_extcpc
0000000000000000 *UND* _E_seterr
0000000000000000 *UND* _U_issurr
0000000000000000 *UND* _U_surbre
0000000000000000 *UND* _fprintf
U_OUTSUR.o: file format Mach-O 64-bit x86-64
SYMBOL TABLE:
0000000000000090 l __DATA,__data __ZL5rname
0000000000000000 g F __TEXT,__text __Z8U_outsurP7surfacePc
0000000000000000 *UND* __Z8E_seterrlPc
0000000000000000 *UND* __Z8U_outsupP7surfaceP7__sFILE
0000000000000000 *UND* _fclose
0000000000000000 *UND* _fopen
So, I am assuming the symbol "U_outsup(surface*, __sFILE*)" can't be found because it has a ridiculous name in the symbol table. Can anyone help me figure out what is going on here? Thanks again.
It doesn't have a ridiculous name. It has a c++ mangled name.
That means it was built with a c++ compiler and not a c one. Recompile the library with gcc or clang, not g++ or clang++.

GDB command 'info sharedlibrary' can't show all the libraries

I am doing cross compile debugging.
My build server CPU is amd64. My device CPU is MIPS.
When I am trying to do debug the elf file compiled by myself. The gdb can only show ld.so.1
(gdb) info sharedlibrary
From To Syms Read Shared Object Library
0x7704f9c0 0x7706c490 Yes (*) /lib/ld.so.1
(*): Shared library is missing debugging information.
(gdb) q
I checked the /proc/xxxx/maps file. It showed that the shared libraries are loaded.
root#TRA:/proc/13679# cat maps
......
76549000-76d48000 rwxp 00000000 00:00 0 [stack:13682]
76d48000-76d4a000 r-xp 00000000 00:0c 5268 /usr/lib/strongswan/plugins/libstrongswan-addrblock.so
76d4a000-76d59000 ---p 00002000 00:0c 5268 /usr/lib/strongswan/plugins/libstrongswan-addrblock.so
......
If I debug the file which is installed from Debian Package server, then GDB can show all the shared libraries.
(gdb) info sharedlibrary
From To Syms Read Shared Object Library
0x77341bc0 0x77342c80 Yes (*) /lib/mips-linux-gnu/libdl.so.2
0x771d77e0 0x772ff6f0 Yes (*) /lib/mips-linux-gnu/libc.so.6
0x773549c0 0x77371490 Yes (*) /lib/ld.so.1
(*): Shared library is missing debugging information.
(gdb)
GDB version is:
GNU gdb (Debian 7.7.1+dfsg-5) 7.7.1
My questions is:
Why the GDB command 'info sharedlibrary' can't show all the libraries? How can I fix it?
(EDIT)
(Does every executable file need the library ld.so? It is missing.)
The output of command "mips-linux-gnu-readelf -d src/charon/.libs/charon"
Dynamic section at offset 0x1fc contains 33 entries:
Tag Type Name/Value
0x00000001 (NEEDED) Shared library: [libstrongswan.so.0]
0x00000001 (NEEDED) Shared library: [libhydra.so.0]
0x00000001 (NEEDED) Shared library: [libcharon.so.0]
0x00000001 (NEEDED) Shared library: [libm.so.6]
0x00000001 (NEEDED) Shared library: [libpthread.so.0]
0x00000001 (NEEDED) Shared library: [libdl.so.2]
0x00000001 (NEEDED) Shared library: [libc.so.6]
0x0000001d (RUNPATH) Library runpath: [/usr/lib/strongswan]
0x0000000c (INIT) 0xd00
0x0000000d (FINI) 0x2eb0
0x00000004 (HASH) 0x32c
0x00000005 (STRTAB) 0x904
0x00000006 (SYMTAB) 0x4d4
0x0000000a (STRSZ) 787 (bytes)
0x0000000b (SYMENT) 16 (bytes)
0x70000035 (MIPS_RLD_MAP_REL) 0x134dc
0x00000015 (DEBUG) 0x0
0x00000003 (PLTGOT) 0x13760
0x00000011 (REL) 0xcf0
0x00000012 (RELSZ) 16 (bytes)
0x00000013 (RELENT) 8 (bytes)
0x70000001 (MIPS_RLD_VERSION) 1
0x70000005 (MIPS_FLAGS) NOTPOT
0x70000006 (MIPS_BASE_ADDRESS) 0x0
0x7000000a (MIPS_LOCAL_GOTNO) 18
0x70000011 (MIPS_SYMTABNO) 67
0x70000012 (MIPS_UNREFEXTNO) 37
0x70000013 (MIPS_GOTSYM) 0x11
0x6ffffffb (FLAGS_1) Flags: PIE
0x6ffffffe (VERNEED) 0xca0
0x6fffffff (VERNEEDNUM) 2
0x6ffffff0 (VERSYM) 0xc18
0x00000000 (NULL) 0x0
EDIT
Debuging GDB:
The gdb query ‘qXfer:libraries-svr4:read’ returned empty library list.
Breakpoint 7, svr4_current_sos_via_xfer_libraries (list=0x7fff8be59ad0, annex=<optimized out>)
at /gdb/gdb-7.11.1/gdb/solib-svr4.c:1301
1301 result = svr4_ parse_libraries (svr4_library_document, list);
1: svr4_library_document = 0x15cd9c0 "<library-list-svr4 version=\"1.0\"/>"
(gdb)
For Debian packages which are not compiled by me, the gdb query ‘qXfer:libraries-svr4:read’ returned full shared library list.
How does gdbserver construct the reply of this query ‘qXfer:libraries-svr4:read’?
EDIT
One more clue:
The pkgs installed from debian Jessie distribute is not PIE code.
The code I compiled is PIE code.
root#TRA:/proc/14956# readelf -r /usr/lib/strongswan/charon
Relocation section '.rel.dyn' at offset 0xcf0 contains 2 entries:
Offset Info Type Sym.Value Sym. Name
00000000 00000000 R_MIPS_NONE
00013870 00000003 R_MIPS_REL32
root#TRA:/proc/14956# readelf -r /usr/bin/id
There are no relocations in this file.
root#TRA:/proc/14956#
EDIT
After debugging gdbserver, I found one strange info.
The DT_DEBUG entry of the running proc is 0. After loader relocate the code, the DT_DEBUG should not be 0.(?) Does the system not support PIE code? I am using Debian Jessie MIPS system.
gdbserver source code:
if (dyn->d_tag == DT_DEBUG && map == -1)
map = dyn->d_un.d_val;
gdbserver dbg print
(gdb) p *dyn
$19 = {d_tag = 21, d_un = {d_val = 0, d_ptr = 0}}
(gdb)
EDIT
Get some information from this link:
https://sourceware.org/ml/binutils/2015-06/msg00166.html
I installed gdbserver from Debian Jessie mips-pkg server. But it seems not support PIE. Where can I install the mips-gdbserver which can support PIE?
Or how can I disable the gcc compiler generate PIE code?
I tried these flags (-fno-pie -fPIC) in cross-compile, but it still generate PIE code.
libtool: link: mips-linux-gnu-gcc -mfp32 -fno-pie -fPIC
-ggdb -O0 -Wall -Wno-format -Wno-format-security
-Wno-pointer-sign -I/cross-mips/usr/include -I/cross-mips/usr/include/libnl3
-I/cross-mips/usr/include/mips-linux-gnu
-I/work/strongswan/src/util
-include /work/strongswan/config.h
-o .libs/charon charon.o -L/cross-mips/lib/mips-linux-gnu
- L/cross-mips -L/cross-mips/usr/lib/mips-linux-gnu
../../src/libstrongswan/.libs/libstrongswan.so
-lm -lpthread -ldl -Wl,-rpath -Wl,/usr/lib/strongswan
Check the generated code:
mips-linux-gnu-readelf -r src/charon/.libs/charon
Relocation section '.rel.dyn' at offset 0xcf0 contains 2 entries:
Offset Info Type Sym.Value Sym. Name
00000000 00000000 R_MIPS_NONE
00013870 00000003 R_MIPS_REL32
Solution
Unfortunately the reason is my compiler gcc-6 is brocken. I used 'gcc version 6.3.0 20170516 (Debian 6.3.0-18)'. It is configured with '--enable-default-pie'. And there is no way to disable PIE. And this PIE breaks static library links. I have to change my compiler to gcc5.
From the info you provided, it seems that there are two likely causes:
Either you fully strip your binary, and gdbserver requires some symbol, or
You are building a PIE binary, and gdbserver on your system doesn't support such binaries.
(It's also possible that it's the combination of 1 and 2 that causes the problem.)
Since you know that the distribution binaries work, your best bet is probably to understand the differences between them and your binary, and minimizing such differences until gdbserver starts working.

objdump -t /usr/bin/sort command shows no symbols

If I try objdump -t /usr/bin/sort command it says no symbols. But it seems to work on my programs. What is the reason for this?
The symbols of /usr/bin/sort has been removed, e.g. with the strip program - for most executables the symbol table is not needed (or only needed for debugging). Here is a bit more info.
As the other answer mentions, your sort binary most likely has its symbols stripped out. However there should still be some dynamic symbol information, which may still be useful for debugging. These are generally the names of functions called by the binary which were dynamically linked. This usually includes libc functions, along with any other lib*.so shared libraries that your binary may have been linked with.
To see these, just add the -T argument:
$ objdump -tT /bin/sort
/bin/sort: file format elf64-x86-64
SYMBOL TABLE:
no symbols
DYNAMIC SYMBOL TABLE:
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 fileno
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 dup2
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 strcoll
...
$

Mongo C driver: Dynamic Linking with undefined symbol giving runtime error

I am trying to use Mongo C driver in my application but stuck badly in a linking problem. MongoC drivers provides 4 objects (libbson.a + libbson.so + libmongoc.a + libmongoc.so). My Makefile has libraries added like this.
srv_la_LIBADD = -lrt -lcre2 -lre2 -lcurl -lpthread -lmongoc \
-lbson #MODULES_LIBADD#
The drivers is compiled and installed successfully at /usr/local/lib. I have even made links to these in /lib and /lib64 directories.
The problem is that my application gets compiled and linked correctly but the final srv.so contains UNDEFINED symbols from the mongo C driver which give runtime errors.
Error loading module srv.so:/usr/local/c_icap/lib/c_icap/srv.so: undefined symbol: mongo_cursor_set_query
The linker line from Make process is:
libtool: link: gcc -shared -fPIC -DPIC .libs/srv_la-srv.o
.libs/srv_la-erd.o
.libs/srv_la-erd_list.o
.libs/srv_la-str_util.o
.libs/srv_la-url_util.o
.libs/srv_la-easyzlib.o
.libs/srv_la-state_db.o
.libs/srv_la-data_access_api.o
.libs/srv_la-cJSON.o
.libs/srv_la-clib_es.o
-lrt -lcre2 -lre2 /usr/lib/x86_64-linux-gnu/libcurl.so
-lpthread -lmongoc -lbson -O2 -O2 -Wl,-soname -Wl
,srv.so -o .libs/srv.so
Specifically the objdump of the srv.so says:
root#talha:/webproxy# objdump -t services/.libs/srv.so|grep "mongo"
0000000000000000 *UND* 0000000000000000 mongo_cursor_set_query
0000000000000000 *UND* 0000000000000000 mongo_destroy
0000000000000000 *UND* 0000000000000000 mongo_cmd_authenticate
0000000000000000 *UND* 0000000000000000 mongo_create_index
0000000000000000 *UND* 0000000000000000 mongo_cursor_destroy
0000000000000000 *UND* 0000000000000000 mongo_update
0000000000000000 *UND* 0000000000000000 mongo_cursor_next
0000000000000000 *UND* 0000000000000000 mongo_cursor_init
0000000000000000 *UND* 0000000000000000 mongo_remove
0000000000000000 *UND* 0000000000000000 mongo_connect
0000000000000000 *UND* 0000000000000000 mongo_cursor_bson
Whereas the bson symbols are added correctly. This is strange as both the libs are installed at the same location and have been added in the Makefile.
I tried to link libmongoc.a(static) statically but that results in the linker giving a portability warning of srv.so linking against libmongoc.a and produces final srv.a instead of src.so(but this kind of makes sense). Even then, the symbols are not present in srv.a. Which is even more strange to me.
The mongo C driver was built with -fPIC flag so that part is catered. Any helpful hints?
Why is it not linking properly and why is the linker not giving any errors?

Resources