pts / minilibc686

libc and tools for creating size-optimized, statically linked Linux i386 and i686 programs
GNU General Public License v2.0
11 stars 0 forks source link

minilibc686: libc and tools for creating size-optimized, statically linked Linux i386 and i686 programs

minilibc686 is a minimalistic, size-optimized C runtime library (libc) targeting Linux i386 and i686, for building statically linked ELF-32 executable programs. minilibc686 is batteries-included: it contains all necessary tools (e.g. the compiler driver minicc, C preprocessor, C compiler, assembler, linker) for building size-optimized Linux i386 programs. All of the libc code of minilibc686 is written in NASM assembly language, and it is manually optimized for size (rather than speed). Feature tradeoffs were made to achieve small code sizes, so minilibc686 deviates from standard C in many aspects. In case some functionality is missing from minilibc686, with the minicc compiler fronted it's convenient to use some other supported libcs (diet libc, uClibc and EGLIBC), which are precompiled, and minicc automatically downloads each of them the first time it is needed.

Getting started

Try it on Linux i386 or Linux amd64 (without the leading $):

$ git clone --depth 1 https://github.com/pts/minilibc686
$ cd minilibc686
$ export PATH="$PWD/pathbin:$PATH"  # Add minicc to $PATH.
$ minicc -mprintf-mini -mno-envp -mconst-seg -o demo demo_c_hello.c
$ ./demo
Hello, World!
$ ls -ld demo
-rwxrwxr-x 1 pts pts 1008 Jul  5 23:28 demo
$ printf '#include <unistd.h>\nint main() { write(1, "Hello, World!\\n", 14); return 0; }\n' >demo_write.c
$ minicc -fomit-frame-pointer -o demo_write demo_write.c
$ ./demo_write
Hello, World!
-rwxrwxr-x 1 pts pts 163 Jun 21 19:12 demo_write

The first time you run minicc, it builds the static libraries libc/minilibc/libc.i386.a and libc/minilibc/libc.i686.a, using the bundled NASM (tools/nasm-0.98.39) assembler. That's why you get hundrdeds of command log lines upon your first compile.

libc size analysis

What sizes are achievable:

hello-world size comparison of different libcs:

How is this possible?

Detailed size analysis of hello-world programs

What's inside?

The following components are included in minilibc686:

Please note that minilibc686 is more like an experimental technological demo rather than a feature-complete and battle-tested libc, and it is not ready for production use, it's especially not ready for easy porting of random prewritten software. (If you need something like that, use musl with zig cc with various targets.) It's also not well-documented. However, if you start writing simple, new command-line tools for Linux, you may want to give it a try.

Related work

Other projects with tiny libc functions:

Other tiny libc projects targeting Windows:

Features

Design limitations:

An end-to-end demo for building a printf-hello-world program in NASM assembly with minilibc686, targeting Linux i386 32-bit ELF (actually i686 processors), is provided in test_demo_hello_linux.sh. For the build you need a Linux host system and NASM. NASM also does the linking with -f bin and the provided elf0.inc.nasm.

An end-to-end demo for building a printf-hello-world C program with minilibc686, targeting Linux i386 32-bit ELF (actually i686 processors), is provided in test_demo_c_hello_linux.sh. For the build you need a Linux i386 or amd64 host system. The build script uses the bundled NASM 0.98.39 assembler and the bundled TinyCC compiler, and it also autodetects GCC, and if available, builds with GCC as well. Please note that using the minicc compiler frontend is preferred (to the shell script test_demo_c_hello_linux.sh) is recommended, see the command line above.

Please note that minilibc686 is currently not ready as a general libc replacement for Linux, mostly because most of the functions haven't been written yet. If you need more functions, try minicc --diet or minicc --uclibc.

minicc

The minicc compiler frontend is a batteries-included Linux command-line tool to build small, statically linked Linux i386 programs from C source. It is part of the minilibc686 distribution (just run it as minicc from the minilib686 directory). It is bundled with several C compilers, linkers and libcs. Use it like this: ./minlibc -o prog prog.c. Try it:

Try minicc on Linux i386 or Linux amd64 (without the leading $):

$ minicc -o demo demo_c_hello.c
$ ./demo
Hello, World!

If you get command not found or similar for minicc, then you have to set up your $PATH first. Run this in the minilibc686 directory containing minicc.sh:

$ export PATH="$PWD/pathbin:$PATH"  # Add minicc to $PATH.

minicc drop-in replacement for gcc, clang, owcc (OpenWatcom C compiler) or tcc to build small, statically linked ELF-32 executables for Linux i386. Running minicc is the recommended way to build your programs using minilibc686. By default, these executables link against minilibc686, but with command-line flags (e.g. the usual -nostdlib and -nostdinc), you can specify any libc. It runs the compiler and the linker with many size-optimization flags, and it removes most unnecessary stuff from the final executable. minicc accepts the command-line flags in GCC syntax (and from that it generates OpenWatcom wcc386 syntax and others as needed).

Here is how to pick the compiler:

Here is how to pick the linker:

Here is how to pick the libc:

Here is how to make the executable program file even smaller:

Here is how to disable some default minicc functionality:

If you program doesn't compile or doesn't work with minilibc686:

How to run minicc:

Testing

minilibc686 has some unit tess. Run all of them by running ./test.sh.

The tests are in the */*.test files, which are shell scripts run by ./test.sh after creating some variables and functions.

Typically each test script file compiles the *.nasm file under test with some test code written in C (*.c), runs it, and analyzes the result.

The test framework supports reproducible tests by automatically removing all environment variables (including $PATH) and then setting some of them to known good values; and also it runs each test file in a separte, empty directory, to prevent accidental data sharing between tests.

Just like with building (./build.sh), the minilibc686 repository contains all build tools (e.g. NASM assembler, TinyCC C compiler and linker, tiny_libmaker static library creator) used by the tests, so running the tests doesn't need tools (e.g. system GCC) installed to the system. As soon as you have downloaded the repository to your Linux i386 or amd64 system, you can run ./test.sh without having to install anything.

Calling convention

Build system

License

Assembly source files src/*.nasm are under the MIT license. Everything else is under GPL v2 (GNU General Public License, Version 2).

Projects that compile with minilibc686

PCC history

Development history:

Use history:

GCC 4.x cc1 programs for Linux i686 (i386)

See download links on the release page.

All files are statically linked Linux i386 32-bit ELF executable programs built for i686 = P6 processors, stripped and then compressed with UPX (upx --best --no-lzma).

Individual GCC release dates and notes:

Please note that no other files (such as the cc1plus C++ compiler, the gcc frontend tool, the ld linker, .h files, libc static library .a files, libc shared library .so files) are provided here. To compile C programs with these compilers, use minicc at https://github.com/pts/minilibc686/; example command: minicc --gcc=4.8 -o prog prog.c. minicc will download these executables from here for you.

Compiler-specific notes

Linker problems

This section is mostly an FYI, it doesn't affter minilibc686 users directly.

TODOs

END