X32 is an ABI for amd64/x86_64 CPUs using 32-bit integers, longs and pointers. The idea is to combine the smaller memory and cache footprint from 32-bit data types with the larger register set of x86_64. The 64-bit registers can make computation more efficient, and with 8 additional registers available, there is less pressure compared to i386/i686.
Compared to amd64, x32 offers significant memory savings, often on the order of 30%, and modest efficiency gains.
Compared to i386, there's no memory use difference, but speed increases are more pronounced, especially in code that's under register pressure, operates on 64-bit or floating-point variables. It also avoids i386's penalty for PIC code, where EBX is essentially reserved for the Global Offset Table (GOT).
There are three principal use cases:
- vserver hosting (memory bound)
- netbooks/tablets (low memory, want performance)
- scientific tasks (want every % of performance)
The website for X32 is X32 System V Application Binary Interface. The official guide for X32 is System V Application Binary Interface, AMD64 (With LP64 and ILP32 Programming Models).
There's two ways to get X32 from Debian. First, you can run an unofficial source from Adam Borowski, which is based on work by Daniel Schepler, Thorsten Glaser and many others. If you're ok with using outside sources, then X32 unofficial repository provides a port with patches applied, and it includes Debian Installer images. The X32 image itself is a Micro-DEB (UDEB) package which part of a larger ISO with extra components. If you want to avoid the Chroot method below, then you should try the D-I image.
The second way to get X32 from Debian is to use QEMU and Chroot's. The QEMU and Chroot is roughly a lightweight Virtual Machine. It is discussed below along with common issues you may encounter.
Running X32 binaries requires Debian kernel versions 3.14.15-1 and above. Additionally, syscall.x32=y must be present on the command line when booting the kernel. To activate X32 in the default GRUB boot, edit /etc/default/grub and modify these lines:
GRUB_CMDLINE_LINUX_DEFAULT="syscall.x32=y quiet" GRUB_CMDLINE_LINUX="syscall.x32=y"
After adding the lines, be sure to update the Grub boot menu:
The X32 system will have two components. The first is the host system, and it can run any Debian 8/Jessie distribution, including Stable, Testing and Unstable. The second is the QEMU/Chroot guest, and it must run Debian 8/Jessie Unstable.
Once you're running a kernel with X32 support, you can create the X32 Chroot with the following.
apt-get install debian-ports-archive-keyring debootstrap --arch=x32 --keyring=/usr/share/keyrings/debian-ports-archive-keyring.gpg unstable /path/to/chroot http://ftp.ports.debian.org/debian-ports/
In the above command, substitute a name like debian-x32 for /path/to/chroot. If using debian-x32, then your command would be chroot debian-x32.
After you create the Chroot, enter into it with the following.
debian-host $ su - Password: ... debian-host # chroot Debian-x32 # Ready to do X32 stuff debian-chroot #
After entering the X32 Chroot for the first time, you should install the port keys and then update the software:
debian-chroot # apt-get install debian-ports-archive-keyring
The following discusses common issues when working with x32.
Failed getting release file http://ftp.ports.debian.org/debian-ports/dists/jessie/Release
If you receive a debootstrap error Failed getting release file http://ftp.ports.debian.org/debian-ports/dists/jessie/Release, then you should enable Unstable:
# From the Chroot X32 guest, not the Host # cat /etc/apt/sources.list deb http://ftp.ports.debian.org/debian-ports sid main updates
When X32 is being targeted, both X32 and x86_64 preprocessor macros are defined. To detect X32, you should use both __ILP32__ and __x86_64__ rather than __amd64__, __x86_64__ or __LP64__. From the System V Application Binary Interface, AMD64 (With LP64 and ILP32 Programming Models), Chapter 7, Development Environments, p. 104:
DEFINE | DESCRIPTION ==================================================================== __amd64 | Defined for both LP64 and ILP32 programming models. __amd64__ | Defined for both LP64 and ILP32 programming models. __x86_64 | Defined for both LP64 and ILP32 programming models. __x86_64__ | Defined for both LP64 and ILP32 programming models. _LP64 | Defined for LP64 programming model. __LP64__ | Defined for LP64 programming model. _ILP32 | Defined for ILP32 programming model. __ILP32__ | Defined for ILP32 programming model.
You should use both __ILP32__ and __x86_64__ because Clang and Solaris' Sun Studio compilers always defines __ILP32__ under the 32-bit data model, even for i386 builds. Additionally, __ILP32__ may be present on some AARCH64/ARM64 builds. While Clang and SunCC are not GNU free software, it benefits all users when free software works as expected everywhere as it takes over the world!
This typically manifests with an error like:
/bin/bash ../libtool --tag=CC --mode=link gcc -I/usr/include/dbus-1.0 -I/usr/lib/x86_64-linux-gnux32/dbus-1.0/include -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnux32/glib-2.0/include -pthread -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnux32/glib-2.0/include -I/usr/include/gtk-2.0 -I/usr/lib/x86_64-linux-gnux32/gtk-2.0/include -I/usr/include/atk-1.0 -I/usr/include/cairo -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/pango-1.0 -I/usr/include/gio-unix-2.0/ -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng12 -g -O2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security -Wall -g -version-info 100:6:100 -export-dynamic -export-symbols-regex "^unique.*" -rpath /usr/lib -no-undefined -Wl,-z,relro -Wl,-z,defs -Wl,-O1 -Wl,--as-needed -o libunique-1.0.la -rpath /usr/lib uniqueapp.lo uniquebackend.lo uniquemessage.lo uniqueenumtypes.lo uniquemarshal.lo ../unique/bacon/libunique-bacon.la ../unique/dbus/libunique-dbus.la -lgtk-x11-2.0 -lgdk-x11-2.0 -latk-1.0 -lgio-2.0 -lpangoft2-1.0 -lpangocairo-1.0 -lgdk_pixbuf-2.0 -lcairo -lpango-1.0 -lfreetype -lfontconfig -lgobject-2.0 -lglib-2.0 -lX11 -ldbus-glib-1 -ldbus-1 -lgobject-2.0 -lglib-2.0 ../libtool: line 7510: test: : integer expression expected ../libtool: line 7510: test: : integer expression expected ../libtool: line 7615: test: : integer expression expected ../libtool: line 7687: test: : integer expression expected ../libtool: line 7687: test: : integer expression expected ../libtool: line 7687: test: : integer expression expected ../libtool: line 7687: test: : integer expression expected libtool: link: /usr/bin/ld -m elf_i386 -r -o .libs/libunique-1.0.la-1.o .libs/uniqueapp.o /usr/bin/ld: Relocatable linking with relocations from format elf32-x86-64 (.libs/uniqueapp.o) to format elf32-i386 (.libs/libunique-1.0.la-1.o) is not supported make: *** [libunique-1.0.la] Error 1 make: Leaving directory `/tmp/buildd/libunique-1.1.6/unique' make: *** [all-recursive] Error 1 make: Leaving directory `/tmp/buildd/libunique-1.1.6/unique' make: *** [all] Error 2 make: Leaving directory `/tmp/buildd/libunique-1.1.6/unique' make: *** [all-recursive] Error 1 make: Leaving directory `/tmp/buildd/libunique-1.1.6' make: *** [all] Error 2 make: Leaving directory `/tmp/buildd/libunique-1.1.6' make: *** [debian/stamp-makefile-build] Error 2 dpkg-buildpackage: error: debian/rules build gave error exit status 2
Note the "-m elf_i386", which should be "-m elf32_x86_64" on X32. The fix is to re-libtoolize with libtool version at least 2.4.2-1.2 from sid. If you prefer to use something like dh_autoreconf to do this at build time, so much the better.
Use of sysctl(2)
The error message from this typically looks something like:
gcc -o jemalloc.o -c -DOSTYPE=\"Linux3\" -DOSARCH=Linux -I../../../memory/jemalloc -I. -I../../dist/include -I../../dist/include/nsprpub -I/usr/include/nspr -I/usr/include/nss -fPIC -D_FORTIFY_SOURCE=2 -Wall -W -Wno-unused -Wpointer-arith -Wdeclaration-after-statement -Wcast-align -W -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security -fno-strict-aliasing -pthread -ffunction-sections -fdata-sections -pipe -DNDEBUG -DTRIMMED -g -Os -freorder-blocks -fomit-frame-pointer -D_FORTIFY_SOURCE=2 -include ../../mozilla-config.h -DMOZILLA_CLIENT -MD -MF .deps/jemalloc.pp /tmp/buildd/iceweasel-10.0.11esr/memory/jemalloc/jemalloc.c In file included from /usr/include/x86_64-linux-gnux32/sys/sysctl.h:79:0, from /tmp/buildd/iceweasel-10.0.11esr/memory/jemalloc/jemalloc.c:327: /usr/include/x86_64-linux-gnux32/bits/sysctl.h:19:3: error: #error "sysctl system call is unsupported in x32 kernel"
The sysctl(2) interface is unmaintained and deprecated even on architectures where it's currently provided, so it's better to update the code to read or write from the corresponding /proc/sys/kernel/* file directly.
If your code uses inline assembly based on #ifdef __x86_64__ or #ifdef __amd64__, etc., these conditions will also be triggered on X32 builds. Some of the time this will work properly; however, if some of the inputs or outputs of the assembly fragment are of pointer or long types, you might get operand size mismatches like this:
/tmp/buildd/php5-5.4.4/ext/standard/math.c: Assembler messages: /tmp/buildd/php5-5.4.4/ext/standard/math.c:628: Error: incorrect register `%esi' used with `q' suffix /tmp/buildd/php5-5.4.4/ext/standard/math.c:629: Error: incorrect register `%edx' used with `q' suffix /tmp/buildd/php5-5.4.4/ext/standard/math.c:632: Error: incorrect register `%edx' used with `q' suffix /tmp/buildd/php5-5.4.4/ext/standard/math.c:633: Error: incorrect register `%esi' used with `q' suffix make: *** [ext/standard/math.lo] Error 1
Depending on the situation, you might be able to get by with just removing explicit "q" suffixes from the opcodes and letting the GNU assembler infer the correct size suffix. Otherwise, you can distinguish between regular amd64 and X32 by testing if __ILP32__ is defined. (Note that it's recommended to use __ILP32__ rather than __LP64__.
If you are interacting with the stack, then you might receive an Error: invalid operand size for a push or a pop. In this case, you have to push or pop a 64-bit register even though ILP32 uses 32-bit integers, longs and pointers. For example:
#if __x86_64__ || (__x86_64__ && __ILP32__) "pushq %rbx \n" #else /* i386 */ "pushl %ebx \n" #endif ... #if __x86_64__ || (__x86_64__ && __ILP32__) "popq %rbx \n" #else /* i386 */ "popl %ebx \n" #endif
When utilizing assembly to access Intel and AMD's rdrand instruction (or Intel's rdseed instruction), you can issue the 64-bit version of the instruction (i.e., with the REX.W modifier), and then copy 8-bytes at a time to the caller.
Updating the X32 environment
Once you enter the X32 environment via chroot debian-x32, issuing apt-get update may result in an error similar to:
GPG error: http://ftp.ports.debian.org/debian-ports/ unstable InRelease: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY A53AB45AC448326E
The fix is to install the debian-ports-archive-keyring in the X32 environment (in addition to the host's environment):
apt-get install debian-ports-archive-keyring
If you have debian-ports-archive-keyring installed and debootstrap provides an error:
I: Checking Release signature E: Release signed by unknown key (key id B4C86482705A2CE1)
Then you need to either (1) ensure you are using the ports repository at http://ftp.ports.debian.org/debian-ports; or (2) enable Unstable, and not Stable.
linux-thread-db.c and internal error
You might experience an error similar to the following when running GDB:
(gdb) r Starting program: .../cryptest.exe warning: linux_ptrace_test_ret_to_nx: Cannot PTRACE_PEEKUSER: Input/output error /build/gdb-gaG2aU/gdb-7.10/gdb/linux-thread-db.c:1675: internal-error: find_new_threads_once: Assertion `!target_has_execution || thread_db_use_events ()' failed. A problem internal to GDB has been detected, further debugging may prove unreliable. Quit this debugging session? (y or n)
This is a known issue for C++ programs and GDB 7.10; see Debian Issue #799556: GDB cannot debug a program on the X32 platform (internal-error: find_new_threads_once...). The fix is to comment out the assert in gdb/linux-thread-db.c, around line 1675:
/* See comment in thread_db_update_thread_list. */ /* gdb_assert (!target_has_execution || thread_db_use_events ()); */
gdb_static_assert (sizeof (nat_siginfo_t) == sizeof (siginfo_t))
If you attempt to build GDB 7.11.1 under X32, then you may encounter the static assert below. If so, please visit Bug 20287: "gdb_static_assert (sizeof (nat_siginfo_t) == sizeof (siginfo_t))".
gcc -g -O2 -I. -I. -I./common -I./config -DLOCALEDIR="\"/usr/local/share/locale\"" <other flags> -c -o amd64-linux-siginfo.o -MT amd64-linux-siginfo.o -MMD -MP -MF .deps/amd64-linux-siginfo.Tpo ./nat/amd64-linux-siginfo.c In file included from ./common/common-defs.h:71:0, from ./nat/amd64-linux-siginfo.c:21: ./common/gdb_assert.h:26:14: error: size of array 'never_defined_just_used_for_checking' is negative extern int never_defined_just_used_for_checking[(expr) ? 1 : -1] ^ ./nat/amd64-linux-siginfo.c:113:1: note: in expansion of macro 'gdb_static_assert' gdb_static_assert (sizeof (nat_siginfo_t) == sizeof (siginfo_t)); ^ Makefile:2370: recipe for target 'amd64-linux-siginfo.o' failed make: *** [amd64-linux-siginfo.o] Error 1
There is no mailing list dedicated to the X32 platform. According to Would like a ports mailing list for x32, questions and discussions should be held on the debian-amd64 list.
You can find a comprehensive list of available Debian mailing lists at Debian Mailing Lists (Complete Index).
I am currently using the usertag user firstname.lastname@example.org for all X32-related bug reports. (I've requested such a mailing list, but it hasn't been created yet.) Some of the tags I'm currently using, or may use in the near future, include:
port-x32 as a catch-all tag applied to all such bugs.
ftbfs-gnulib for packages which FTBFS because of an out-of-date version of gnulib.
ftbfs-eglibc2-16 for packages which have more general issues building under eglibc 2.16, but still not specific to X32.
ftbfs-libtool for packages which FTBFS because of an out-of-date version of libtool.
di-x32 for debian-installer stuff.
ftbfs-x32 for X32-specific build failures not covered by one of the above.