libc and undefined symbol: stime - glibc

I have an python application that uses the FTDI driver library named:
/usr/local/lib64/libftd2xx.so.1.4.22
When I run the application using libc 2.27, it works fine.
When running it against libc 2.32 it fails with the following:
/usr/local/lib64/libftd2xx.so: undefined symbol: stime
While looking at the libc release, indeed there is something related to stime from libc 2.31 as described at: https://lwn.net/Articles/811315/
It says:
"The obsolete function stime is no longer available to newly linked
binaries, and its declaration has been removed from <time.h>."
My understanding from this is that only "new code" cannot compile/link with this function but an existing library that were using this function should still work.
In fact if I look for the stime symbol the rough the below command in both 2.27 and the 2.32 I find that stime is there:
2.27
root#PPL23:~# nm --demangle --dynamic --defined-only --extern-only /lib/x86_64-linux-gnu/libc-2.27.so* | grep stime
00000000000d5ee0 T stime
2.32
localhost /tmp # nm --demangle --dynamic --defined-only --extern-only /lib64/libc-2.32.so | grep stime
000000000012e490 T stime#GLIBC_2.2.5
Why is libc 2.32 not backward compatible with the existing FTDI driver? Shouldn't that work even with 2.32 version since the symbol seems to be there?

According to the man page stime(2) is deprecated.
NOTE: This function is deprecated; use clock_settime(2) instead.
Instead of:
stime(100)
following code can be used:
clock_settime(CLOCK_REALTIME, (struct timespec*){100,0})
If for some reason you want to go with stime anyway, you may use the assembly trick proposed in the SymbolVersioning
__asm__(".symver stime,stime#GLIBC_2.2.5");

Related

Inspect and get binary from ELF file on MAC

I have a ELF file and I want to get a hex or bin file of my code from it. In the terminal, if a do a file main, which is my file, it shows:
main: ELF 32-bit LSB executable, UCB RISC-V, version 1 (SYSV), statically linked, not stripped
As I learned, objdump on MAC is not working and with otool -l main I get the following error:
llvm-objdump: 'main': Object is not a Mach-O file type.
The ELF file was created using the command:
riscv-none-gcc/8.2.0-2.1-20190425-1021/bin/riscv-none-embed-gcc --specs=nosys.specs main.c -o main
So is there a way to do it?
Thanks a lot
For creating "raw binary files"
the program objcopy
can be used, as described here:
objcopy -O binary foo.elf foo.bin
The program objcopy is part of the MacPorts
package x86_64-elf-binutils,
and can be used as follows:
/opt/local/bin/x86_64-elf-objcopy -O binary foo.elf foo.bin
where foo.elf is an ELF file compiled on (or cross-compiled for) an x86_64
Linux. The MacPorts package x86_64-elf-binutils can be installed as follows:
port install x86_64-elf-binutils
The program objcopy is part of binutils.
For Mach-O, it can be installed on macOS via the package binutils
of MacPorts, as follows:
port install binutils
The MacPorts binutils package installs gobjcopy.
Versions of binutils on macOS for cross-development for other target systems,
too, are available
via MacPorts.
This post is motivated also by MacOSX: which dynamic libraries linked by binary?,
and is intended to be also informational.
Executables can be:
ELF on Linux
Mach-O on macOS
ldd
ldd is a script in Linux
that wraps ld. It is described as
print shared object dependencies
The GNU ld is unavailable on macOS. More fundamentally, that ldd calls ld
means that its operation is non-static, in contrast to tools like readelf,
objdump, and nm.
In that sense, even if certain information is obtainable using tools other
than ldd, the results are not equivalent, because the other tools do not
attempt to load the binary. Moreover, attempting to load a binary requires
being on a Linux, so ldd is
genuinely a Linux tool that cannot be emulated exactly by a program on macOS.
A relevant description.
There does exist a pure-Python implementation that approximates ldd without
loading binaries the way that ld does: lddcollect.
Using lddcollect is possible on a Linux system, where the required libraries
are present.
One reason to not use ldd is security: inspecting executables without
executing them.
ldd is an initialism for
"List Dynamic Dependencies".
ldd appears to be a bash script that is part of glibc, with source code at:
https://sourceware.org/git/?p=glibc.git;a=blob;f=elf/ldd.bash.in;h=ba736464ac5e4a9390b1b6a39595035238250232;hb=271ec55d0ae795f03d92e3aa61bff69a31a19e3a
Relevant: What is the difference between ldd and objdump?
Relevant: cross compiler ldd
objdump
objdump shows information about
object files, and can disassemble them. It is part of binutils.
Programs that are called objdump on macOS:
/opt/local/bin/gobjdump by the MacPorts package binutils
/usr/bin/objdump by macOS (part of package com.apple.pkg.Essentials),
which is described as the
llvm object file dumper
The manual of ldd suggests calling objdump as an alternative, as follows:
objdump -p /path/to/program | grep NEEDED
Relevant: https://superuser.com/questions/206547/how-can-i-install-objdump-on-mac-os-x
readelf
readelf displays information about
ELF files by reading them (static, not loading them). It is part of binutils.
It does not disassemble files, like objdump can.
Variants available on macOS:
/opt/local/bin/greadelf from the MacPorts package binutils
/opt/local/bin/elftc-readelf from the MacPorts package elftoolchain
Example usage:
readelf -s elf_file
nm
/usr/bin/nm by macOS (part of package com.apple.pkg.Essentials)
/opt/local/bin/nm by the MacPorts package cctools,
which is a symbolic link: /opt/local/bin/nm -> llvm-nm-mp-10
/opt/local/bin/nm-classic by the MacPorts package cctools
/opt/local/bin/elftc-nm by the MacPorts package elftoolchain
/opt/local/bin/gnm by the MacPorts package binutils
Apparently, both /usr/bin/nm and /opt/local/bin/nm are versions of the
llvm symbol table dumper
and do work with ELF files.
otool (and variants)
otool is the the disassembler for MacOS's Mach-O format.
Variants of otool available on macOS:
/usr/bin/otool by macOS (part of package com.apple.pkg.Essentials)
/opt/local/bin/otool by the MacPorts package cctools,
which links to /opt/local/bin/llvm-otool by the MacPorts package cctools,
which is described as:
the otool-compatible command line parser for llvm-objdump
/opt/local/bin/otool-classic by the MacPorts package cctools
More details:
> which -a otool
/opt/local/bin/otool
/usr/bin/otool
> ls -lsa /opt/local/bin/otool
... /opt/local/bin/otool -> llvm-otool
> port provides /opt/local/bin/otool
/opt/local/bin/otool is provided by: cctools
> which -a llvm-otool
/opt/local/bin/llvm-otool
> port provides /opt/local/bin/llvm-otool
/opt/local/bin/llvm-otool is provided by: cctools
> ls -lsa /usr/bin/otool
... /usr/bin/otool
> pkgutil --file-info /usr/bin/otool
volume: /
path: /usr/bin/otool
pkgid: com.apple.pkg.Essentials
...
The MacPorts package cctools installs also /opt/local/bin/otool-classic,
which, as said in its documentation, is obsolete.
elfdump
elfdump is available on macOS via the MacPorts package elftoolchain,
and installed as the binary /opt/local/bin/elftc-elfdump.
strings
The program strings can be
useful for inspecting the symbols contained in an ELF file. It is a more
general tool, not designed specifically for ELF files, but usable nonetheless.
Variants of strings on macOS:
/usr/bin/strings by macOS (part of package com.apple.pkg.Essentials)
/opt/local/bin/strings from the MacPorts package cctools
/opt/local/bin/elftc-strings from the MacPorts package elftoolchain
/opt/local/bin/gstrings from the MacPorts package binutils
Example usage (piping to ag):
strings some_elf_file | ag GLIBC
elftc-strings appears to have fewer options and give fewer results than
the other strings implementations (which differ with each other, but seem
to print similar results).
elftoolchain
Available via MacPorts, elftoolchain
is a BSD-licensed library of tools like those in binutils. Tools from that
collection that are relevant to analyzing ELF files:
/opt/local/bin/elftc-elfdump
/opt/local/bin/elftc-nm
/opt/local/bin/elftc-readelf
/opt/local/bin/elftc-strings
There are also plans for
implementing objdump.
Confirming that a binary is from MacPorts
To find out whether a given file is part of MacPorts:
> port provides /opt/local/bin/otool
/opt/local/bin/otool is provided by: cctools
Discussed in this answer.
Confirming that a binary is from macOS
Also useful for finding out how each
of the tools discussed above was installed is pkgutil:
pkgutil --file-info /usr/bin/objdump
This can be useful to confirm that a binary was part of macOS itself, and not
installed by other means.
Confirming that an executable is an ELF
This text was motivated when I wanted to analyze an executable with the
following details:
> file filename
ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=..., for GNU/Linux 3.2.0, not stripped
As for other tools, there are multiple options for file on macOS:
/usr/bin/file by macOS (part of package com.apple.pkg.Essentials)
/opt/local/bin/file by the MacPorts package file
Other tools
Apparently, on some operating systems there are also elftools available.
For analyzing files for specific architectures, there are MacPorts packages
like arm-elf-binutils.
DWARF
There is also DWARF and dwarftool,
as well as dwarfdump (part of XCode).
Miscellanea
binutils can analyze Mach-O on Linux: https://stackoverflow.com/a/8714142/1959808
darling can be used on Linux to run
macOS software (Mach-O, dyld), it is analogous to wine

GNU toolchain (newlib): compatibility between toolchain versions (undefined symbol __ctype_ptr__)

Having here a project that is using some external GNU-toolchain built libraries (provided externally, without source-code). I'm compiling an application for embedded systems (FreeRTOS specifically), so I use newlib.
I initially tried using this toolchain https://releases.linaro.org/components/toolchain/binaries/7.4-2019.02/aarch64-elf/
but that failed because of (among others) these linker errors:
undefined reference to `__ctype_ptr__'
It seems that this symbol should be defined by libc. Going into the newlib sysroot, specifically in this case the sysroot-newlib-linaro-2019.02-aarch64-elf\usr\lib directory, tried to find __ctype_ptr__ in libc.a:
aarch64-elf-nm -C --defined-only -g libc.a | grep __ctype_ptr__
No output, so this libc indeed does not define __ctype_ptr__.
Continuing by taking a look into the library that needs the symbol, a notepad++ edit revealed this among the mangled text:
/opt/gcc-linaro-5.4.1-2017.05-x86_64_aarch64-elf/aarch64-elf/libc/usr/include/machine
Which means this library was built using the 5.4.1 aarch64-elf toolchain version and I was trying to use version 7.4 since I need newer C++ standard support.
Downloaded the 5.4.1 version as well (sysroot only): https://releases.linaro.org/components/toolchain/binaries/5.4-2017.05/aarch64-elf/
Again, going into the 5.4.1 sysroot-newlib-linaro-2017.05-aarch64-elf\usr\lib directory this time:
aarch64-elf-nm -C --defined-only -g libc.a | grep __ctype_ptr__
finally reveals:
0000000000000000 D __ctype_ptr__
which means that indeed the 5.4.1 newlib libc exports this symbol.
Questions:
Why this incompatibility between the 2 versions? What category do these kind of changes belong to? Where can I find more detailed information about changes like these and the reasons they are there?
Am I forced to use the old version because those libraries were built with it? Is there no way to use the newer version instead? How are these situations usually handled?
_ctype_ptr_ is simply a pointer to _ctype_ which is a 128 byte table
containing a bitset used by the ctype.h functions like isalpha.
The functions will take a character as a parameter, and will use the
character as an index into the _ctype_ array.
A mask is applied to the read value, and if non-zero the function returns "true"
You can worst case define your own
extern const char _ctype_[];
const char* __ctype_ptr__ = _ctype_;
If _ctype_ is reported undefined by the linker,
you may have to define it in the linker
ctype = _ctype_;
and in the source code.
extern const char ctype[];
const char* __ctype_ptr__ = ctype;

Synology DSM6 - libc.so.6 - File format not recognized

My final goal is to install Nagios on my Synology DiskStation DS1813+ with DSM 6.0.1-7393 Update 1. But I can't even begin compiling the package...
When I try to use gcc on my Synology DiskStation I always get the following error message:
$ gcc hello.c -o hello.o
/lib/libc.so.6: file not recognized: File format not recognized
collect2: ld returned 1 exit status
Here's my shell environment. I have tried it with different LD_LIBRARY_PATH settings, but even omitting it doesn't make a difference.
$ env
TERM=xterm-256color
SHELL=/bin/sh
SSH_CLIENT=192.168.2.110 51079 22
OLDPWD=/var/services/homes/egi
SSH_TTY=/dev/pts/7
LC_ALL=en_US.utf8
USER=egi
LD_LIBRARY_PATH=/opt/lib:
PAGER=more
MAIL=/var/mail/egi
PATH=/opt/sbin:/opt/bin:/sbin:/bin:/usr/sbin:/usr/bin
PWD=/var/services/homes/egi/exer
LANG=en_US.utf8
PS1=[\u#\h \W]$
SHLVL=1
HOME=/var/services/homes/egi
TERMINFO=/usr/share/terminfo
LOGNAME=shunyam
SSH_CONNECTION=xxx.xxx.xxx.xxx 51079 yyy.yyy.yyy.yyy 22
PGDATA=/var/services/pgsql
CC=gcc
_=/opt/bin/env
The compiler has been installed with ipkg and its specs look like this:
$ gcc --verbose
Using built-in specs.
Target: i686-linux-gnu
Configured with: ../gcc-4.2.1/configure --build=i386-pc-linux-gnu --host=i686-linux-gnu --target=i686-linux-gnu --prefix=/opt --disable-nls --disable-static --with-as=/home/slug/optware/syno-i686/toolchain/gcc-4.2.1-glibc-2.3.6/i686-linux-gnu/bin/i686-linux-gnu-as --with-ld=/home/slug/optware/syno-i686/toolchain/gcc-4.2.1-glibc-2.3.6/i686-linux-gnu/bin/i686-linux-gnu-ld --enable-languages=c,c++ --disable-multilib
Thread model: posix
gcc version 4.2.1
The library that causes the problem returns this information:
$ /lib/libc.so.6
GNU C Library (crosstool-NG 1.20.0) stable release version 2.20-2014.11, by Roland McGrath et al.
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 4.9.3 20150311 (prerelease).
Available extensions:
crypt add-on version 2.1 by Michael Glad and others
GNU Libidn by Simon Josefsson
Native POSIX Threads Library by Ulrich Drepper et al
BIND-8.2.3-T5B
libc ABIs: UNIQUE IFUNC
For bug reporting instructions, please see:
<http://www.gnu.org/software/libc/bugs.html>.
There is also a linker script at /opt/lib/libc.so:
$ cat /opt/lib/libc.so
/* GNU ld script
Use the shared library, but some functions are only in
the static library, so try that secondarily. */
OUTPUT_FORMAT(elf32-i386)
GROUP ( /lib/libc.so.6 /opt/lib/libc_nonshared.a )
The library can't actually be broken, otherwise nothing would work at all.
Alongside with gcc all other required packages have also been installed with ipkg.
Weirdly enough I seem to be the only person with that issue as I have found no relevant posts on Google. Synology's support told me that they are not supporting installing command command line packages.
When I first installed gcc on this Diskstation about two years ago, everything was working fine. I have noticed this problem a few months ago (probably after a DSM update).
Has anyone also come across this issue or has a clue on how to get it working again? Thanks!
I had this exact same problem. GCC use to work and now with DSM 6.1 it broke. I think it's after they switched to 64-bit with DSM 6.0 I believe. Your question actually gave me the answer so I wanted to share it here. I changed /lib/libc.so.6 to /lib32/libc.so.6 in the file /opt/lib/libc.so.
$ cat /opt/lib/libc.so
/* GNU ld script
Use the shared library, but some functions are only in
the static library, so try that secondarily. */
OUTPUT_FORMAT(elf32-i386)
GROUP ( /lib32/libc.so.6 /opt/lib/libc_nonshared.a )
After making the change above optware GCC compiled my test file without any environment variables set just like you would expect on a normal Linux system.
It looks like I've been using some other g++:
/volume1/homes/user/x86_64-pc-linux-gnu/bin/x86_64-pc-linux-gnu-g++
It came from this file: gcc473_glibc217_x86_64_cedarview-GPL.tgz.
Other people have problems too with DSM 6: https://forum.synology.com/enu/viewtopic.php?t=116803
It's suggested to use the Debian Chroot Package from SynoCommunity instead.
You just have to change lib by lib32 like this :
cat /opt/lib/libc.so
/* GNU ld script
Use the shared library, but some functions are only in
the static library, so try that secondarily. */
OUTPUT_FORMAT(elf32-i386)
GROUP ( /lib32/libc.so.6 /opt/lib/libc_nonshared.a )

CentOS: Using GCC 4.7 from devtoolset results in linking libstdc++ incorrectly (undefined symbols)

I am using the devtoolset-1.0 for CentOS 6.3 in order to upgrade temporarily the GCC version. Although I am now able to compile my C++ application, the final binary is missing some symbols:
$ ldd -d -r myapp
$ [..]
$ libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x0000003216e00000)
$ [..]
$ undefined symbol: _ZNSt8__detail15_List_node_base11_M_transferEPS0_S1_ (./myapp)
$ undefined symbol: _ZNSt8__detail15_List_node_base7_M_hookEPS0_ (./myapp)
$ undefined symbol: _ZNSt8__detail15_List_node_base9_M_unhookEv (./myapp)
I figured out, that these are some new functions, which aren't found in the 'old' libstdc++, but in a newer libstdc++. On my system, both libstdc++ (default version 4.4.7) and devtoolset-1.0-libstdc++-devel (4.7 via devtoolset) are installed. Interestingly, the libstdc++ from devtoolset links agains to the old one:
$ cat /opt/centos/devtoolset-1.0/root/usr/lib/gcc/x86_64-redhat-linux/4.7.0/libstdc++.so
$ /* GNU ld script
$ Use the shared library, but some functions are only in
$ the static library, so try that secondarily. */
$ OUTPUT_FORMAT(elf64-x86-64)
$ INPUT ( /usr/lib64/libstdc++.so.6 -lstdc++_nonshared )
What I actually want is to replace the libstdc++ binding, but I don't know how to achieve that. I already tried to set LD_LIBRARY_PATH and pointing to the devtoolset directory, but the libstdc++ was still set to the old location. Also a symbolic link did not result in a success, because it is a ld script and not actual shared library.
the final binary is missing some symbols
That looks like a bug in devtoolset-1-gcc, which I assume has been fixed in more recent versions of devtoolset.
Interestingly, the libstdc++ from devtoolset links agains to the old one:
Yes, that's how the devtoolset gcc is supposed to work (see this answer for more details).
What I actually want is to replace the libstdc++ binding, but I don't know how to achieve that.
You can't do that with the devtoolset of GCC, because it doesn't even have a new libstdc++.so library. As you found, that file is actually a linker script, which links your binary to libstdc++_nonshared.a /usr/lib64/libstdc++.so
Since there is no new libstdc++.so you can't link to it.
The GCC compiler and its libraries (very specially g++ and corresponding libstdc++ runtime) need to match. Compiling with a newer compiler will (very often, practically guaranteed if a new version of the language is supported) give binaries that don't work with an older library. Older binaries might work with a newer library, no guarantees here.

What is the difference between /lib/i386-linux-gnu/libc.so.6, /lib/x86_64-linux-gnu/libc.so.6 and /usr/lib/x86_64-linux-gnu/libc.so?

I installed Matlab in my Linux Mint 14 Nadia (a uname -a shows: Linux Ideapad-Z570 3.5.0-17-generic #28-Ubuntu SMP Tue Oct 9 19:31:23 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux) and when calling it from the command line I would get a: "/lib64/libc.so not found".
I followed the help on mathworks by making a link in /lib64 as:
ln -s /lib/x86_64-linux-gnu/libc.so.6 .
That solved the issue.
Now, if I do a locate of this library I get:
locate "libc.so"
/lib/i386-linux-gnu/libc.so.6
/lib/x86_64-linux-gnu/libc.so.6
/usr/lib/x86_64-linux-gnu/libc.so
I will be compiling with gcc in this computer and I would like to have full 64bit compilations. What does exactly mean to have all these different libc.so libraries? which one will the gnu compiler be using? do I need to do anything different with gcc to compile for 64 bits?
I would also love to optimize as much as I can for my new i7 core!!!
/lib/i386-linux-gnu/libc.so.6
This is is 32-bit version of the library.
/lib/x86_64-linux-gnu/libc.so.6
This is the 64-bit version of the library.
Both are usually symbolic links to the actual library file, which will usually be named according to the glibc release number, for example libc-2.15.so
/usr/lib/x86_64-linux-gnu/libc.so
This is not a library, but a linker script file, which refers to the above symlinks.
Why do we need all these:
First, regardless of libc version installed, the linker will always search for libc.so, because the compiler driver will always pass to the linker the -lc options. The name libc stays the same and denotes to most recent version of the library.
The symlinks libc.so.6 are named after the soname of the library, which, more or less corresponds to the ABI version of the library. The executables, linked against libc.so in fact contain runtime dependencies on libc.so.6.
If we imagine the someday a grossly ABI incompatible libc is released, it's soname could be named libc.so.7, for example and this version coukld coexists with the older libc.so.6 version, thus executables linked against one or the other can coexist in the same system,
And finally, the name libc-2.15.so refers to the libc release, when you install a new libc package, the name will change to libc-2.16.so. Provided that it is binary compatible with the previous release, the libc.so.6 link will stay named that way and the existing executables will continue to work.
To find which one to use, you have to first find the order that ld (the linker) uses to find libraries, like so:
ld --verbose | grep SEARCH
For me it gave me this output:
SEARCH_DIR("/usr/x86_64-unknown-linux-gnu/lib64"); SEARCH_DIR("/usr/x86_64-unknown-linux-gnu/lib"); SEARCH_DIR("/usr/lib"); SEARCH_DIR("/usr/local/lib");
This means that on my computer, ld looks in these directories, in order:
/usr/x86_64-unknown-linux-gnu/lib64
/usr/x86_64-unknown-linux-gnu/lib
/usr/lib
/usr/local/lib
So if libc was in /usr/x86_64-unknown-linux-gnu/lib64, and libc was also in /usr/lib, it would use the /usr/x86_64-unknown-linux-gnu/lib64 version, because it was listed first.
The symlink you created will have no effect whatsoever on GCC. The 32-bit version is only used when you compile using the -m32 GCC flag. GCC will not attempt to generate 32-bit binaries unless you specifically tell it to (by using that flag.)

Resources