Skip to content

vms-40b: Alpha struct stat/sigaction layouts + stat64 wrappers - #629

Merged
baron-3dl merged 1 commit into
mainfrom
work/vms-40b-alpha-stat
Aug 16, 2026
Merged

baron-3dl merged 1 commit into
mainfrom
work/vms-40b-alpha-stat

Conversation

@baron-3dl

Copy link
Copy Markdown
Contributor

Summary

Rung A1 of the OVMX-on-Alpha epic (rd vms-40b). A0 landed the Alpha freestanding backend (src/libvmssys/arch/alpha/{crt0,syscall,sigreturn}.S + the __alpha__ syscall table) but deliberately left struct vms_stat and struct vms_sigaction undefined for Alpha, so any code path touching them failed loud (compiler warning) rather than silently reading a wrong layout. This PR defines both, and proves the whole tests/libvmssys suite green under qemu-alpha.

Struct layouts — provenance

Both verified byte-for-byte by compiling offsetof/sizeof probes against the verbatim struct definitions from the real kernel headers and running them under qemu-alpha (not derived from memory):

  • struct vms_statarch/alpha/include/uapi/asm/stat.h, struct stat64, Linux 6.6.52 source (same header shipped by the gcc-alpha-linux-gnu/libc6-dev-alpha-cross cross toolchain). This is what fstat64/fstatat64 fill.
  • struct vms_sigactionarch/alpha/include/uapi/asm/signal.h, struct sigaction (same shape in glibc's alpha bits/sigaction.h). Order is handler/mask/flags — not flags-then-mask like x86_64/aarch64 — and there is no sa_restorer field.

Wrapper fixes in vms_syscall.h:

  • vms_sys_fstat now calls __NR_fstat64 (427) instead of the old __NR_fstat (91, a narrower non-stat64 struct) — the known trap from the rung brief.
  • vms_sys_rt_sigaction gets an Alpha-specific 5-arg body: Alpha's rt_sigaction is SYSCALL_DEFINE5(rt_sigaction, sig, act, oact, sigsetsize, restorer) — the restorer is an explicit 5th syscall argument, not a struct field.

Four more pre-existing gaps found proving the gate

None of these are caused by the struct work above — all were already blocking tests/libvmssys under qemu-alpha before this PR, just invisible because nothing had tried to run the suite there yet.

  1. No hardware integer divide/remainder. Alpha has no div/idiv-equivalent; GCC calls __divqu/__remqu. Added as hand-written assembly (arch/alpha/softdiv.S) because these use a non-standard calling convention (args in $24/$25, return address in $23 not $26, result in $27, and — the part that cost real debugging time — the callee must preserve $1-$8 because GCC's div+mod fusion (e.g. vms_snprintf.c's uint_to_str) keeps the original dividend live across the call in an otherwise-volatile register).
  2. No inline __builtin_sqrt/floor/ceil lowering on Alpha's GCC backend — always a libcall (confirmed via -S output even with -mieee). Added freestanding implementations (arch/alpha/softmath.c): schoolbook division, Newton-Raphson sqrt from a bit-halved exponent guess, IEEE-754 mantissa-mask floor/ceil. Both this and authenticity: INV-1 system-identity SSOT + logical-driven login banners (vms-e652) #1 must avoid glibc/libgcc (Rule 3), hence hand-rolled rather than linked from the cross sysroot.
  3. Alpha's mmap flag bits are not the generic Linux ones (arch/alpha/include/uapi/asm/mman.h): MAP_FIXED/MAP_ANONYMOUS/MAP_NORESERVE all differ. With the generic values, test_vmssys_syscall's mmap test got a small negative errno back that didn't equal VMS_MAP_FAILED, so the test dereferenced it and segfaulted.
  4. No TLS thread-pointer setup in crt0. Alpha sets the TLS base via PALcode (rduniq/wruniq, not a syscall). The TCB header offset (16 bytes, Variant I) isn't published in the toolchain headers, and installed glibc's own __tls_init_tp never calls wruniq at all (it assumes the kernel already set "unique" for the initial thread — an assumption our freestanding CRT can't rely on). Pinned it empirically: a probe filled a scratch buffer with a marker at a known offset, swept wruniq() across candidate base addresses, and asked a real __thread variable (in a separate TU, so the compiler couldn't constant-fold it away) which value it read back. Exactly one offset matched.
  5. Alpha's signal numbers are OSF/1, not generic Linux (e.g. SIGCHLD=20, not 17; several others renumbered). test_vmssys_futex's clone()-based fork emulation passed the generic VMS_SIGCHLD (17, which is Alpha's real SIGSTOP) as the clone exit signal and got EINVAL back every time; Alpha's real SIGCHLD (20) succeeds. Also found and removed a stale duplicate #define VMS_SIGCHLD 17 elsewhere in vms_types.h that was silently clobbering the per-arch value via macro redefinition.

Gate — qemu-alpha evidence

$ cmake -S src/libvmssys -B build-alpha -DCMAKE_SYSTEM_NAME=Linux -DCMAKE_SYSTEM_PROCESSOR=alpha \
    -DCMAKE_C_COMPILER=alpha-linux-gnu-gcc -DCMAKE_CROSSCOMPILING_EMULATOR=qemu-alpha
$ cmake --build build-alpha && ctest --test-dir build-alpha --output-on-failure

Test project .../build-alpha
    Start 1: test_vmssys_syscall
1/7 Test #1: test_vmssys_syscall ..............   Passed    0.00 sec
    Start 2: test_vmssys_string
2/7 Test #2: test_vmssys_string ...............   Passed    0.00 sec
    Start 3: test_vmssys_snprintf
3/7 Test #3: test_vmssys_snprintf .............   Passed    0.00 sec
    Start 4: test_vmssys_futex
4/7 Test #4: test_vmssys_futex ................   Passed    0.01 sec
    Start 5: test_vmssys_stdio
5/7 Test #5: test_vmssys_stdio ................   Passed    0.00 sec
    Start 6: test_vmssys_math
6/7 Test #6: test_vmssys_math .................   Passed    0.01 sec
    Start 7: test_vmssys_crt
7/7 Test #7: test_vmssys_crt ..................   Passed    0.00 sec

100% tests passed, 0 tests failed out of 7

The Alpha "declared inside parameter list" warnings are gone (confirmed clean -Wall -Wextra -ffreestanding -fno-builtin compile of every src/libvmssys/*.c).

Also needed (unrelated to the struct/ABI work, but required to make the qemu-alpha gate runnable at all): enable_language(ASM) and enable_testing() when src/libvmssys/CMakeLists.txt is configured standalone (cmake -S src/libvmssys), which the alpha gate does — previously only exercised by the netbsd-vax path, which needs neither.

x86_64 / aarch64 unchanged

  • x86_64: full-tree cmake -B build -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTS=ON -DBUILD_TOOLS=ON configures clean; ctest -R vmssys → 7/7 pass.
  • aarch64: standalone cross-compile (-DCMAKE_SYSTEM_PROCESSOR=aarch64 -DCMAKE_C_COMPILER=aarch64-linux-gnu-gcc) builds clean, no warnings.

Neither arch touches softdiv.S/softmath.c (Alpha-only in CMakeLists) or the Alpha branches of vms_types.h/vms_syscall.h/vms_runtime_init.c.

Test plan

  • tests/libvmssys cross-compiles for alpha-linux-gnu with zero warnings/errors
  • All 7 tests/libvmssys suites pass under qemu-alpha (shown above)
  • x86_64 full-tree configure + ctest -R vmssys unaffected (7/7 pass)
  • aarch64 standalone cross-compile unaffected (clean build)

🤖 Generated with Claude Code

Rung A1 of the OVMX-on-Alpha epic. A0 left struct vms_stat and struct
vms_sigaction deliberately undefined for __alpha__; this defines both,
verified field-for-field (offsetof/sizeof probes compiled and run under
qemu-alpha) against the real alpha-linux-gnu kernel headers:
arch/alpha/include/uapi/asm/stat.h (`struct stat64`, what fstat64/
fstatat64 fill) and arch/alpha/include/uapi/asm/signal.h (`struct
sigaction`, handler/mask/flags order -- no sa_restorer field). Wires
vms_sys_fstat to __NR_fstat64 (427) instead of the old __NR_fstat (91,
a narrower non-stat64 struct) per the known stat64-pairing trap, and
gives vms_sys_rt_sigaction an Alpha-specific 5-arg body: Alpha's
rt_sigaction syscall takes the signal restorer as an explicit 5th
argument (SYSCALL_DEFINE5) rather than a struct field.

Proving `tests/libvmssys` under qemu-alpha (the stated gate) surfaced
four more pre-existing, unrelated Alpha ABI gaps left open by A0 --
none caused by the struct work above, all blocking before it too:

  - No hardware integer divide/remainder: added __divqu/__remqu as
    hand-written asm (arch/alpha/softdiv.S) implementing Alpha's
    non-standard division-helper calling convention (args in $24/$25,
    return address in $23, result in $27, and -- the part that cost
    real debugging time -- callee must preserve $1-$8 because GCC's
    div+mod fusion keeps values live across the call).
  - No inline __builtin_sqrt/floor/ceil lowering on Alpha's GCC
    backend (always a libcall): added freestanding implementations
    (arch/alpha/softmath.c) -- schoolbook division, Newton-Raphson
    sqrt, IEEE-754 mantissa-mask floor/ceil. Neither gap can pull in
    glibc/libgcc (Rule 3), hence hand-rolled.
  - Alpha's mmap flag bits are not the generic Linux ones (MAP_FIXED/
    MAP_ANONYMOUS/MAP_NORESERVE all differ); the generic values sent a
    "success" pointer that was actually a small negative errno,
    segfaulting on the first write.
  - No TLS thread-pointer setup in crt0 (Alpha uses PALcode rduniq/
    wruniq, not a syscall); the TCB header offset (16 bytes, Variant I)
    was pinned empirically since neither the toolchain headers nor
    glibc's own __tls_init_tp publish it.
  - Alpha's signal numbers are OSF/1, not generic Linux (SIGCHLD=20 not
    17, several others renumbered); the generic VMS_SIGCHLD sent as a
    clone() exit signal produced EINVAL. Also removed a stale duplicate
    `#define VMS_SIGCHLD 17` elsewhere in the file that was silently
    clobbering the per-arch value via macro redefinition.

Gate: all 7 tests/libvmssys suites pass under qemu-alpha (standalone
`cmake -S src/libvmssys` configure, needed enable_language(ASM) and
enable_testing() added for that path). x86_64 (full-tree ctest,
BUILD_TESTS=ON) and aarch64 (standalone cross-compile) both unchanged
and still green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@baron-3dl
baron-3dl force-pushed the work/vms-40b-alpha-stat branch from 6c1c607 to c1dcb39 Compare August 16, 2026 20:46
@baron-3dl
baron-3dl merged commit 2e9f174 into main Aug 16, 2026
90 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant