Discussion:
Making a Fat Binary for Linux and Mac
(too old to reply)
Frederick Gotham
2020-10-22 10:47:53 UTC
Permalink
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".
Ralf Fassel
2020-10-22 16:05:50 UTC
Permalink
* Frederick Gotham <***@gmail.com>
| dd if="$0" of=/tmp/binaryfile bs=1 skip=${skip} count=${count} > /dev/null 2>&1

Nitpick: use mktemp(1), or at least something along these lines to
create the temporary file and remove it after use:

cleanup () {
rm -f "$TMPFILE"
exit $1
}
TMPFILE=${TMPDIR:-/tmp}/foobar.$$
trap "cleanup 1" 1 2 15

dd ... of="$TMPFILE" ...

TNX
R'
Keith Thompson
2020-10-22 18:05:03 UTC
Permalink
Post by Frederick Gotham
I have an idea for making a 'fat binary' that doesn't require any kernel
support on Linux or Mac.
[...]

This is the third time I've seen this article. You also posted it
to comp.lang.c and comp.lang.c++, where it's not topical because
it doesn't even mention the C or C++ programming language.

If you insist on posting to multiple newsgroups, please cross-post
(post a single article with multiple newsgroups in the "Newsgroups:"
header line). That way most newsreaders will mark the article
as read the first time the reader sees it, and not show it in the
other newsgroups.

Better yet, pick a single newsgroup where it's topical and post it
only there.
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+***@gmail.com
Working, but not speaking, for Philips Healthcare
void Void(void) { Void(); } /* The recursive call of the void */
Loading...