Why can't I directly start a shared library in Linux? - linux

$ chmod +x libsomelibrary.so
$ ./libsomelibrary.so
Segmentation fault
$ gcc -O2 http://vi-server.org/vi/bin/rundll.c -ldl -o rundll
$ ./rundll ./libsomelibrary.so main
(application starts normally)
Why can't I just start libsomelibrary.so if it has usable entry point?
rundll.c is trivial:
void* d = dlopen(argv[1], RTLD_LAZY);
void* m = dlsym(d, argv[2]);
return ((int(*)(int,char**,char**))m)(argc-2, argv+2, envp);
Why is it not used internally when attempting to load a binary?

main is not the entry point recognised by the kernel or the dynamic linker - it is called by the startup code linked into your executable when you compile it (such startup code isn't linked into shared libraries by default).
The ELF header contains the start address.

Shared libraries are not designed to be directly runnable. They are designed to be linked into another codebase. It may have a usable entry point, but being executable entails more than merely having a usable entry point. The rundll utility is proof of this. Your second test shows that the shared library is indeed executable, but only after rundll does some work. If you are curious as to what all has to be done before the library code can be executed, take a look at the source code for rundll.

You can start shared libraries in Linux.
For example, if you start /lib/libc.so.6, it will print out its version number:
$ /lib/libc.so.6
GNU C Library stable release version 2.12, by Roland McGrath et al.
Copyright (C) 2010 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.5.0 20100520 (prerelease).
Compiled on a Linux 2.6.34 system on 2010-05-29.
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 must be something missing from your library.

Related

Hello world cross compiled for ARM is runing on both x86_64 and ARM

I was preparing a demonstration of user mode Qemu's (qemu-user package) qemu-arm. To do so, I used a simple hello world C program hello.c:
#include <stdio.h>
int main()
{
printf("Oi, Qemu!\nPrograma C aqui!\n");
}
To cross compile it (statically linked), I used the cross toolchain from gcc-arm-linux-gnueabihf:
$ arm-linux-gnueabihf-gcc --version
arm-linux-gnueabihf-gcc (Ubuntu 9.3.0-10ubuntu1) 9.3.0
Copyright (C) 2019 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.
$ arm-linux-gnueabihf-gcc hello.c -o hello_c_static -static
The output runs in both qemu-arm, Beaglebone Black AND ON THE PC.
How is it possible?!
EDIT
About the compiled executable:
file hello_c_static
hello_c_static: ELF 32-bit LSB executable, ARM, EABI5 version 1
(GNU/Linux), statically linked,
BuildID[sha1]=6a33aaa5abb9a14fbc0ca4f2e7b432d6fa5d7067, for GNU/Linux 3.2.0,
not stripped
Check ls -l /proc/sys/fs/binfmt_misc/ to see if your x86 system is set up to transparently run qemu on ARM binaries for you, the same way it can be to run WIINE on Windows executables or whatever using Linux binfmt_misc. https://en.wikipedia.org/wiki/Binfmt_misc
Admin guide https://www.kernel.org/doc/Documentation/admin-guide/binfmt-misc.rst
The installer for the qemu-user package might have registered the executable formats it supports.
With no binfmts registers, you'll just have the register and status "files". On my system, WINE and Mono boot scripts have registered handlers so I also see CLR and DOSWin files. e.g.
$ cat /proc/sys/fs/binfmt_misc/DOSWin
enabled
interpreter /usr/bin/wine
flags:
offset 0
magic 4d5a
If there's somehow a different mechanism, try using strace ./some_arm_program to see what system calls happen when you execute it.
Maybe also suspend it while it's running (control-z) and look at /proc/$(pidof some_arm_program)/maps and other files.
(This last section was written after the OP commented that they only saw register and status files, not qemu-arm, but they've since change their comment. It looks like binfmt-support is the answer.)

Valgrind: shared libraries for the executable program could not be loaded

I have some weird memory related errors in my program.
It uses intel mkl and therefore depends upon some mkl specific shared libraries.
When I run my program, it segfaults after it has done most of the work. The segfaults occurs in the function call fclose() to a file pointer that is not null.
When I run my program through gdb, the stacktrace is not very useful.
I therefore wanted to run valgrind to find possible errors in my code.
But, I cannot run the executable from valgrind. It prints the following error message.
==52778== Memcheck, a memory error detector
==52778== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==52778== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==52778== Command: ./main.exe
==52778==
./main.exe: error while loading shared libraries: libmkl_intel_lp64.so: cannot open shared object file: No such file or directory
The shared library libmkl_intel_lp64.so is present in the same directory (as well as all other shared libraries that my executable depends upon).
How do I resolve this problem, so that I can valgrind my code?
Thanks.
Edit: I also set (and checked) the environment variable LD_LIBRARY_PATH to the current directory, but it did not help.
Edit: Running on Linux 64 bit, using intel compilers 2017
The shared library libmkl_intel_lp64.so is present in the same
directory (as well as all other shared libraries that my executable
depends upon).
How do I resolve this problem, so that I can valgrind my code?
valgrind provides much of it's own environment and wrappers for various functions in order to do its job. Since you have set LD_LIBRARY_PATH and are still experiencing problems finding your library, your other option is to provide the library search path within the executable itself using the linker option -rpath=/path/to/dir that contains the library. The addition to the compile string would be:
-Wl,-rpath=/path/to/dir /* that has libmkl_intel_lp64.so in it */
Then finding the library doesn't depend on the external environment or the hope that valgind will extend its library search to the current working directory.
(glad it worked)

GDB Warning: Loadable section not found in added symbol-file system-supplied DSO at 0x7ffff7ffd000

abijith bufferOverFlow $ gdb a.out
GNU gdb (GDB) 7.6
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-unknown-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/abijith/Project/Security/bufferOverFlow/a.out...done
(gdb) r
Starting program: /home/abijith/Projec2qt/Security/bufferOverFlow/a.out
warning: no loadable sections found in added symbol-file system-supplied
SO at 0x7ffff7ffd000
I wrote a simple program which prints a string and returns. I was able to execute it directly, by typing "./a.out". But when I run it in gdb the error mentioned above happens. I tried compiling the code using the "-g" flag and without using it. Both time it gave the same result. Can anyone help me with this issue??
That message,
warning: no loadable sections found in added symbol-file system-supplied
SO at 0x7ffff7ffd000
is a warning that does not prevent GCC from running a.out; at least, it should not.
It is saying that there's a dynamically loaded object used by a.out that is missing symbols. Nothing about a.out itself.
You can try to build a.out as a static executable; like this:
gcc -static a.c
Obviously, add any other compiler arguments needed.
As a static executable, you won't get that warning from GCC. Those symbols may still be missing, but it should not affect execution of the program.
It appears this is a bug in glibc or gdb (depending on where you want to put the blame). It is apparently harmless - gdb will work fine.
It is caused by some magic the Linux kernel performs on binaries it runs. For details, see Debian bug report 738702 and the original gdb bug report 13097.
There is a patch to fix this, which Debian applied recently, so the problem no longer occurs with GDB 7.7.1 on Debian.

gcov not showing any coverage data

I am trying to use gcov on Linux(Ubuntu) to see frequency of execution for each line of source.
I have added following flags to my gcc compiler and linker flags,
CCFLAGS = -fprofile-arcs -ftest-coverage
LDFLAGS = -fprofile-arcs -lgcov
but after compiling and running the program, i see no *.gcda file created. As a result of which when i run
gcov --object-directory <path to the *.gcno/*.gcda files> myfile.cpp
Shows error:
myfile.gcda:cannot open data file, assuming not executed
File '../../../../../code/myfile.cpp'
Lines executed:0.00% of 2625
Am i missing something. How to fix this?
You can use __gcov_flush() method inside your code.
You will need to invoke this from registered signal handler.
See:
https://www.osadl.org/fileadmin/dam/interface/docbook/howtos/coverage.pdf
Using this, you can keep your service running and issue "kill" whenever you need to dump coverage data.
Hope that helps....
make sure the gcov and gcc are of the same version :), this where many of the people fail to check.
$gcc --version
gcc (GCC) 4.1.1
Copyright (C) 2006 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.
$ find /usr/lib/gcc -name libgcov.a
/usr/lib/gcc/x86_64-redhat-linux/4.1.1/32/libgcov.a
/usr/lib/gcc/x86_64-redhat-linux/4.1.1/libgcov.a
/usr/lib/gcc/x86_64-redhat-linux/3.4.6/32/libgcov.a
/usr/lib/gcc/x86_64-redhat-linux/3.4.6/libgcov.a
so the gcc version you have loaded should be atleast in the available list of libgcov.a

When linking a program with gcc on Linux or OSX how can I figure out how it's called when using -l

The name of the file which contains the lib and the name used in -l do not always match. So how can I figure out the name used when linking? Usually I googled, but it should be somewhere in the system I think..
My answer's a bit messy, sorry about that. I'm pretty sure there's a better solution but this should help nevertheless.
During link-time, AFAIK the linker searches all library paths it knows about and looks for the arch-dependent library name, on Linux "-l foo" would search for "libfoo.so", on a Mac "libfoo.dylib". Now if you look for example in /usr/lib, you'll notice that there are a lot of symlinks. For example, if you have libfoo.so.1.2.3 there should also be symlinks libfoo.so.1.2 -> libfoo.so.1.2.3, libfoo.so.1 -> libfoo.so.1.2 and libfoo.so -> libfoo.so.1. The idea behind this is to support various versions. So if you need to know which file is used I suggest you do this:
Add "-v" to your LDFLAGS or directly to your call to gcc. This will result in a noisy output of gcc, the interesting thing is the call to "collect2". It has various arguments -L... and these are the directories the linker searches for libraries. You will also see -l... (lower case ell). You need to look into the -L directories for libraries given in -l and follow their symlinks.
If you need to know which library is used during runtime: that's a lot easier. Just run ldd some_program, it will tell you which libraries are used. It actually calls the program so that the dynamic linker kicks in, but passes an environment variable that makes the linker print out what it has loaded and exit the program before even starting it. On a Mac, use otool -L some_program.
For a running program, you need to find out the program's PID. Then do cat /proc/pid_of_program/maps. That gives you the memory map. The interesting part is the right hand column which lists the loaded libraries (because they get mmap'ed into the process). I don't know the equivalent for that on a Mac.
The best way to see what is happening here is to examine exactly what files gcc (both the compiler and the linker) is manipulating:
strace -f -e trace=open -o strace_output (your_gcc_command)
The '-f' is needed to follow child processes since that is how gcc works. I find this method to be extremely useful, since I can figure out exactly what libraries the linker is concatenating into my executable. I only wish that 'gcc -v' were this verbose.
Just type man gcc at a prompt to get the manual page for gcc. It details what the -l option does. If gcc is using ld as the linker then just do man ld for slightly more information. For example on my Linux system the latter says
-lnamespec
--library=namespec
Add the archive or object file
specified by namespec to the list of
files to link. This option may be
used any number of times. If namespec
is of the form :filename, ld will
search the library path for a file
called filename, otherise it will
search the library path for a file
called libnamespec.a.
On systems which support shared
libraries, ld may also search for
files other than libnamespec.a.
Specifically, on ELF and SunOS
systems, ld will search a directory
for a library called libnamespec.so
before searching for one called
libnamespec.a. (By convention, a
".so" extension indicates a shared
library.) Note that this behavior
does not apply to :filename, which
always specifies a file called
filename.
Copyright (c) 1991, 92, 93, 94, 95, 96, 97, 98, 99, 2000, 2001, 2002,
2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3 or
any later version published by the Free Software Foundation; with no
Invariant Sections, with no Front-Cover Texts, and with no Back-Cover
Texts.
Also note that on OSX if you set the environment variables RC_TRACE_ARCHIVES and RC_TRACE_DYLIBS then ld will print lots of useful debugging information. This can be helpful if you are picking up the wrong library at build time.

Resources