Skip to content

vms-e11: imgact EM_ALPHA backend + activation proof - #628

Merged
baron-3dl merged 1 commit into
mainfrom
work/vms-e11-imgact-alpha
Aug 16, 2026
Merged

baron-3dl merged 1 commit into
mainfrom
work/vms-e11-imgact-alpha

Conversation

@baron-3dl

Copy link
Copy Markdown
Contributor

Summary

  • Adds src/imgact/arch/alpha/ (imgact_arch.h + start.S), mirroring the x86_64/aarch64 IMGACT.EXE backends and the #elif defined(__alpha__) branch in imgact.c (rd vms-e11, Alpha[A2], epic vms-8954).
  • A cross-built, freestanding static-PIE Alpha OVMX image (PT_INTERP=IMGACT.EXE, DT_NEEDED on a shareable image) activates and runs under qemu-alpha, printing IMGACT-TEST: PASS (r1=42 r2=42 r3=7 r4=0), exit 0. The missing-shareable failure path correctly yields %IMGACT-F-IMGNOTFND + nonzero exit.
  • x86_64/aarch64 backends re-verified unchanged (both proof harnesses still PASS, identical relocation sets and output).

EM_ machine value (oracle)

readelf -h on a real alpha-linux-gnu-gcc-built object reports Machine: Alpha; the toolchain's own <elf.h> (both /usr/include/elf.h and the alpha sysroot's) defines #define EM_ALPHA 0x9026. imgact.c selects the arch header at compile time via #if defined(__alpha__) (same pattern the x86_64/aarch64 backends already use — CMake's CMAKE_SYSTEM_PROCESSOR branch is the analogous compile-time selector), so no runtime e_machine check was needed or added.

Real Alpha ABI wrinkles found (all #ifdef/#if defined(__alpha__)-guarded; x86_64/aarch64 behavior byte-identical)

  1. MAP_ANONYMOUS is 0x10 on Alpha, not the generic 0x20 other archs use (confirmed against alpha-linux-gnu's <asm/mman.h>; empirically, a plain 0x20 anonymous mmap() returned -EBADF).
  2. The SysV .hash section uses 8-byte (Elf64_Xword) fields on Alpha, not the 4-byte fields every other 64-bit port (including aarch64/x86_64) uses — confirmed via sh_entsize==8 and empirically (the 4-byte-field read walked a garbage bucket/chain index into an out-of-bounds symtab access → SIGSEGV under qemu-alpha). obj_find()/struct obj generalized on a new imgact_hashword_t typedef, gated on IMGACT_HASH_XWORD (only alpha's arch header defines it).
  3. Alpha has no TLSDESC (alpha-linux-gnu-gcc -mtls-dialect=desc is rejected as unrecognized). Its only TLS model is the classic General Dynamic one: a JMP_SLOT call to __tls_get_addr(&tls_index), with DTPMOD64/DTPREL64 relocations filling the two-word tls_index. Implemented as a new IMGACT builtin (resolving directly against IMGACT's own g_objs[] module table — no real DTV needed) plus two new apply_rela() cases, both guarded on IMGACT_R_TLS_DTPMOD. The existing IMGACT_R_TLSDESC case is now itself guarded on #ifdef IMGACT_R_TLSDESC, since Alpha's arch header deliberately doesn't define it.
  4. (Not Alpha-specific in cause, but only reachable once Alpha's DT_HASH lookup was exercised for the first time: the hash-bucket modulo used plain %, which GCC lowers to a libgcc __remqu call on Alpha — unavailable in this -nostdlib build, left as a dangling GLOB_DAT relocation IMGACT's RELATIVE-only self_relocate() never fills. Replaced with a small standard-calling-convention umod64(): software binary long division on Alpha, a plain % pass-through everywhere else.)

Test plan

  • src/imgact/test/run_test_alpha.sh (containerized via tools/cross-alpha/, qemu-alpha user-mode): activation + failure-path PASS.
  • src/imgact/test/run_test_x86_64.sh (native x86_64 host): unchanged PASS.
  • aarch64 cross build + qemu-aarch64: unchanged PASS (same relocation set, same PASS output).

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

Adds src/imgact/arch/alpha/ (imgact_arch.h + start.S), mirroring the
x86_64/aarch64 IMGACT.EXE backends, so a cross-built freestanding
static-PIE OVMX Alpha ELF image activates under qemu-alpha.

Alpha objects carry EM_MACHINE 0x9026 (readelf: "Machine: Alpha"),
confirmed against alpha-linux-gnu's own <elf.h> and a real
alpha-linux-gnu-gcc-built object; imgact.c's #if defined(__alpha__)
arch-header-select branch does not need a runtime EM_ machine check
(neither the x86_64/aarch64 backends have one -- selection is
compile-time via the target triple, matching CMake's
CMAKE_SYSTEM_PROCESSOR branch).

Three real Alpha ABI wrinkles surfaced during bring-up under qemu-alpha
and are now handled generically (x86_64/aarch64 behavior unchanged,
verified by re-running both existing proof harnesses):

- MAP_ANONYMOUS is 0x10 on Alpha, not the generic 0x20 (confirmed
  against alpha-linux-gnu's <asm/mman.h>; a plain 0x20 anonymous mmap
  returned -EBADF).
- The SysV .hash section uses 8-byte (Elf64_Xword) fields on Alpha,
  not the 4-byte fields every other 64-bit port (including
  aarch64/x86_64) uses (confirmed via sh_entsize==8 and empirically --
  the 4-byte-field read walked a garbage bucket/chain index into an
  out-of-bounds symtab access, SIGSEGV). obj_find()/struct obj are
  generalized on a new imgact_hashword_t typedef, gated on
  IMGACT_HASH_XWORD (defined only in the alpha arch header).
- Alpha has no TLSDESC (alpha-linux-gnu-gcc rejects
  -mtls-dialect=desc/gnu2 outright); its only TLS model is the
  classic General Dynamic one: a JMP_SLOT call to
  __tls_get_addr(&tls_index), with DTPMOD64/DTPREL64 relocations
  filling the two-word tls_index. Implemented as a new IMGACT builtin
  (imgact_tls_get_addr, resolving directly against IMGACT's own
  g_objs[] module table -- no real DTV needed) plus two new
  apply_rela() cases, both guarded on IMGACT_R_TLS_DTPMOD so the
  existing TLSDESC-only backends are untouched. The existing
  IMGACT_R_TLSDESC case is now itself guarded on #ifdef
  IMGACT_R_TLSDESC, since Alpha's arch header deliberately does not
  define it.
- (Also fixed, not Alpha-specific in cause but only reachable once
  Alpha's DT_HASH lookup was exercised for the first time: the SysV
  hash bucket-index modulo used a plain `%`, which GCC lowers to a
  libgcc __remqu call on Alpha -- unavailable in this -nostdlib
  build, and left a live GLOB_DAT relocation IMGACT's RELATIVE-only
  self_relocate() never fills. Replaced with a small
  standard-calling-convention umod64() -- software binary long
  division on Alpha, a plain `%` pass-through elsewhere.)

Activation proof (src/imgact/test/run_test_alpha.sh, containerized via
tools/cross-alpha/, qemu-alpha user-mode): a test executable
(PT_INTERP=IMGACT.EXE, DT_NEEDED on a shareable image exercising
RELATIVE/GLOB_DAT/JMP_SLOT/DTPMOD64/DTPREL64) activates and prints
"IMGACT-TEST: PASS (r1=42 r2=42 r3=7 r4=0)", exit 0. The
missing-shareable failure path correctly yields
%IMGACT-F-IMGNOTFND + nonzero exit.

Re-ran both existing proof harnesses to confirm no regression:
run_test_x86_64.sh (native x86_64 host) and the aarch64 cross build
(qemu-aarch64) both still PASS with identical relocation sets and
output.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@baron-3dl
baron-3dl force-pushed the work/vms-e11-imgact-alpha branch from d74db5b to 9d0f23f Compare August 16, 2026 21:09
@baron-3dl
baron-3dl merged commit 7d3c99a 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