Porting
These pages describe the parts of the Alpha architecture that most often cause problems when software is first built for Alpha/Linux.
Many of these failures are latent defects in portable code rather than Alpha-specific problems. Alpha traps on every misaligned load or store other than LDQ_U and STQ_U, does not order dependent loads, and reports arithmetic traps imprecisely on processors before the 21264; the original architecture also had no byte or word stores. Alpha therefore exposes defects that x86 tolerates. Where that is the case, these pages cite the evidence that a change is a genuine fix rather than an architecture-specific workaround.
| Page | Topic |
|---|---|
| Unaligned Access | Why *(uint32_t *)(buf + 1) is undefined behavior in C, how it also crashes x86 programs, and how to find and fix it |
| Byte and Word Access | The byte/word extension (BWX), pre-BWX byte and word access, and why non-atomic byte access ended pre-EV56 support |
| Memory Model | The weakest memory model Linux supports, dependent load reordering, barriers, and load-locked / store-conditional |
| Floating Point | -mieee, imprecise traps, software completion, the FPCR, and denormals |
| Why Alpha Has libc.so.6.1 | Code that names libc.so.6, and the January 1997 ABI break behind the different name |
| Linux ABI Differences | The 8 KiB page size, 128-bit long double, va_list, the 1024 Hz clock tick, and the system call, errno, signal, and ioctl numbers that differ from x86-64 |
Symptoms
| Symptom | Likely cause | Page |
|---|---|---|
unaligned trap messages in the kernel log, or SIGBUS | A misaligned load or store, or a misaligned atomic operation | Unaligned Access |
SIGFPE on floating-point code, often on NaN, infinity, or denormal operands | Code built without -mieee | Floating Point |
SIGILL | Code built for a newer processor (-mcpu) than the one running it | Toolchains |
| Corrupted neighboring bytes under threads or signals | Non-atomic byte or word stores in code built for pre-EV56 processors | Byte and Word Access |
| Intermittent failures in lock-free code | Missing memory barriers | Memory Model |
libc.so.6: cannot open shared object file | The C library named by file name | Why Alpha Has libc.so.6.1 |
Wrong errno values, signals, or ioctl requests; EINVAL from mmap() | Numbers copied from x86, or a 4 KiB page size assumed | Linux ABI Differences |
CPU times from times() or /proc about ten times too large | Clock ticks assumed to be 100 per second | Linux ABI Differences |
conversion … to non-scalar type __gnuc_va_list at compile time | A va_list treated as a pointer | Linux ABI Differences |
relocation truncated to fit at link time | GOT or small data area overflow | Toolchains |
Checklist
- No LLVM. Clang, Rust (except through GCC-based efforts), Zig, and other LLVM-based compilers are not available; code must build with GCC. See Toolchains.
- Processor baseline. Current kernels require an EV56 (21164A) or later, but the compiler's default may be older: Debian's GCC defaults to
-mcpu=ev56, Gentoo's to the architecture baseline. Gentoo's release stages are built with-mcpu=ev4, so the code in them stores bytes and words with non-atomic pre-BWX sequences (see Byte and Word Access). 1) 2) See Distribution baselines. -mieee. Debian and Gentoo enable it by default; upstream GCC does not. Code that handles NaN, infinity, or denormals needs it. See Floating Point.- 8 KiB pages. Obtain the page size with
sysconf(_SC_PAGESIZE). See Page size. - Alignment. Misaligned ordinary loads and stores are fixed up by the kernel, slowly; misaligned atomic operations always raise
SIGBUS. See Unaligned Access. - Sub-word atomics. Atomic operations on 8-bit and 16-bit objects are built from quadword load-locked/store-conditional sequences. See Memory Model.
- Integer division is a library call. Alpha has no integer divide instruction, and GCC calls helper routines with a nonstandard register convention. See Instruction Set.
- JIT compilers and hand-written assembly have to issue the
imbPALcode call after writing code and before running it (see PALcode calls), change page protections in 8 KiB units (see Page size), set up$27and$29as the calling convention requires (see Registers), implement or call integer division, and assemble for EV56 or later so that byte stores are atomic (see binutils). - The C library is
libc.so.6.1, packaged in Debian aslibc6.1andlibc6.1-devrather thanlibc6andlibc6-dev. See Why Alpha Has libc.so.6.1. - The target triplet is
alpha-unknown-linux-gnu(alpha-linux-gnuon Debian). Processor-specific triplets such asalphaev67-unknown-linux-gnuare also valid, so configure scripts should matchalpha*. 3)config.guessrun on an Alpha returns such a triplet itself, taking the processor from thecpu modelline of/proc/cpuinfo:alphaev67-unknown-linux-gnuon an EV67, for example. 4) Meson's CPU family for Alpha isalpha, which it counts as a 64-bit family. 5) 6)
Testing and diagnosis
What the compiler targets
The predefined macros show which processor and floating-point mode a compiler targets, including defaults that a distribution builds into it:
gcc -dM -E - </dev/null | grep -E '__alpha_|_IEEE_FP'
GCC defines __alpha_bwx__, __alpha_max__, __alpha_fix__, and __alpha_cix__ for each enabled extension, one of __alpha_ev4__, __alpha_ev5__, or __alpha_ev6__ for the scheduling family, _IEEE_FP under -mieee, and _IEEE_FP_INEXACT under -mieee-with-inexact. 7) Output with no __alpha_bwx__ means that byte and word stores are compiled as non-atomic pre-BWX sequences. gcc -Q –help=target lists the Alpha options and the values in effect, such as -mcpu= and -mieee.
What a binary contains
objdump -d shows how a binary was compiled. Floating-point instructions with a /su or /sui suffix (addt/su) come from -mieee or -mieee-with-inexact, as do trapb barriers in code built for processors before the EV6 (see Trap shadows); a /d suffix from -mfp-rounding-mode=d. stb and stw instructions mean the code was built for BWX; byte stores built without it appear as ldq_u, mskbl, insbl, stq_u sequences.
What the processor provides
LD_SHOW_AUXV=1 makes the dynamic linker print the auxiliary vector before running any program: HWCAP holds the extension bits described in Architecture Mask, PLATFORM the kernel's processor class (ev56, ev6, or ev67), and CLKTCK the 1024 Hz clock tick. 8) 9)
LD_SHOW_AUXV=1 /bin/true
Testing under QEMU
qemu-alpha runs Alpha programs on another host, which is enough to find build failures, wrong constants, and most ABI problems. It does not reproduce everything real hardware does:
- Unaligned accesses succeed silently in user mode, with no kernel fixup, log message, or counter, unless the program has asked for
SIGBUSwithprctl(PR_SET_UNALIGN). 10) 11) They have to be found on hardware or with the methods in Finding unaligned accesses. - Memory ordering is the host's, since QEMU declares no ordering requirement of its own for Alpha guests, 12) so bugs from missing barriers often do not show up. Such bugs need a multiprocessor Alpha to reproduce; see QEMU: Limitations and Memory Model.
- Processor selection follows
-cpu; the default, EV67, runs code that would raiseSIGILLon an EV56.
Tools that are not available
- Valgrind has no Alpha port. 13)
- GCC's sanitizers (AddressSanitizer, ThreadSanitizer, UndefinedBehaviorSanitizer and the others) are unavailable, since GCC does not build its sanitizer runtime library for targets that library's configuration does not list, and Alpha is not listed. 14) 15) Misaligned accesses can instead be found by building the same code with UBSan on another architecture; see UBSan on a non-Alpha host.
- gdbserver has no Alpha support; GDB runs natively. See Toolchains: GDB.
Terms
Alpha documentation calls a 16-bit quantity a word, a 32-bit quantity a longword, and a 64-bit quantity a quadword. These pages follow that usage.
