Other Why are FreeBSD binaries smaller than Linux ones?

Just out of curiosity (or maybe it matters?), does anyone know why binaries on FreeBSD are smaller than on Linux? There are something like 30-40% smaller (counting using du -s <path>)! That's crazy! We are talking about the exact same programs that have the exact same capabilities!

Making some analysis myself, I found out (using readelf --segments <path>) that binaries on freebsd have fewer segments than those of linux. I don't know why that's the case, but it at least gives me an idea.

However, to add more, using size -dA <path> to count the size for each segments, it seems that the same segments on freebsd programs, are smaller than the equivalent ones on the linux programs. Hmm....

I have not check every program and library. Just a few of them. And the only program that was actually bigger on freebsd than on linux was "Xorg" (another reason to root for Wayland, lol!). Tho, when checking their segment sizes with size -dA <Xorg_path>, it actually reports a smaller "total" for freebsd.

Yeah, I'm confused... and very curious!
 
You could try running strings <command>. I just did on ls, on FreeBSD-14.0 and RockyLinux 8.9. I ran
strings /usr/bin/ls |wc -l on Linux and it showed 1610 lines vs running strings on /bin/ls in FreeBSD which showed 266 lines.

I'm not a coder or programmer so I couldn't make much sense of the output, but if you're a programmer, that might make the reasons more clear. It seems, from my unknowledgeable point of view, that the Linux version had a lot of unneeded cruft, but as I said, I don't have much knowledge about it.
 
Here is a counterexample of the same program compiled for both OSes, GNU make:
Code:
FreeBSD:
   text    data     bss     dec     hex filename
 245902    5320   17232  268454   418a6 /usr/local/bin/gmake
Linux:
   text    data     bss     dec     hex filename
 222901    7844   14552  245297   3be31 /usr/bin/make

The substantially larger data size on Linux is curious.
 
You could try running strings <command>. I just did on ls, on FreeBSD-14.0 and RockyLinux 8.9. I ran
strings /usr/bin/ls |wc -l on Linux and it showed 1610 lines vs running strings on /bin/ls in FreeBSD which showed 266 lines.

I'm not a coder or programmer so I couldn't make much sense of the output, but if you're a programmer, that might make the reasons more clear. It seems, from my unknowledgeable point of view, that the Linux version had a lot of unneeded cruft, but as I said, I don't have much knowledge about it.
Thanks, I didn't know about this program! Reading it, it seems to be printing the printable characters so, this will be any data constant that (like the name says) can be printed. Of course, I expect the system utilities to be different as they are different for every OS, but I was measuring 3rd party programs like "git" or "gtk" and they also have different sizes so, weird...
 
FreeBSD uses LLVM to build its whole userland, while most Linux distributions still use GCC for that.

FreeBSD uses its own version of libc instead of GNU libc.

Two important contributors to the differences.

It did try to search online for "GCC vs Clang" and there doesn't seem to be any binary difference. And If I remember correctly, I have also tried to compile QBE in the past with both GCC and Clang and the file sizes were the same. Even if it makes any difference, it would be in the code generation some I don't expect anything more than some bytes...
 
Lots of fat binaries like Snap packs and flat packs etc where all the dependencies are included rather than using shared objects.

Oh, no no! I was comparing apples with apples. Specifically, 3rd party apps and libraries like "git", "gtk", "meld" and in general, nothing that should be different across OSes.
 
Here is a counterexample of the same program compiled for both OSes, GNU make:
Code:
FreeBSD:
   text    data     bss     dec     hex filename
 245902    5320   17232  268454   418a6 /usr/local/bin/gmake
Linux:
   text    data     bss     dec     hex filename
 222901    7844   14552  245297   3be31 /usr/bin/make

The substantially larger data size on Linux is curious.
Random commandline binaries on Linux usually have more commandline options than their BSD equivalent.

Good thought but like I said above, I was comparing 3rd party apps and libraries that should be exactly the same in every OS, except system calls of course but, in the case of FreeBSD and Linux, these will mostly only be thread spawning and other rare stuff. So, I wasn't expecting such a big difference...
 
Specifically, 3rd party apps and libraries like "git", "gtk", "meld" and in general, nothing that should be different across OSes.
Isn't meld a python app?

Also, the size comparison would need to specify what size was compared. File size on media? Runtime memory image?
Are these binaries stripped? Gcc is pretty talkaktive with the debug information, maybe that is the reason? Many of the symbols are kept in, for the sake of readable backtraces.
 
While I don't know where the differences stem from, FreeBSD binaries/libs aren't always smaller (but most of the time are). When working on my UE4/5 ports, for a while I expected that my libs didn't have the correct code as the (supplied) Linux counterparts due to sometimes massive size differences.
From comparison I also found out that sometimes the Linux binaries would be considerably smaller. I would give a few examples, but sadly my dev disk was wiped by hackers and I haven't restored that stuff yet.
 
Isn't meld a python app?

Also, the size comparison would need to specify what size was compared. File size on media? Runtime memory image?
Are these binaries stripped? Gcc is pretty talkaktive with the debug information, maybe that is the reason? Many of the symbols are kept in, for the sake of readable backtraces.

Ok, let's forget "meld". But I'm pretty sure "git" and "gtk" are C apps (so, binary). Same with Xorg and some others I tried but don't remember.

Maybe it's about debug symbols, Idk. But like I said, every section is bigger in the Linux version. Debug symbols are added in their own sections so, I would understand that. But nope, the same sections are bigger on Linux and then, plus the extra ones that it has over FreeBSD.
 
While I don't know where the differences stem from, FreeBSD binaries/libs aren't always smaller (but most of the time are). When working on my UE4/5 ports, for a while I expected that my libs didn't have the correct code as the (supplied) Linux counterparts due to sometimes massive size differences.
From comparison I also found out that sometimes the Linux binaries would be considerably smaller. I would give a few examples, but sadly my dev disk was wiped by hackers and I haven't restored that stuff yet.
Thank you for the information and I'm very sorry about your disk my friend!
 
I compiled gmake on FreeBSD with both gcc and llvm and the difference was minimal, much less than what we see in FreeBSD vs. Linux.
 
I compiled gmake on FreeBSD with both gcc and llvm and the difference was minimal, much less than what we see in FreeBSD vs. Linux.

As expected. Same thing that happened for my under Linux. It is an operating system thing but, I do wonder what....
 
It did try to search online for "GCC vs Clang" and there doesn't seem to be any binary difference. And If I remember correctly, I have also tried to compile QBE in the past with both GCC and Clang and the file sizes were the same. Even if it makes any difference, it would be in the code generation some I don't expect anything more than some bytes...
Maybe, but you are still neglecting that most Linux distributions do use GNU libc, while FreeBSD has its own libc which uses a completely different code base.
 
Maybe, but you are still neglecting that most Linux distributions do use GNU libc, while FreeBSD has its own libc which uses a completely different code base.

Yeah, but libc is dynamically linked in both cases. So the library itself can't be responsible for the size difference. Maybe data structures dependent on include files, but I don't think so either.
 
Yeah, actually using things from libc makes the binary (without the actual libc) about 5% bigger in Linux. Also the object file.
 
I did some more checks, and folks - the difference is in the used tool chains, more specifically in the linker C uses. GCC normally uses GNU ld by default, and has the option to use other linkers (BFD, gold, mold, LLD) as well.

LLVM on the other hand users lld by default.

Here we go, using a simple "Hello World" program.

Code:
void main()
{
    printf("Hello World.\n");
}

Compiled with GCC 12.2.0 under recent Debian, standard parameters: 15925 bytes unstripped.

Compiled with same setup, but LLD linker instead (gcc hello.c -o hello -fuse-ld=lld): 5928 bytes unstripped.

Compiled with standard tool chain under FreeBSD 14.0-RELEASE: 9664 bytes unstripped.

So its the linker, baby!
 
Well, here we are, using GCC on Debian Linux again:

name
type
size​
hello-ld​
file​
15.1 KiB​
hello-ld-stripped​
file​
14.1 KiB​
hello-lld​
file​
5.4 KiB​
hello-lld-stripped​
file​
4.6 KiB​
hello.c​
file​
46 B​
 
I did some more checks, and folks - the difference is in the used tool chains, more specifically in the linker C uses. GCC normally uses GNU ld by default, and has the option to use other linkers (BFD, gold, mold, LLD) as well.

LLVM on the other hand users lld by default.

Here we go, using a simple "Hello World" program.

Code:
void main()
{
    printf("Hello World.\n");
}

Compiled with GCC 12.2.0 under recent Debian, standard parameters: 15925 bytes unstripped.

Compiled with same setup, but LLD linker instead (gcc hello.c -o hello -fuse-ld=lld): 5928 bytes unstripped.

Compiled with standard tool chain under FreeBSD 14.0-RELEASE: 9664 bytes unstripped.

So its the linker, baby!
Now strip the binaries and check again.

Nice test! I thought about testing this but with a real program, like QBE (git version), using clang and lld, version 17 on both FreeBSD and Linux.

The modified C and linker flags are the followings:
Bash:
CC       = clang17
CFLAGS   = -std=c99 -O3 -Wall -Wextra -Wpedantic -march=native -fno-asynchronous-unwind-tables
LDFLAGS  = -Xlinker -O2 -Xlinker -s -Xlinker -S -Xlinker -gc-sections -fuse-ld=lld17

The results are the following:

File sizes (counted with `du -sh qbe`):

Unstriped:

FreeBsd:
141K
Linux: 216K

Striped:

FreeBsd:
137K
Linux: 204K
 
I did some more checks, and folks - the difference is in the used tool chains, more specifically in the linker C uses. GCC normally uses GNU ld by default, and has the option to use other linkers (BFD, gold, mold, LLD) as well.

LLVM on the other hand users lld by default.
Compiled with GCC 12.2.0 under recent Debian, standard parameters: 15925 bytes unstripped.

Compiled with same setup, but LLD linker instead (gcc hello.c -o hello -fuse-ld=lld): 5928 bytes unstripped.

Compiled with standard tool chain under FreeBSD 14.0-RELEASE: 9664 bytes unstripped.

So its the linker, baby!
Well, here we are, using GCC on Debian Linux again:
I thought about testing this but with a real program, like QBE (git version), using clang and lld, version 17 on both FreeBSD and Linux.
FreeBSD version 10 released in 2014, for certain architectures, started using LLVM/Clang, and versions of FreeBSD before that used GCC. Gradually since then, other parts of the GCC toolchain were replaced. I wonder what's the comparison of GCC to LLVM with the GNU LD and LLD linkers on a recent FreeBSD?

https://www.freebsd.org/releases/
 
Back
Top