Fat Binary for Linux and Mac without kernel support

Frederick Gotham cauldwell.thomas at gmail.com
Thu Oct 22 11:41:04 UTC 2020


I have an idea for making a 'fat binary' that doesn't require any kernel
support on Linux or Mac.

So let's say we start off with a small shell script like this:

    #!/bin/sh

    arch=`uname -m`

    if [ $arch = "x86_64" ] ; then
        // Do something
    elif [ $arch = "aarch64" ] ; then
        // Do something
    fi

    exit 0

The most important line is the last one "exit 0" because it will stop
the script. It is after this line that I will put the x86_64 binary,
followed by the aarch64 binary, so the script will look something like
this:

    #!/bin/sh

    arch=`uname -m`

    if [ $arch = "x86_64" ] ; then
        skip=00290
        count=08816
    elif [ $arch = "aarch64" ] ; then
        skip=09106
        count=14688
    else
        exit 1
    fi

    dd if="$0" of=/tmp/binaryfile bs=1 skip=${skip} count=${count} >
/dev/null 2>&1

    chmod +x /tmp/binaryfile
    /tmp/binaryfile

    exit 0
    [ - - -  x86_64 binary goes here - - - ]
    [ - - - aarch64 binary goes here - - - ]

So as a test program to try it out, I'll now write a small C++ program
that prints a number sequence:

    #include <iostream>  /* cout, endl */
    #include <thread>    /* this_thread::sleep_for */
    #include <chrono>    /* seconds */

    auto main(void) -> int
    {
        for ( unsigned i = 0; /* ever */ ; ++i )
        {
            std::this_thread::sleep_for(std::chrono::seconds(1u));
            std::cout << i << std::endl;
        }
    }

I have compiled this program for two architectures:

                      g++ main.cpp -DNDEBUG -Os -o prog_x86_64
    aarch64-linux-gnu-g++ main.cpp -DNDEBUG -Os -o prog_aarch64

and so I have two binaries as follows:

    -rwxr-xr-x 1 root root  8816 Oct 22 10:53 prog_x86_64
    -rwxr-xr-x 1 root root 14688 Oct 22 10:52 prog_aarch64

The  x86_64 binary is  8816 bytes.
The aarch64 binary is 14688 bytes.

So now I get the size of my small script above:

    -rwxr-xr-x 1 root root 290 Oct 22 11:31 myscript.sh

It is 290 bytes, which means I know how much to skip by:

    dd if="$0" of=/tmp/binaryfile bs=1 skip=00290 count=08816

Finally I concatenate the 3 files:

    cat myscript.sh prog_x86_64 prog_aarch64 > fatbin

And I run my fat binary:

    chmod +x fatbin
    ./fatbin

I've tried this 'fatbin' file on both architectures and it works. You
can download the files here and try it yourself:

	http://virjacode.com/experimental/prog.cpp
	http://virjacode.com/experimental/prog_aarch64
	http://virjacode.com/experimental/prog_x86_64
	http://virjacode.com/experimental/myscript.sh
	http://virjacode.com/experimental/fatbin
	
I think it might even be possible to extend this script so that it
doubles as a batch file for Microsft Windows, so maybe we could have two
Linux binaries, a Mac binary, as well as a Microsoft binary all in one
file. It can made threadsafe and re-enterable by using system-supplied
temporary filenames or UUID's instead of "/tmp/binaryfile".



More information about the Ubuntu-devel-discuss mailing list