Why does libc depend on ld.so? - c

I always think that libc should be an independent dynamic library, until I find this:
$ ldd /lib/x86_64-linux-gnu/libc.so.6
/lib64/ld-linux-x86-64.so.2 (0x00007fd743c00000)
linux-vdso.so.1 (0x00007fffc75f4000)
Can someone tell me why libc needs ld.so and what function it uses?

ld.so is needed by any application or shared library that is linked with shared libraries:
The programs ld.so and ld-linux.so* find and load the shared
objects (shared libraries) needed by a program, prepare the
program to run, and then run it.
Applications don't normally invoke any functions from ld-linux-x86-64.so, rather it loads the executable and shared libraries and passes the control flow to the application, which is normally C and C++ library runtime initialization code. Such a dependency on ld-linux.so* is established with .interp section of ELF file (see readelf -l /lib/x86_64-linux-gnu/libc.so.6 output) and that is not what ldd shows.
ldd, however, (recursively) shows libraries marked as NEEDED in dynamic section (see readelf -d /lib/x86_64-linux-gnu/libc.so.6 output). On Linux, thread local storage support for shared libraries is implemented by /lib64/ld-linux-x86-64.so.2. That is an implementation detail, but is the reason glibc depends on ld-linux-x86-64.so.

Related

What is the difference between shared and dynamic libraries in C?

I don't understand the difference between the two types of libraries, and many websites say that they are the same thing, but at school we use two different commands to create them
dynamic library
$ gcc -shared -o libsample.so lib.c
$ gcc -o main main.c -ldl
to execute:
$ ./main ./libsample.so
shared library
$ gcc -shared -o libsample.so lib.c
$ gcc -o main main.c -L. -lsample
to execute:
$ LD_LIBRARY_PATH=. ./main
Can someone help me in understanding the difference between the two "codes"?
Dynamic Linked Library (.DLL) is the terminology used by Microsoft Windows. Shared Object (.so) is the terminology used by Unix and Linux.
Other than that, conceptually they're the same.
Regarding your snippets of commands, I guess the difference (and I'm only guessing here, because you didn't show us the relevant parts) is how the library is loaded. There is "link time loading" where the library is tied to the executable by the linker¹. And there is "runtime loading", where the program sort of "ingests" the dynamic/shared library.
runtime loading is done in Windows with the LoadLibrary (there's an …A and a …W variant) function, and on Unix/Linux with dlopen (which is made available by libdl which is linked to by that -ldl library link statement).
1: The linker is the program that creates the actually executable file from the intermediary objects created by the various compiler stages.
Dynamic and shared libraries are usually the same. But in your case, it looks as if you are doing something special.
In the shared library case, you specify the shared library at compile-time. When the app is started, the operating system will load the shared library before the application starts.
In the dynamic libary case, the library is not specified at compile-time, so it's not loaded by the operating system. Instead, your application will contain some code to load the library.
The first case is the normal case. The second case is a special use and it's mainly relevant if your application support extensions such a plug-ins. The dynamic loading is required because there can be many plug-ins and they are built after your application. So their names are not available at compile-time.

How can I statically link a dylib to my program on macOS?

my c program calls:
hLibrary = dlopen("libPCBUSB.dylib", RTLD_LAZY);
and I seem to need this file in the directory when I run the executable after calling gcc main.c.
i.e. I run ./a.out and it all works as long as the dylib is in that directory.
In order to produce an executable with that dylib statically built in I've been trying all sorts of linking options but failing.
What is the correct way to compile my c program (in macOS Darwin not linux) to include this lib so the end user will not need it on their Mac?
Dynamic libraries (.dylib) can't be statically linked. If you have access to the source code for building the library, you can convert it to a static library and statically link against it in your app. If this is a 3rd-party binary-only library, you will need to ask the vendor for a static version of the library, and if that's not available, you will need to stick with linking it dynamically.
Note that dlopen() is not the only way to link against a dylib, you can also use -l, then you don't need to mess around with dlsym() etc. to get to the entry points. Either way requires shipping the library with your app of course.

Changing which libc.so gets linked?

Im trying to cross compile for MIPSEL on my router. I got stuff working in assembly, but now Im moving to trying to compile basic C code.
Currently just have simple hello world c code, and using the mipsel-linux-gnu-gcc compiler, which works for assembly.
Compiler command:
mipsel-linux-gnu-gcc -L/home/uname/devel/extr/squashfs-root/lib -l:libc.so.0 -mips32 -Wl,--build-id=none -Wl,--dynamic-linker=/lib/ld-uClibc.so.0 ma.c
The libc.so.0 is extracted from the firmware for the router.
The program compiles, however in readelf, the issue is that it links against libc.so.6
0x00000001 (NEEDED) Shared library: [libc.so.6]
whereas pulling the busybox binary from the firmware and running readelf on it
0x00000001 (NEEDED) Shared library: [libc.so.0]
How do I get it to link against libc.so.0?
It looks like you need to negate the standard glibc path, as the compiler checks this first. This can be done by compiling with -nostdinc.
You'll then need to -I include the gcc headers and such, as discussed here.
Figured it out. Had to build a uClibc toolchain using buildroot.

Linking shared library to executable

libourown.so provides function f definition
After execution of gcc command,
gcc a.o libourown.so.1 -o app
1)
Does libourown.so get linked to app at runtime , when f is called in app? or Does libourown.so gets linked to app at build time?
2)
Does libc.so get linked at runtime to app, after printf is called in app ? or Does libc.so gets linked to app at build time?
The answer is same to both of your questions. The shared libraries are not built into your executable (that's one of the main reasons why they came into existence in the first place!).
When you run your app, the drynamic linker/loader ld.so loads the necessary libraries.
You can see the shared libraries needed by your application by running:
$ ldd ./app
on the command line.
You may find this very useful to understand shared libraries on Linux: how to write shared libraries
To answer your "Does libourown.so get linked to app at runtime , when f is called in app? or Does libourown.so gets linked to app at build time?"
Dynamic libraries are linked as soon as they are brought into ram. The same answer valid for both of your questions. This type of linking done is known as load time linking.
Another method of doing it is to use the concept of run time linking. Using functions like dlopen(), dlsym()
The whole point of a shared object is that it won't be linked statically to your executable, but rather sit in the memory and serve those who need it.
Look at this thread:
how can I link a shared object in C?
It's impossible to statically link to a .so file: this file is missing information which is necessary for the linker to work. If you need to statically link to libourown.so, you have two options:
generate the static version of the library, libourown.a, and link against that
use a tool like statifier to embed libourown.so in your executable.
Libc is linked to executables dynamically by default. You can link to it statically using -static option. It should be noted that statically linking to libc will do more harm than good, because other libraries your executable is using are likely to be linked agains libc dynamically, and linking to the same library twice leads to a disaster.

How to compile readline from source?

When I compile readline into my directory /mypath as instructed (./configure --prefix=/mypath; make; make install) I get the following unresolved symbols in it:
ldd -r /mypath/lib/libreadline.so.6.2
linux-vdso.so.1 => (0x00007ffffb186000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f450c62f000)
/lib64/ld-linux-x86-64.so.2 (0x00007f450cc07000)
undefined symbol: UP (/mypath/lib/libreadline.so.6.2)
undefined symbol: PC (/mypath/lib/libreadline.so.6.2)
undefined symbol: BC (/mypath/lib/libreadline.so.6.2)
When I read the readme-file of readline, this seems to be a feature and not a bug:
`--with-curses'
This tells readline that it can find the termcap library functions
(tgetent, et al.) in the curses library, rather than a separate
termcap library. Readline uses the termcap functions, but does not
link with the termcap or curses library itself, allowing applications
which link with readline the to choose an appropriate library.
This option tells readline to link the example programs with the
curses library rather than libtermcap.
I tried it of course with --with-curses but that did not change anything, which is not surprising because it seems to be a setting that only affects some testing programs in readline.
My distribution (debian) however has a readline without undefined symbols, so it is clearly possible to do.
How to create a readline library without unresolved symbols?
Edit:
I have compiled and installed ncurses into the same directory and I have also tried to configure readline with CFLAGS=" -Wl,-rpath=/mypath" and --enable-static, without success.
Those symbols are defined by libncurses, I think. You can probably confirm this like this:
env LD_PRELOAD=/usr/lib/libncurses.so ldd -r /mypath/lib/libreadline.so.6.2
(I think ldd takes preloads into account when checking symbols, but it may not.)
The build script used by Arch Linux is here. It looks like the trick is to use:
make SHLIB_LIBS=/mypath/libncurses.so
There's also some other adjustments to the -rpath options in a build file, so you might need that also.
The make install step is installing the shared library in some directory, often /usr/local/lib/
You need to make the dynamic loader ld.so(8) aware of that. I would suggest add once /usr/local/lib/ into your /etc/ld.so.conf file then running ldconfig after each installation of new shared libraries inside it. See ldconfig(8), ldd(1)
You could also specify some -Wl,-rpath when linking programs with your version of libreadline.so
And when building a shared library you can link it to other shared libraries. On my Debian the system libreadline is linked to libtinfo:
% ldd /lib/x86_64-linux-gnu/libreadline.so.6
linux-vdso.so.1 (0x00007ffffccf3000)
libtinfo.so.5 => /lib/x86_64-linux-gnu/libtinfo.so.5 (0x00007f45cffcc000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f45cfc23000)
/lib64/ld-linux-x86-64.so.2 (0x00007f45d046c000)
You may want to study the source package of your readline6, since it contains the patches to the building procedure.
BTW, my Debian has a libtinfo5 package (obtained with dpkg -S /lib/x86_64-linux-gnu/libtinfo.so.5)

Resources