Short answer is ltrace
doesn't behave as expected due to the Object File Type and Position Independent Executable of the binary being traced. If the binary being traced has an ET_EXEC
Object File Type and no Position Independent Executable, then ltrace
will be able to intercept and record the dynamic library calls.
For the Object File Type (ET_EXEC
, ET_DYN
, etc.) of a binary please refer to the ELF header (0x10 offset).
To verify this I'll be using the same test.c
program from the previous answer:
#include <unistd.h>
int main() {
write(0, "hello\n", 6);
return 0;
}
My system according to /etc/os-release
:
NAME="Ubuntu"
VERSION="20.04.2 LTS (Focal Fossa)"
Default gcc -v
(version and config):
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/9/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none:hsa
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 9.3.0-17ubuntu1~20.04' --with-bugurl=file:///usr/share/doc/gcc-9/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++,gm2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-9 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-9-HskZEa/gcc-9-9.3.0/debian/tmp-nvptx/usr,hsa --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04)
Now compiling with gcc test.c -o test
, we have:
$ ltrace ./test
hello
+++ exited (status 0) +++
Checking Object File Type of the binary with readelf -h ./test | grep Type
:
Type: DYN (Shared object file)
Checking Position Independent Executable with hardening-check ./test | grep Position
:
Position Independent Executable: yes
However compiling with gcc -no-pie test.c -o test
, we have:
$ ltrace ./test
write(0, "hello\n", 6hello
) = 6
+++ exited (status 0) +++
Checking Object File Type of the binary with readelf -h ./test | grep Type
:
Type: EXEC (Executable file)
Checking Position Independent Executable with hardening-check ./test | grep Position
:
Position Independent Executable: no, normal executable!
Hope this helps clarifying the behavior of ltrace
and its relation with the Object File Type and Position Independent Executable of the binary been traced.