Porting to Hammer This document shows some common problems when porting software to Linux/x86-64 Andi Kleen, SuSE Labs Prototypes must be correct when stdargs are involved. Some programs have inconsistent prototypes over multiple source code files. When the actual function definition uses stdargs or varargs it expects the %rax register to be initialized to the number of floating point arguments. When the caller doesn't know about this because its prototype doesn't include the ellipsis (...) it won't initialize %rax and and a crash will occur after the call. The functions usually jump into nirvana and cause very strange failure modes (completely different functions are suddenly executed etc.) glibc defines some functions unexpectedly as stdarg (e.g. ptrace, fcntl, open) and expects %rax to be set correctly for them. These must have correct prototypes, best by including the correct glibc header How to check: Make sure your prototypes are correct and consistent. Look for prototypes that are not declared in shared include files and verify that they are connect. Run lclint with only function call checking enabled over the whole program to check for consistent prototypes. The gcc protoize tool may also be used to generate a global prototype file that could be included in every file using gcc's -include option. ---- Shared libraries must be compiled with -fPIC. i386 and other ports tolerate shared libraries that are not compiled with -fPIC. On x86-64 this leads to a crash when accessing external symbols to the shared library (e.g. symbols declared in the main program) because only 32bit relocations are used for referencing them. The shared library is loaded more than 32bits away from the main program. The 32bit relocations sometimes work between shared libraries when they are loaded at startup because then the shared libraries are within reach of 32bit, but it may fail for shared libraries that are loaded later with dlopen() for example. How to check: Run readelf -r and nm on the shared library. Relocations showing as 'U' in nm must have an corresponding entry in the GOT table shown as the '.rela.got'. ---- Libraries are in /lib64 64bit libraries are in */lib64 instead of */lib. Makefiles that install libraries must be changed for this. Also the common -L/usr/X11R6/lib compile flag or a similar flag for the Qt library must be changed to reference */lib64. ---- Correct return type declarations for pointers. Functions returning pointers must be prototyped to return a pointer. When they are used implicitly they are assumed to return 32bit int, which leads to a truncation of the pointer and a crash on accessing the pointer. Common victims of this are standard library functions like strerror or malloc when their include file is not included. How to check: Enable -Wall in gcc and look for warnings for undeclared functions. ------------------------------------------------------------------------- The following are caveats for porting linux kernel code. This does not apply to user space applications. If you are only porting user space application you can stop reading now. Interrupt flags used in save_flags() or spin_lock_irqsave() must be unsigned long. Other architectures tolerate int, but Hammer doesn't. How to check: The x86-64 include files force a warning for this with -Wall. Look for the warning and fix it. Also the code may cause assembly failures with wrong types. ---- Modules must be compiled with -mcmodel=kernel -mno-redzone Modules that are built external to the main source tree must be compiled with -mcmodel=kernel. Otherwise they will crash soon after loading. Modules built in the kernel tree do this automatically. -mno-redzone avoids potential problems with interrupts and some gcc optimizations. ---- Drivers must use the PCI DMA mapping API Drivers must use the PCI dma mapping API for bus addresses. See Documentation/DMA-mapping.txt in the kernel source tree. This is currently not strictly required, but will be very soon if the drivers should work on boxes with more than 4GB of ram.