Home
X32 System V Application Binary Interface
A 32-bit psABI for x86-64 with 32-bit pointer size.
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.
Native Gentoo port is available as a stage3 release (can be chroot-ed into under other distros if your kernel is v3.6 or newer):
http://distfiles.gentoo.org/releases/amd64/autobuilds/current-stage3/
http://distfiles.gentoo.org/releases/amd64/autobuilds/current-iso/ (livecd w/x32 already enabled)
VirtualBox image for Fedora 19 with x32 support is available. It can be used to bootstrap and test GCC with x32 enabled. Additional virtual hard disk is needed to get extra disk space needed for GCC source and build.
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
Check all pointer/long usages in x86-64 specific files. One example
http://gcc.gnu.org/git/?p=gcc.git;a=commitdiff;h=cd0b9991c76903b66ad3c938d6135aedbf4e1ef0
The code tries to load long as an pointer to a 64bit field. The problem is long is signed. It isn’t a problem if long is 64bit. But long is 32bit for x32 and it gets sign-extended to 64bit, which leads to wrong address. The fix changed it to unsigned long, which zero-extends it to 64bit. Another example
http://gcc.gnu.org/git/?p=gcc.git;a=commitdiff;h=4b3971febf364bff23be95aa254f36a3173467f0
The code tries to update a 64bit value with an address by dereferencing a pointer to void *, which is 32bit for x32. The fix changed to a pointer to unsigned long long, which is always 64bit for both x32 and x86-64. It used unsigned to make sure that the 32bit address is zero-extended to 64bit.
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.
Port additional packages:
valgrind
javascript
Diagnosis/fix known bugs in packages:
Gentoo tracker bug with links to known problems: https://bugs.gentoo.org/showdependencytree.cgi?id=393673&hide_resolved=0