flak rss random

you don't link all of libc

On OpenBSD, there is a rule that you link with libc to interface with the kernel, because that’s where the syscall stubs live. This causes a great deal of consternation for partisans of other languages, because they don’t want to link “all of libc”. But when does anything link all of libc?

quick proof

$ ls -l /bin/ls /usr/lib/libc.a
-r-xr-xr-x  1 root  bin   297448 Mar 20  2024 /bin/ls
-r--r--r--  1 root  bin  8347256 Mar 20  2024 /usr/lib/libc.a

ls is statically linked, yet clearly smaller than libc.a. It is not linked with all of libc. QED.

If you are statically linking with libc just to get open and mmap and related symbols, and somehow all of libc shows up in your program, that’s a deficiency of your dogshit linker.

ar

What’s in libc.a anyway? It’s an ar archive, which is conceptually not so different from tar I guess. It’s a big pile of object files collected together. Like tar, it has options to print (and extract) files.

$ ar p /usr/lib/libc.a malloc.o > malloc.o
$ ar p /usr/lib/libc.a open.o > open.o
$ ls -l *o
-rw-r--r--  1 tedu  wheel  201624 Feb 11 15:32 malloc.o
-rw-r--r--  1 tedu  wheel    2360 Feb 11 15:32 open.o

There’s more code in malloc than open, so that looks about right. You can now objdump or even hexdump these files to confirm that they are the same files one gets by compiling.

Heck, let’s just go through it start to finish.

wx$ cc -c funtime.c        
wx$ ar qc libfun.a funtime.o
wx$ ar p libfun.a funtime.o > new.o                                                           
wx$ strings new.o
Are we not entertained
wx$ cat funtime.c
char mesg[] = "Are we not entertained";

linking

There’s an index of symbols to files in the archive, generated by ranlib. When you link with an archive, conceptually those object files are extracted and then linked as if added on the command line. There’s not much difference between cc ... -lfun and cc ... funtime.o except the former is much simpler in the case where there are many object files involved. A good linker is a bit more sophisticated than running cat to append the archive to the executable, but not terribly so.

The fact that the linker works at the level of object files explains why there are so many source files in libc (and other archives of a certain vintage). Object files do get linked in their entirety, and so splitting libc into many object files allows more granular linking. If it were compiled as a giant splat.c file, then you would end up linking with all of it.

bits

The rules are different for dynamic linking, but all the cool kids only do static linking. You do get all of libc, but it’s already there anyway.

I keep saying all of libc like a nervous tic because the people who hate linking with libc keep saying all of libc. I don’t know why.

The rule that you link with libc on OpenBSD is more like a guideline. It’s not magic, it’s just code. You can write not C code that does the same. There’s no blockchain of all libcs embedded in the kernel to enforce the rule.

Posted 12 Feb 2025 18:54 by tedu Updated: 12 Feb 2025 18:54
Tagged: c openbsd programming