Skip to content
Adrian Perez edited this page Mar 13, 2017 · 4 revisions

Certain 64-bit applications may include and execute 32-bit programs, therefore needing a mixed “multiarch” userland. By default the sandbox disallows running 32-bit programs; the restriction can be lifted by finishing the build with --allow=multiarch. While it is recommended to avoid packaging together mixed 64-bit and 32-bit binaries, this might not always be possible when:

  • The application uses binaries originally not built with the application (e.g. downloaded from the network, or supplied by the user), which might be 32-bit.
  • The application is 64-bit, and it uses 32-bit binaries for which the source code is not available.

Using --allow=multiarch is strongly discouraged, and should be avoided whenever possible: it is preferred to build applications from source, or to avoid mixing binaries.

Static 32-bit executables

These only need --allow=multiarch to work.

Dynamic 32-bit executables

Trying to execute 32-bit dynamic executables works normally when using --allow=multiarch: the kernel will check the value of the PT_INTERP entry in the ELF program header, which contains the path to the interpreter used to load the program. This typically contains a platform-dependent string with the path of the dynamic linker:

Architecture Typical Values
x86 /lib/ld-linux.so.2
ARM /lib/ld-linux.so.3, /lib/ld-linux-armhf.so.3

The dynamic linker will, among other things, read the DT_NEEDED entries from the dynamic tags ELF section, locate the libraries (shared objects) listed, load them, and relocate them to make their code usable by the program being loaded. Flatpak itself makes no effort at providing either, and it is up to packagers to provide the needed files at suitable locations.

Also, note that in general the readily available runtimes and SDKs do not include any support for mixed binaries, and if you want to use these your only option is bundling the needed files with your application.

Bundled 32-bit runtime

When the set of 32-bit binaries are known at build time, the simplest solution is to provide the needed 32-bit libraries as part of the application bundle, and modify the binaries to point to the dynamic linker at /app/: The binary will contain the string with dynamic linker path (e.g. /lib/ld-linux.so.2 for x86, see table above for other platforms; usually somewhere in its first kilobyte), and can modified it with a hex editor to replace the /lib prefix with /app. This way the replaced string has the same length, and no other values in the ELF header need to be modified. Once modified, install the binaries normally under /app/bin.

As for the shared objects (libraries) needed at runtime, the built application bundle should include:

  • Dynamic linker. It must be directly under /app instead of the “usual” /app/lib due to the modification done to the headers of ELF executables (e.g. /app/ld-linux.so.2 for x86, see table above for other platforms).
  • Libraries needed by the program under, including the C library (usually this will be glibc), libgcc and the rest of the libraries listed in the ELF header of the executables (use readelf -d to list the DT_NEEDED entries from the header). There are two options:
    • /app/lib: Flatpak automatically arranges this location to be searched for libraries. Having mixed 32-bit and 64-bit libraries is possible, as long as their file names do not clash.
    • Separate directory for 32-bit libraries, typically /app/lib32: The directory path must be added to the LD_LIBRARY_PATH environment variable with --env=LD_LIBRARY_PATH=… when finishing the build.

Mixed runtime

If building and using a custom runtime/SDK is acceptable (or already being done), it can be made to include the 32-bit libraries. As a bare minimum, it should include the C library (typically glibc) and a copy of the dynamic linker in the usual location (e.g. /lib/ld-linux.so.2 for x86, see table above for other architectures). Application-specific libraries can be provided under /app/lib or under a custom subdirectory like /app/lib32 and adjusting LD_LIBRARY_PATH accordingly (see the previous section).

This approach might be desirable when there is a sizeable number of application bundles which will use a common set of 32-bit libraries: application bundles will be smaller, and the burden on application packagers is smaller.

64-bit ready runtime

Similar to the mixed runtime approach, but instead of providing 32-bit libraries within the runtime/SDK, a dangling symbolic link is added at the location where the dynamic linker is expected to be (/lib/ld-linux.so.2 for x86, see table above for other architectures), pointing to a location under /app (e.g. pointing to /app/lib/ld-linux.so.2). From this point on, the application bundles are responsible of providing the 32-bit dynamic linker, basic user space libraries, and the additional libraries needed by the application.

This approach might be desirable when there is a few application bundles using 32-bit libraries, as it does not add weight to the runtime, at the cost of slightly increasing the burden on application packagers.