Re: [RFC PATCH v2 2/8] tools/nolibc: Remove .global _start from the entry point code

Willy Tarreau
2022-03-22T18:24:52Z

On Tue, Mar 22, 2022 at 11:07:17AM -0700, Nick Desaulniers wrote:
> > First, the usual static printf("hello world!\n"):
> >
> > $ ll hello-*libc
> > -rwxrwxr-x 1 willy dev 719232 Mar 22 18:50 hello-glibc*
> > -rwxrwxr-x 1 willy dev 1248 Mar 22 18:51 hello-nolibc*
>
> ! What! Are those both statically linked?

Yes:

$ file hello-nolibc
hello-nolibc: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, stripped

(rebuilding without stripping)
$ nm --size hello-nolibc
000000000000000f T main
0000000000000053 t u64toa_r
0000000000000280 t printf.constprop.0
$ nm hello-nolibc
00000000004013c5 R __bss_start
00000000004013c5 R _edata
00000000004013c8 R _end
00000000004000bf W _start
00000000004000b0 T main
0000000000400130 t printf.constprop.0
00000000004000dd t u64toa_r

> > This one supports ~30-40 simple commands (mount/unmount, mknod, ls, ln),
> > a tar extractor, multi-level braces, and boolean expression evaluation,
> > variable expansion, and a config file parser to script all this. The code
> > is 20 years old and is really ugly (even uglier than you think). But that
> > gives an idea. 20 years ago the init was much simpler and 800 bytes (my
> > constraint was for single floppies containing kernel+rootfs) and strings
> > were manually merged by tails and put in .text to drop .rodata.
>
> Oh, so nolibc has been around for a while then?

Not exactly. Over time I collected some of my stuff out of preinit to
make more reusable code for other tools, and eventually created a separate
project for it 5 years ago [1]. I then changed my mind a few times on how
to arrange all this and over time it became a bit easier to use. One day
Paul asked how to make less invasive static binaries for rcutorture and I
found that it was the perfect match so we agreed to integrate it there. It
was still a single file by then. And as usual when some code starts to get
more exposure it receives more contribs and feature requests ;-)

> ld.lld will do string merging in that fashion at -O2 (the linker can
> accept and optimization level). I did have a kernel patch for that
> somewhere, need to update it for CC_OPTIMIZE_FOR_SIZE...

Ah I didn't know, that's good to know!

> I guess the tradeoff with strings in .text is that now the strings
> themselves are r+x and not just r?

Yes but when you're writing a small shell to allow you to manually
mount your rootfs from the kernel, you don't really care if someone
might try to use some of your strings as code gadgets for ROP exploits :-)

I would really not want to see this used for general programs, but it
does fit well with hacking stuff for initramfs, and what lies in the
selftests directory in general I guess.

What I particularly like is that I don't need a full toolchain, so if
I can build a kernel with the bare-metal compilers from kernel.org then
I know I can also build my initramfs that's packaged in it using the
exact same compiler. This significantly simplifies the build process.

Willy

[1] https://github.com/wtarreau/nolibc