Coding

Fun With Apple Multi-Arch Binaries

Apple macOS has for many years supported the ability to have binaries for multiple platforms in one executable. Upon execution the correct binary data is loaded into RAM. This has multiple names such as “Universal”, “fat binary” or “Multi-Architecture Binaries”. These were really useful when Apple was transition from PowerPC to Intel CPUs, a single binary would execute on both platforms. It could be useful in the future if, as many predict, Apple move from Intel to ARM CPUs.

In this post I’ll talk about the m4 script I wrote at HP to use this feature for combined 32bit and 64bit Intel binaries (back when that was relevant).

I was working on a high-performance asynchronous C API to connect to MySQL servers around 2014 which was to be used by HP. As part of this I wanted to make it work on as many platforms as possible. Quite a few people in my division used Apple hardware so I wanted to make it work on that. At the time I had access to both 32bit and 64bit Apple hardware and wanted my binaries to work on both. Hence building this solution.

I was using autotools back then as it is my preferred build system, so after figuring out how to do it I created a script which would build a single library that simultaneously worked for x86 and x86_64 platforms. The script is as follows:

# SYNOPSIS
#
#   AX_UNIVERSAL_BINARY()
#
# DESCRIPTION
#
#   --enable-universal-binary
#
# LICENSE
#
#  Copyright 2014 Hewlett-Packard Development Company, L.P.
#  All rights reserved.
#
# [CUT BSD 3-Clause license, see SPDX-License-Identifier: BSD-3-Clause]

#serial 2

AC_DEFUN([AX_UNIVERSAL_BINARY],
    [AC_ARG_ENABLE([universal-binary],
                   [AC_HELP_STRING([--enable-universal-binary=auto],
                                   [Apple combined x86 & x86_64 binary support])],,
                   [enable_universal_binary=auto])
    have_universal_binary=no
    if test x"enable_universal_binary" != x"no"; then
        AC_CANONICAL_HOST
        AC_MSG_CHECKING([for universal binary support])
        case $host in *-apple-darwin*)
            save_CFLAGS="$CFLAGS"
            save_CXXFLAGS="$CXXFLAGS"
            save_LDFLAGS="$LDFLAGS"
            CFLAGS="$CFLAGS -arch x86_64 -arch i386"
            CXXFLAGS="$CXXFLAGS -arch x86_64 -arch i386"
            LDFLAGS="$LDFLAGS -arch x86_64 -arch i386"
            AC_LINK_IFELSE([AC_LANG_SOURCE([int main() {return 0;}])],
                          [have_universal_binary=yes])
            if test x"$have_universal_binary" = x"no"; then
                CFLAGS="$save_CFLAGS"
                CXXFLAGS="$save_CXXFLAGS"
                LDFLAGS="$save_LDFLAGS"
            fi
            ;;
        esac
        AC_MSG_RESULT($have_universal_binary)
    fi
    case "$have_universal_binary:$enable_universal_binary" in
        no:yes) AC_MSG_ERROR([no universal binary support on this host]) ;;
        yes:*)  AC_MSG_WARN([disabling dependency tracking])
                AM_CONDITIONAL([AMDEP],[false])
                AM_CONDITIONAL([am__fastdepCC],[false])
                AMDEPBACKSLASH=
                ;;
    esac])

You can see here that it first looks “Apple Darwin” which is the macOS kernel and the advertised platform. If we don’t have this then we error saying that we cannot do this.

In the compiler we specify multiple archs, in this case x86_64 and i386. The compiler knows what to do with this and we have a very simple test to build to make sure it works.

If we get this far the script disables dependency tracking. I honestly can’t remember why now (it has been 6 years) but I know dependency tracking didn’t work.

Summary

There have been attempts to do this in Linux too using a project called “FatELF“. This doesn’t appear to have taken off but I think it would be very interesting if more work was put into this. Especially with ARM and Intel both becoming major Linux platforms.

LinuxJedi

Share
Published by
LinuxJedi

Recent Posts

Upgrading the RAM Detective: A Firmware Adventure with RAMCHECK

The firmware in my RAMCHECK is very old, there were many updates since then. Unfortunately,…

1 month ago

The Ultimate RAM Detective: Meet the Innoventions RAMCHECK

Whilst repairing vintage machines, a lot of RAM passes by my benches. Most of it…

2 months ago

Vintage Speed Demon: Fixing an ARK1000VL Graphics Card

According to some, the ARK1000VL is considered the fastest VLB graphics card chip you can…

2 months ago

Using rr On Newer Intel CPUs

If, like me, you have a newer Intel hybrid CPU, with P-Cores and E-Cores, you…

2 months ago

The Legend Continues: Amiga 1000 Keyboard Revival

I have restored the boxed Amiga 1000 main unit and the mice that came with…

3 months ago

Amiga 4000 Repair: This one was just weird

I was recently sent an Amiga 4000 motherboard repair. It should have been quite straightforward,…

3 months ago