jart / cosmopolitan

build-once run-anywhere c library
ISC License
17.37k stars 597 forks source link

hello-world program size regression since 2.2 (24 KB to 258 KB) #821

Open pts opened 1 year ago

pts commented 1 year ago

The getting started guide says that a hello-world program can be as small as 16 KiB. However, I'm not able to get anything smaller than 250 KB. How can I get 16 KB on Linux?

I'm a new user of Cosmopolitan. I've just downloaded and extracted https://justine.lol/cosmopolitan/cosmopolitan-tinylinux.zip, I'm using GCC 7.5.0 on Ubuntu 18.04. I'm running the commands on https://justine.lol/cosmopolitan/index.html:

$ printf %s '
  main() {
    printf("hello world\n");
  }
' >hello.c
$ gcc -g -Os -static -fno-pie -no-pie -nostdlib -nostdinc -gdwarf-4 \
  -fno-omit-frame-pointer -pg -mnop-mcount -mno-tls-direct-seg-refs \
  -o hello.com.dbg hello.c -Wl,--gc-sections -fuse-ld=bfd -Wl,--gc-sections \
  -Wl,-T,ape.lds -include cosmopolitan.h crt.o ape-no-modify-self.o cosmopolitan.a
/usr/bin/ld.bfd: warning: .note.gnu.build-id section discarded, --build-id ignored.
$ objcopy -S -O binary hello.com.dbg hello.com
$ ./hello.com
hello world
$ ls -l hello.com
-rwxrwxr-x 1 pts pts 258048 May 25 03:16 hello.com

FYI When I download the hello.com from https://justine.lol/cosmopolitan/howfat.html (https://justine.lol/cosmopolitan/howfat/hello2.v127.com) , it is indeed about 16 KB, and it works.

pkulchenko commented 1 year ago

You can try building with the provided make file:

make MODE=optlinux o/optlinux/examples/hello.com

produces 40960 binary for me,

make MODE=tiny o/tiny/examples/hello.com

produces 32768 binary for me, and

make MODE=tinylinux o/tinylinux/examples/hello.com

produces 20480 binary for me (using gcc version 11.3.0 (Ubuntu 11.3.0-1ubuntu1~22.04.1)). All work. Not exactly 16KB, but maybe close enough?

The list of modes (and their content) is available in https://github.com/jart/cosmopolitan/blob/master/build/config.mk

pts commented 1 year ago

Something's quite wrong here:

I've just downloaded https://justine.lol/cosmopolitan/cosmopolitan.tar.gz (65562747 bytes), and I'm still getting a ~250 KB hello-world:

$ make MODE=tinylinux o/tinylinux/examples/hello.com
...
$ ls -ld o/tinylinux/examples/hello.com
-rwxrwxr-x 1 pts pts 249856 May 25 05:04 o/tinylinux/examples/hello.com

During the compilation, it was running its own gcc:

$ o/third_party/gcc/bin/x86_64-linux-musl-gcc -v
...
gcc version 9.2.0 (GCC) 

Is there a known good and reproducible configuration I can try running?

pkulchenko commented 1 year ago

I'm using the master branch from this repository with a recent commit (6881a2ecea). It does use the same version of gcc as your version (o/third_party/gcc/bin/x86_64-linux-musl-gcc). I'm wondering if your version of cosmopolitan compiles binaries with blink included. It's approximately 221Kb in size, which would explain the size difference you see.

I'll have to check on how to exclude it, but at one point it was compiled in by default.

pts commented 1 year ago

Indeed, if I use https://justine.lol/cosmopolitan/cosmopolitan-amalgamation-tinylinux-2.2.zip , the hello-world program is just 24.5 KB:

$ wget -O cosmopolitan-amalgamation-tinylinux-2.2.zip https://justine.lol/cosmopolitan/cosmopolitan-amalgamation-tinylinux-2.2.zip
$ mkdir cosmopolitan-amalgamation-tinylinux-2.2
$ cd cosmopolitan-amalgamation-tinylinux-2.2
$ unzip ../cosmopolitan-amalgamation-tinylinux-2.2.zip
$ gcc -v
...
gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04) 
$ echo 'main(){printf("hello world\n");}' >hello.c
$ gcc -g -Os -static -fno-pie -no-pie -nostdlib -nostdinc -gdwarf-4   -fno-omit-frame-pointer -pg -mnop-mcount -mno-tls-direct-seg-refs   -o hello.com.dbg hello.c -Wl,--gc-sections -fuse-ld=bfd -Wl,--gc-sections   -Wl,-T,ape.lds -include cosmopolitan.h crt.o ape-no-modify-self.o cosmopolitan.a
...
$ objcopy -S -O binary hello.com.dbg hello.com
$ ls -ld hello.com
-rwxrwxr-x 1 pts pts 24576 May 25 11:43 hello.com

The file size is the same if I use GCC 9.2.0 (o/third_party/gcc/bin/x86_64-linux-musl-gcc) from the other archive.

pts commented 1 year ago

Possible action items here:

  1. Disable whatever caused the size regression since version 2.2, and make the tiny hello-world go back to 24 KB.
  2. Analyze what caused the size regression from 16 KB to 24 KB, and either fix it, or change the number to 24 KiB in the intro page on getting started guide.
  3. Set up a unit test which detects and disallows changes with such size regressions.
Wallacy commented 2 months ago

I know that is not a top priority, but what is got me on this project at first was downloading the 4KB hello world from the main site; hello2.v1.com (GNU/Systemd), hello2.v9.com (GNU + XNU) and hello2.v121.com (all except Windows and BareMetall)

For me was like: "Hell yeah, its like a better Musl"

Not exactly because the size, but because was able to static compile the very minimum necessary and still less than dynamic glibc hello world (7,5KB on my system) and much less than static musl (150KB on my machine); That's sounds that the library was very well thought to static compilation.

For my user case i will probably keep restrict the OSes because the app logic; So even with only one target i was planing to use as std lib;

But yes, my 2c here is... App size is a nice bonus here. Will be nice not "lose" that...