Home

X32 System V Application Binary Interface

A 32-bit psABI for x86-64 with 32-bit pointer size.

Action items

Site activity feed

Important dates

News

    • Ubuntu 13.04 added x32 support.

  • GCC 4.8.0 has been released with address size prefix improvement. GCC 4.8 is the recommended minimum version of GCC for x32.

    • X32 support is checked into GDB 7.5.

    • X32 support is checked into GLIBC 2.16.

    • X32 support is checked into Linux kernel 3.4.

    • Updated x32 psABI to document predefined pre-processor symbols, _ILP32 and __ILP32__, for X32 programming model.

    • Updated x32 psABI to add TLS specification for x32.

    • I updated glibc x32 branches to restore unsigned long int on uc_flags in struct ucontext in <sys/ucontext.h>.

    • Backported the upstream patch to drop sys32_rt_sigprocmask to hjl/x32/lfs/v3.0, hjl/x32/lfs/v3.1 and hjl/x32/lfs/v3.2 branches. MUST RECOMPILE GLIBC WITH THE NEW KERNEL HEADER FILES since the x32 system call numbers are changed. I also updated hjl/x32 and hjl/4.6/x32 branches in x32 git repository to adjust system calls.

    • Reverted the previous MTRR header bug fix and installed a new fix to hjl/x32/lfs/v3.0, hjl/x32/lfs/v3.1 and hjl/x32/lfs/v3.2 branches.

    • Updated x32 psABI to document predefined pre-processor symbols, _LP64 and __LP64__, for LP64 programming model.

    • Fixed the MTRR header bug and 4 64bit time_t kernel bugs on hjl/x32/lfs/v3.0 and hjl/x32/lfs/v3.1 branches:

      • X server works in qemu.

      • We need help to update compat ioctl layer to support ioctl commands with struct size lile:

        • #define IOCTL_COMMAND _IOR('o', 28, struct ioctl_arg)

        • They are in

drivers/media/video/v4l2-compat-ioctl32.c

fs/compat_ioctl.c

fs/xfs/xfs_ioctl32.c

fs/xfs/xfs_ioctl32.h

sound/core/pcm_compat.c

sound/core/rawmidi_compat.c

sound/core/timer_compat.c

        • When "struct ioctl_arg" contains fields of "struct timeval/timespec" and long/pointer, its size is from regular 32bit "struct ioctl_arg" since "struct timeval/timespec" are 2x64bit for x32 and 2x32bit for regular 32bit targets. One way to solve is for each such command, we add a new compat function to support 64bit time_t.

        • Some ioctl commands also take time_t, like PPPIOCGIDLE.

    • Implemented the address size prefix on hjl/x32/addr32 branch.

    • Backported x32 support to GCC 4.6.

    • Backported x32 support to glibc 2.14, 2.13, 2.12 and 2.11:

    • Since glibc 2.11 is the first x32 release now, the x32 minimum ABI is changed from GLIBC_2.14 to GLIBC_2.11, which require recompiling all existing x32 binaries.

    • X32 kernel uses the 64bit filesystem interface (LFS) as well as 64bit time_t. They are on hjl/x32/lfs/v3.0 and hjl/x32/lfs/v3.1 branches.

    • As of revision 177914, all x32 changes have been merged with GCC trunk.

    • Update x32 psABI to add R_X86_64_RELATIVE64 relocation for x32.

    • Update x32 psABI to allow R_X86_64_64 relocation.

    • Update x32 psABI to specify that pointers are zero-extended to 64bit when returned or passed in a register.

    • The preliminary system call number scheme is:

      • In kernel, x86-64 and x32 share the same system call slot if they are the same.

      • First 512 system call slots are reserved for common and x86-64 specific ones. X32 specific system call slots start at 512.

      • All x32 system call numbers have the bit 30 set.

      • This scheme is implemented on hjl/x32/syscall/v3.0 kernel branch.

Current Status

    • X32 psABI draft is in Project Documents and it is also available on hjl/x32/master branch from:

https://github.com/hjl-tools/x86-psABI

    • The GNU binutils support is available in binutils 2.22:

http://www.sourceware.org/binutils/

Gold on trunk also supports x32.

    • Linux kernel 3.4 supports x32, which can be enabled by setting CONFIG_X86_X32=y in .config.

      • You should use 3.6 or newer due to some syscall changes (otherwise dhcp won't work)

    • GDB support has been checked into GDB 7.5.

    • X32 support has been merged into GLIBC master branch. The backport for GLIBC 2.15 is on hjl/x32/release/2.15 branch at

http://sourceware.org/git/?p=glibc.git;a=summary

    • X32 is functional complete with C, C++, Objective C and Fortran on GCC trunk as of revision 177914. The backport to GCC 4.6 is on hjl/x32/gcc-4_6-branch at

http://gcc.gnu.org/git/?p=gcc.git;a=summary

The address size prefix is implemented on trunk and has been backported to hjl/x32/gcc-4_7-branch.

Related work:

    • J. Liu and Y. Wu. Performance characterization of the 64-bit x86 architecture from compiler optimizations’ perspective. In Proceedings of the International Conference on Compiler Construction, CC’06, 2006

http://www.springerlink.com/index/521324472703w117.pdf

Comparison

    • Test machines:

      • Fedora 17/x86-64

        • kernel-3.3.7-3.0

        • glibc-2.15-37.0

    • 181.mcf from SPEC CPU 2000 (memory bound):

      • Intel Core i7

        • ~40% faster than x86-64.

        • ~2% slower than ia32.

      • Intel Atom

        • ~40% faster than x86-64.

        • ~1% faster than ia32.

    • 186.crafty from SPEC CPU 2000 (64bit integer):

      • Intel Core i7

        • ~3% faster than x86-64.

        • ~40% faster than ia32.

      • Intel Atom

        • ~4% faster than x86-64.

        • ~26% faster than ia32.

X32 ABI

    • X32 ABI is designed for environments where the current ia32 ABI is sufficient. It can be viewed as ia32 with register extended to 64-bit plus 8 more registers as well as IP relative address. Everything else is still 32-bit.

    • X32 kernel interface is implemented with "syscall" instruction.

      • Use the same 64-bit system calls with 64bit arguments:

        • Both 64-bit and unsigned 32-bit values can be passed in 64bit argument.

Compiling for x32

    • The target tuple is the same as an x86_64 system. e.g. x86_64-linux

    • The toolchain will support both x86_64 and x32 binaries. The default is still x86_64, but x32 support can be selected by various flags at runtime:

  • Selecting x32 depends on the tool:

      • gas: --x32

      • ld: -m elf32_x86_64

    • gcc: -mx32

    • gdb: bfd automatically detects things

  • gcc will automatically pass the correct flags down to the assembler/linker when it is given -mx32 itself.

  • Differences between x32 and x86_64:

    • long and pointer sizes:

      • X32: 32bits.

      • X86_64: 64bits

    • Library API is the same as ia32.

    • To compile a package for x32:

      • Always add -mx32 to compiler and configure it as x86-64:

        • To configure C and C++ programs, use

          • CC="gcc -mx32 " CXX="g++ -mx32" ./configure

  • Write inline x86-64 assembly statements for x32 and LP64:

      • When there is a register destination operand for pointers or longs, drop the `q' mnemonic suffix. For example, instead of doing

[hjl@gnu-tools-1 tmp]$ cat q.c

int *

add (int *p)

{

asm ("movq %%fs:0,%0\n\t"

"addq foo@gottpoff(%%rip),%0"

: "=r" (p));

return p;

}

[hjl@gnu-tools-1 tmp]$ gcc -c -mx32 q.c

q.c: Assembler messages:

q.c:4: Error: operand size mismatch for `movq'

q.c:5: Error: incorrect register `%eax' used with `q' suffix

[hjl@gnu-tools-1 tmp]$

we should do

[hjl@gnu-tools-1 tmp]$ cat p.c

int *

add (int *p)

{

asm ("mov %%fs:0,%0\n\t"

"add foo@gottpoff(%%rip),%0"

: "=r" (p));

return p;

}

[hjl@gnu-tools-1 tmp]$ gcc -c -mx32 p.c

[hjl@gnu-tools-1 tmp]$

  • Add x32 support on existing x86_64 support:

    • C/C++ codes:

      • Use int64_t or long long instead of long for 64bit integer.

    • Assembler codes:

      • Use 32bit instructions on long and pointer.

    • You can do

#ifdef __x86_64__

...

# ifdef __ILP32__

X32 code

# else

LP64 code

# endif

....

#endif /* __x86_64__ support. */

See libgcc/config/i386/morestack.S in GCC source for examples.

Debug Memory Corruption

  • Invalid addresses like 0xfffffffffxxxxxxxx, where upper 32bits are all 1s

What You Can Help

    • GCC

      • Avoid unnecessary 0x67 address prefix.

    • Kernel:

      • Add a meta register to ptrace interface to identify x32 process.

      • Update compat ioctl layer to support ioctl commands with struct size lile:

        • #define IOCTL_COMMAND _IOR('o', 28, struct ioctl_arg)

        • They are in

drivers/media/video/v4l2-compat-ioctl32.c

fs/compat_ioctl.c

fs/xfs/xfs_ioctl32.c

fs/xfs/xfs_ioctl32.h

sound/core/pcm_compat.c

sound/core/rawmidi_compat.c

sound/core/timer_compat.c

        • When "struct ioctl_arg" contains fields of "struct timeval/timespec" and long/pointer, its size is from regular 32bit "struct ioctl_arg" since "struct timeval/timespec" are 2x64bit for x32 and 2x32bit for regular 32bit targets. One way to solve is is for each such command, we add a new compat function to support 64bit time_t.

        • Some ioctl commands also take time_t, like PPPIOCGIDLE.