Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion src/vmslink/mk_decc_shr.sh
Original file line number Diff line number Diff line change
Expand Up @@ -430,8 +430,24 @@ if [ "$OVMX_DECC_ARCH" = alpha ]; then
esac
done
VEC=$(printf '%s' ",$VEC," | sed 's/,decc\$_getcwd64=PROCEDURE,/,decc$_getcwd64\/ovmx_crtl_getcwd=PROCEDURE,/; s/,decc\$getcwd\/decc\$_getcwd64=PROCEDURE,/,decc$getcwd\/ovmx_crtl_getcwd=PROCEDURE,/; s/^,//; s/,$//')
# vms-599: DEC C exit() records the image's VMS completion status (SYS$EXIT in
# LIBVMS$SHR) after musl's atexit handlers and stdio flush. decc$exit is rebound
# in place; __posix_exit (exit() under _POSIX_EXIT) is a new universal at the tail.
for _ex in ovmx_crtl_exit ovmx_crtl_posix_exit; do
"$NM" --defined-only "$SYS_OBJ" 2>/dev/null | awk '{print $NF}' | grep -qxF "$_ex" \
|| { echo "mk_decc_shr: FAIL crtl_process.c did not define $_ex" >&2; exit 2; }
done
case ",$VEC," in
*',decc$exit=PROCEDURE,'*) ;;
*) echo "mk_decc_shr: FAIL decc\$exit is not a PROCEDURE universal to rebind" >&2; exit 2;;
esac
VEC=$(printf '%s' ",$VEC," | sed 's/,decc\$exit=PROCEDURE,/,decc$exit\/ovmx_crtl_exit=PROCEDURE,/; s/^,//; s/,$//')
case ",$VEC,${PASS2_TAIL:-}," in
*',decc$__posix_exit'[=/]*) echo "mk_decc_shr: FAIL decc\$__posix_exit is already in the vector" >&2; exit 2;;
esac
PASS2_TAIL="${PASS2_TAIL:-},decc\$__posix_exit/ovmx_crtl_posix_exit=PROCEDURE"
ALPHA_VENEER_OBJ="$ALPHA_VENEER_OBJ $SYS_OBJ"
echo "mk_decc_shr: DEC C system() wired (vms-65a): decc\$system -> ovmx_crtl_system (LIB\$SPAWN, --use $ALPHA_CRTL_VMS_USE)"
echo "mk_decc_shr: DEC C system() wired (vms-65a): decc\$system -> ovmx_crtl_system (LIB\$SPAWN, --use $ALPHA_CRTL_VMS_USE); exit/__posix_exit record \$STATUS (vms-599)"
fi

# Plain (non-decc$-decorated) names the decc$ filter above cannot catch,
Expand Down
60 changes: 60 additions & 0 deletions src/vmsrms/crtl_process.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,21 @@
* image. The musl system() the archive also carries (a clone with CLONE_VFORK,
* which the executive refuses) stays an internal symbol: decc$system is rebound
* in place to ovmx_crtl_system by mk_decc_shr.sh.
*
* exit() and __posix_exit() (vms-599): the value an image hands exit() is its VMS
* completion status, which DCL reads as $STATUS. Measured on OpenVMS Alpha V8.4
* (tests/lab/captures/decc-exit-alpha-20261021, MACRO-32 calling the C RTL entry
* points): DECC$EXIT turns 0 into %X00000001 (SS$_NORMAL) and passes every other
* value through unchanged (1, 2, 3, %X1000002C). DECC$__POSIX_EXIT (what exit()
* is under _POSIX_EXIT) keeps the low eight bits, turns 0 into %X00000001, and any
* other n into a C-facility message: %X0035A001 + (n << 3), with 1 made an error
* whose message is inhibited, %X1035A00A (2 -> %X0035A011, 255 -> %X0035A7F9,
* 256 -> %X00000001). musl's exit() ran the atexit handlers and flushed stdio, then
* exit_group()ed a POSIX code, and nothing recorded the status: DCL saw exit(1),
* a success, as "exited with error status %X00000001". Both entry points record
* the status, then run musl's exit; the C RTL file layer's system-call hook
* (crtl_rms_fd.c) sees the final exit_group and ends the image with SYS$EXIT of
* that status, after the handlers and the flush, as the DEC C RTL does.
*/
#include <errno.h>
#include <stdlib.h>
Expand Down Expand Up @@ -97,3 +112,48 @@ char *ovmx_crtl_getcwd(char *buf, unsigned long size, int vms_flag)
memcpy(buf, out, need);
return buf;
}

/* ------------------------------------------------------- exit (vms-599) ---- */

extern unsigned int sys$exit(unsigned int code); /* LIBVMS$SHR */
extern void (*__ovmx_crtl_exit_record)(void); /* crtl_rms_fd.c */

static unsigned int crtl_exit_cond;

/* Called from the system-call hook at the image's final exit_group: end the
* image with SYS$EXIT of the recorded status (it runs the exit handlers, records
* the status with the executive and terminates). The cell is cleared first, so
* SYS$EXIT's own exit_group passes straight through the hook. */
static void crtl_exit_record(void)
{
__ovmx_crtl_exit_record = 0;
(void)sys$exit(crtl_exit_cond);
}

static void crtl_exit_with(unsigned int cond)
{
crtl_exit_cond = cond;
__ovmx_crtl_exit_record = crtl_exit_record;
exit((cond & 1u) ? 0 : 1); /* musl: atexit, stdio flush */
}

/* DEC C exit(): 0 is SS$_NORMAL, any other value is the status itself. */
void ovmx_crtl_exit(int status)
{
crtl_exit_with(status == 0 ? 1u : (unsigned int)status);
}

/* DEC C __posix_exit() (exit() under _POSIX_EXIT): a POSIX code 0-255 as a
* C-facility condition value (see the measurement above). */
void ovmx_crtl_posix_exit(int status)
{
unsigned int n = (unsigned int)status & 255u;
unsigned int cond;
if (n == 0)
cond = 1u;
else if (n == 1)
cond = 0x1035A00Au;
else
cond = 0x0035A001u + (n << 3);
crtl_exit_with(cond);
}
7 changes: 7 additions & 0 deletions src/vmsrms/crtl_rms_fd.c
Original file line number Diff line number Diff line change
Expand Up @@ -1489,10 +1489,17 @@ static long long rms_hook_body(long long n, long long a1, long long a2,
}
}

/* Set by the DEC C exit()/__posix_exit() (crtl_process.c, vms-599) to the routine
* that ends the image with SYS$EXIT of the status it was given; called at the
* final exit_group, after musl ran the atexit handlers and flushed stdio. */
void (*__ovmx_crtl_exit_record)(void);

static long long rms_hook(long long n, long long a1, long long a2, long long a3,
long long a4, long long a5, long long a6, int *handled)
{
(void)a6;
if (n == SYS_exit_group && __ovmx_crtl_exit_record)
__ovmx_crtl_exit_record(); /* SYS$EXIT: does not return */
if (in_rms)
return 0; /* RMS's own system calls */
in_rms = 1;
Expand Down
8 changes: 7 additions & 1 deletion tests/integration/test_userspace_service_register.sh
Original file line number Diff line number Diff line change
Expand Up @@ -892,6 +892,12 @@ grep -E '\.[sS]$' "$WORK/buildset" > "$WORK/prodasm" 2>/dev/null || : > "$WORK/p
# and only compiles inside the extracted musl tree. Its real compile runs in
# build-musl.sh and its behaviour is proven by the alpha vfork gate. Anchored +
# file-level, like lite_malloc.c above.
# tools/cross-alpha-vms/musl-arch/src/exit/alpha-dec-vms/exit.c and
# .../src/stdio/alpha-dec-vms/__stdio_exit.c (vms-599) are the same kind again
# (src/<dir>/$(ARCH)/ replaces the generic file): they include musl's INTERNAL
# "libc.h"/"stdio_impl.h" and define only exit() / __stdio_exit(), no sys$ symbol.
# Its real compile + the exit nm gate run in build-musl.sh; the alpha crtl-fd gate
# proves the behaviour. Anchored + file-level.
# src/vmsrms/crtl_rms_fd.c (vms-b90) is the C RTL file layer DECC$SHR's
# RMS-backed pass links: it hooks the musl-arch syscall funnel and fills musl's
# arch-internal struct kstat (musl-arch kstat.h), so it only compiles against
Expand All @@ -917,7 +923,7 @@ grep -E '\.[sS]$' "$WORK/buildset" > "$WORK/prodasm" 2>/dev/null || : > "$WORK/p
# the alpha-dec-vms client headers (musl-arch bits/stat.h: st_ino[3], st_fab_*,
# the __OVMX_DECC_STAT_FIELDS list); a host libc has neither. They define no
# sys$ service; their real compiles are mk_decc_shr.sh and the crtl-fd gate.
SYMSCAN_EXCLUDE_RE="^src/kernel/|^src/kernel-netbsd/|^src/kernel-core/|^src/vmsfs/ods2/ods2_block_kern\.c$|^tools/cross-alpha-vms/musl-arch/src/internal/vms_alpha_syscall\.c$|^tools/cross-alpha-vms/musl-arch/src/thread/alpha-dec-vms/__set_thread_area\.c$|^tools/cross-alpha-vms/include-surface/compile_vms_unwind\.c$|^tools/cross-alpha-vms/musl-arch/src/malloc/alpha-dec-vms/lite_malloc\.c$|^tools/cross-alpha-vms/musl-arch/src/process/alpha-dec-vms/_Fork\.c$|^src/vmsrms/crtl_rms_fd\.c$|^src/vmsrms/rms_vmsabi\.c$|^tools/cross-alpha-vms/include-surface/vms_abi_headers\.c$|^tools/cross-alpha-vms/joint-e2e/vmsabi_rms_test\.c$|^src/vmslink/ovmx_decc_stat\.c$|^tools/cross-alpha-vms/joint-e2e/crtl_fd_test\.c$|^src/libvms/syssvc/sys_vmsabi\.c$|^tools/cross-alpha-vms/include-surface/hostabi_bfd_shapes\.c$"
SYMSCAN_EXCLUDE_RE="^src/kernel/|^src/kernel-netbsd/|^src/kernel-core/|^src/vmsfs/ods2/ods2_block_kern\.c$|^tools/cross-alpha-vms/musl-arch/src/internal/vms_alpha_syscall\.c$|^tools/cross-alpha-vms/musl-arch/src/thread/alpha-dec-vms/__set_thread_area\.c$|^tools/cross-alpha-vms/include-surface/compile_vms_unwind\.c$|^tools/cross-alpha-vms/musl-arch/src/malloc/alpha-dec-vms/lite_malloc\.c$|^tools/cross-alpha-vms/musl-arch/src/process/alpha-dec-vms/_Fork\.c$|^tools/cross-alpha-vms/musl-arch/src/exit/alpha-dec-vms/exit\.c$|^tools/cross-alpha-vms/musl-arch/src/stdio/alpha-dec-vms/__stdio_exit\.c$|^src/vmsrms/crtl_rms_fd\.c$|^src/vmsrms/rms_vmsabi\.c$|^tools/cross-alpha-vms/include-surface/vms_abi_headers\.c$|^tools/cross-alpha-vms/joint-e2e/vmsabi_rms_test\.c$|^src/vmslink/ovmx_decc_stat\.c$|^tools/cross-alpha-vms/joint-e2e/crtl_fd_test\.c$|^src/libvms/syssvc/sys_vmsabi\.c$|^tools/cross-alpha-vms/include-surface/hostabi_bfd_shapes\.c$"

SYMCC=""
for _c in cc gcc; do
Expand Down
87 changes: 87 additions & 0 deletions tests/lab/captures/decc-exit-alpha-20261021/CONSOLE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
$ MACRO/NOLIST/OBJECT=SYS$SCRATCH:EXS0.OBJ SYS$SCRATCH:EXS0.MAR
$ LINK/EXECUTABLE=SYS$SCRATCH:EXS0.EXE SYS$SCRATCH:EXS0.OBJ
$ RUN SYS$SCRATCH:EXS0.EXE
$ WRITE SYS$OUTPUT "PROBE EXS0 STATUS=",F$STRING($STATUS)
PROBE EXS0 STATUS=%X00000001
$ SHOW SYMBOL $STATUS
$STATUS == "%X00010001"
$ MACRO/NOLIST/OBJECT=SYS$SCRATCH:EXS1.OBJ SYS$SCRATCH:EXS1.MAR
$ LINK/EXECUTABLE=SYS$SCRATCH:EXS1.EXE SYS$SCRATCH:EXS1.OBJ
$ RUN SYS$SCRATCH:EXS1.EXE
$ WRITE SYS$OUTPUT "PROBE EXS1 STATUS=",F$STRING($STATUS)
PROBE EXS1 STATUS=%X00000001
$ SHOW SYMBOL $STATUS
$STATUS == "%X00010001"
$ MACRO/NOLIST/OBJECT=SYS$SCRATCH:EXS2.OBJ SYS$SCRATCH:EXS2.MAR
$ LINK/EXECUTABLE=SYS$SCRATCH:EXS2.EXE SYS$SCRATCH:EXS2.OBJ
$ RUN SYS$SCRATCH:EXS2.EXE
%NONAME-E-NOMSG, Message number 00000002
$ WRITE SYS$OUTPUT "PROBE EXS2 STATUS=",F$STRING($STATUS)
PROBE EXS2 STATUS=%X00000002
$ SHOW SYMBOL $STATUS
$STATUS == "%X00010001"
$ MACRO/NOLIST/OBJECT=SYS$SCRATCH:EXS3.OBJ SYS$SCRATCH:EXS3.MAR
$ LINK/EXECUTABLE=SYS$SCRATCH:EXS3.EXE SYS$SCRATCH:EXS3.OBJ
$ RUN SYS$SCRATCH:EXS3.EXE
$ WRITE SYS$OUTPUT "PROBE EXS3 STATUS=",F$STRING($STATUS)
PROBE EXS3 STATUS=%X00000003
$ SHOW SYMBOL $STATUS
$STATUS == "%X00010001"
$ MACRO/NOLIST/OBJECT=SYS$SCRATCH:EXS4.OBJ SYS$SCRATCH:EXS4.MAR
$ LINK/EXECUTABLE=SYS$SCRATCH:EXS4.EXE SYS$SCRATCH:EXS4.OBJ
$ RUN SYS$SCRATCH:EXS4.EXE
%NONAME-F-NOMSG, Message number 00000004
$ WRITE SYS$OUTPUT "PROBE EXS4 STATUS=",F$STRING($STATUS)
PROBE EXS4 STATUS=%X00000004
$ SHOW SYMBOL $STATUS
$STATUS == "%X00010001"
$ MACRO/NOLIST/OBJECT=SYS$SCRATCH:EXSBIG.OBJ SYS$SCRATCH:EXSBIG.MAR
$ LINK/EXECUTABLE=SYS$SCRATCH:EXSBIG.EXE SYS$SCRATCH:EXSBIG.OBJ
$ RUN SYS$SCRATCH:EXSBIG.EXE
$ WRITE SYS$OUTPUT "PROBE EXSBIG STATUS=",F$STRING($STATUS)
PROBE EXSBIG STATUS=%X1000002C
$ SHOW SYMBOL $STATUS
$STATUS == "%X00010001"
$ MACRO/NOLIST/OBJECT=SYS$SCRATCH:PXS0.OBJ SYS$SCRATCH:PXS0.MAR
$ LINK/EXECUTABLE=SYS$SCRATCH:PXS0.EXE SYS$SCRATCH:PXS0.OBJ
$ RUN SYS$SCRATCH:PXS0.EXE
$ WRITE SYS$OUTPUT "PROBE PXS0 STATUS=",F$STRING($STATUS)
PROBE PXS0 STATUS=%X00000001
$ SHOW SYMBOL $STATUS
$STATUS == "%X00010001"
$ MACRO/NOLIST/OBJECT=SYS$SCRATCH:PXS1.OBJ SYS$SCRATCH:PXS1.MAR
$ LINK/EXECUTABLE=SYS$SCRATCH:PXS1.EXE SYS$SCRATCH:PXS1.OBJ
$ RUN SYS$SCRATCH:PXS1.EXE
$ WRITE SYS$OUTPUT "PROBE PXS1 STATUS=",F$STRING($STATUS)
PROBE PXS1 STATUS=%X1035A00A
$ SHOW SYMBOL $STATUS
$STATUS == "%X00010001"
$ MACRO/NOLIST/OBJECT=SYS$SCRATCH:PXS2.OBJ SYS$SCRATCH:PXS2.MAR
$ LINK/EXECUTABLE=SYS$SCRATCH:PXS2.EXE SYS$SCRATCH:PXS2.OBJ
$ RUN SYS$SCRATCH:PXS2.EXE
$ WRITE SYS$OUTPUT "PROBE PXS2 STATUS=",F$STRING($STATUS)
PROBE PXS2 STATUS=%X0035A011
$ SHOW SYMBOL $STATUS
$STATUS == "%X00010001"
$ MACRO/NOLIST/OBJECT=SYS$SCRATCH:PXS3.OBJ SYS$SCRATCH:PXS3.MAR
$ LINK/EXECUTABLE=SYS$SCRATCH:PXS3.EXE SYS$SCRATCH:PXS3.OBJ
$ RUN SYS$SCRATCH:PXS3.EXE
$ WRITE SYS$OUTPUT "PROBE PXS3 STATUS=",F$STRING($STATUS)
PROBE PXS3 STATUS=%X0035A019
$ SHOW SYMBOL $STATUS
$STATUS == "%X00010001"
$ MACRO/NOLIST/OBJECT=SYS$SCRATCH:PXS255.OBJ SYS$SCRATCH:PXS255.MAR
$ LINK/EXECUTABLE=SYS$SCRATCH:PXS255.EXE SYS$SCRATCH:PXS255.OBJ
$ RUN SYS$SCRATCH:PXS255.EXE
$ WRITE SYS$OUTPUT "PROBE PXS255 STATUS=",F$STRING($STATUS)
PROBE PXS255 STATUS=%X0035A7F9
$ SHOW SYMBOL $STATUS
$STATUS == "%X00010001"
$ MACRO/NOLIST/OBJECT=SYS$SCRATCH:PXS256.OBJ SYS$SCRATCH:PXS256.MAR
$ LINK/EXECUTABLE=SYS$SCRATCH:PXS256.EXE SYS$SCRATCH:PXS256.OBJ
$ RUN SYS$SCRATCH:PXS256.EXE
$ WRITE SYS$OUTPUT "PROBE PXS256 STATUS=",F$STRING($STATUS)
PROBE PXS256 STATUS=%X00000001
$ SHOW SYMBOL $STATUS
$STATUS == "%X00010001"
$
7 changes: 7 additions & 0 deletions tests/lab/captures/decc-exit-alpha-20261021/EXS0.MAR
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.TITLE EXS0 OVMX exit-status probe: DECC$EXIT(0)
.PSECT CCODE,EXE,NOWRT,QUAD
.ENTRY EXS0,^M<>
PUSHL #0
CALLS #1,G^DECC$EXIT
RET
.END EXS0
7 changes: 7 additions & 0 deletions tests/lab/captures/decc-exit-alpha-20261021/EXS1.MAR
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.TITLE EXS1 OVMX exit-status probe: DECC$EXIT(1)
.PSECT CCODE,EXE,NOWRT,QUAD
.ENTRY EXS1,^M<>
PUSHL #1
CALLS #1,G^DECC$EXIT
RET
.END EXS1
7 changes: 7 additions & 0 deletions tests/lab/captures/decc-exit-alpha-20261021/EXS2.MAR
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.TITLE EXS2 OVMX exit-status probe: DECC$EXIT(2)
.PSECT CCODE,EXE,NOWRT,QUAD
.ENTRY EXS2,^M<>
PUSHL #2
CALLS #1,G^DECC$EXIT
RET
.END EXS2
7 changes: 7 additions & 0 deletions tests/lab/captures/decc-exit-alpha-20261021/EXS3.MAR
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.TITLE EXS3 OVMX exit-status probe: DECC$EXIT(3)
.PSECT CCODE,EXE,NOWRT,QUAD
.ENTRY EXS3,^M<>
PUSHL #3
CALLS #1,G^DECC$EXIT
RET
.END EXS3
7 changes: 7 additions & 0 deletions tests/lab/captures/decc-exit-alpha-20261021/EXS4.MAR
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.TITLE EXS4 OVMX exit-status probe: DECC$EXIT(4)
.PSECT CCODE,EXE,NOWRT,QUAD
.ENTRY EXS4,^M<>
PUSHL #4
CALLS #1,G^DECC$EXIT
RET
.END EXS4
7 changes: 7 additions & 0 deletions tests/lab/captures/decc-exit-alpha-20261021/EXSBIG.MAR
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.TITLE EXSBIG OVMX exit-status probe: DECC$EXIT(%X1000002C)
.PSECT CCODE,EXE,NOWRT,QUAD
.ENTRY EXSBIG,^M<>
PUSHL #^X1000002C
CALLS #1,G^DECC$EXIT
RET
.END EXSBIG
7 changes: 7 additions & 0 deletions tests/lab/captures/decc-exit-alpha-20261021/PXS0.MAR
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.TITLE PXS0 OVMX exit-status probe: DECC$__POSIX_EXIT(0)
.PSECT CCODE,EXE,NOWRT,QUAD
.ENTRY PXS0,^M<>
PUSHL #0
CALLS #1,G^DECC$__POSIX_EXIT
RET
.END PXS0
7 changes: 7 additions & 0 deletions tests/lab/captures/decc-exit-alpha-20261021/PXS1.MAR
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.TITLE PXS1 OVMX exit-status probe: DECC$__POSIX_EXIT(1)
.PSECT CCODE,EXE,NOWRT,QUAD
.ENTRY PXS1,^M<>
PUSHL #1
CALLS #1,G^DECC$__POSIX_EXIT
RET
.END PXS1
7 changes: 7 additions & 0 deletions tests/lab/captures/decc-exit-alpha-20261021/PXS2.MAR
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.TITLE PXS2 OVMX exit-status probe: DECC$__POSIX_EXIT(2)
.PSECT CCODE,EXE,NOWRT,QUAD
.ENTRY PXS2,^M<>
PUSHL #2
CALLS #1,G^DECC$__POSIX_EXIT
RET
.END PXS2
7 changes: 7 additions & 0 deletions tests/lab/captures/decc-exit-alpha-20261021/PXS255.MAR
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.TITLE PXS255 OVMX exit-status probe: DECC$__POSIX_EXIT(255)
.PSECT CCODE,EXE,NOWRT,QUAD
.ENTRY PXS255,^M<>
PUSHL #255
CALLS #1,G^DECC$__POSIX_EXIT
RET
.END PXS255
7 changes: 7 additions & 0 deletions tests/lab/captures/decc-exit-alpha-20261021/PXS256.MAR
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.TITLE PXS256 OVMX exit-status probe: DECC$__POSIX_EXIT(256)
.PSECT CCODE,EXE,NOWRT,QUAD
.ENTRY PXS256,^M<>
PUSHL #256
CALLS #1,G^DECC$__POSIX_EXIT
RET
.END PXS256
7 changes: 7 additions & 0 deletions tests/lab/captures/decc-exit-alpha-20261021/PXS3.MAR
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.TITLE PXS3 OVMX exit-status probe: DECC$__POSIX_EXIT(3)
.PSECT CCODE,EXE,NOWRT,QUAD
.ENTRY PXS3,^M<>
PUSHL #3
CALLS #1,G^DECC$__POSIX_EXIT
RET
.END PXS3
37 changes: 37 additions & 0 deletions tests/lab/captures/decc-exit-alpha-20261021/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# DEC C exit() and __posix_exit() completion status on OpenVMS Alpha V8.4 (2026-10-21)

Evidence for rd vms-599. Captured on a disposable lab pod (`exitalpha-1`, node `ALPHA1`,
OpenVMS Alpha V8.4 on AXPbox), driven over the console FIFO with `tools/lab-alpha/`.
The pod and its lab directory were deleted afterwards.

The node has `MACRO` and `LINK` but no C compiler. Each probe is our own MACRO-32
program, which calls the C RTL entry point directly with one value:
`PUSHL #n` / `CALLS #1,G^DECC$EXIT` (or `DECC$__POSIX_EXIT`). The program is then
`MACRO`ed, `LINK`ed and `RUN`, and `F$STRING($STATUS)` is printed (`CONSOLE.txt`).

| call | `$STATUS` |
|---|---|
| `DECC$EXIT(0)` | `%X00000001` |
| `DECC$EXIT(1)` | `%X00000001` |
| `DECC$EXIT(2)` | `%X00000002` (DCL: `%NONAME-E-NOMSG`) |
| `DECC$EXIT(3)` | `%X00000003` |
| `DECC$EXIT(4)` | `%X00000004` (DCL: `%NONAME-F-NOMSG`) |
| `DECC$EXIT(%X1000002C)` | `%X1000002C` |
| `DECC$__POSIX_EXIT(0)` | `%X00000001` |
| `DECC$__POSIX_EXIT(1)` | `%X1035A00A` |
| `DECC$__POSIX_EXIT(2)` | `%X0035A011` |
| `DECC$__POSIX_EXIT(3)` | `%X0035A019` |
| `DECC$__POSIX_EXIT(255)` | `%X0035A7F9` |
| `DECC$__POSIX_EXIT(256)` | `%X00000001` |

So `exit()` turns 0 into SS$_NORMAL and passes every other value through unchanged.
`__posix_exit()` keeps the low eight bits. It turns 0 into `%X00000001` and turns any
other n into `%X0035A001 + (n << 3)`, a C-facility message with success severity.
The one exception is 1: it becomes an error with the message inhibited, `%X1035A00A`.

`EXIT_FAILURE` is a header constant and cannot be observed without a compiler. The VSI
C RTL Reference (exit) groups "a status value of 2 or EXIT_FAILURE" as the error-level
value, which matches the `%X00000002` measured above.

Clean-room: observation only. Nothing was disassembled, and no VSI/HPE source or header
was read.
Loading
Loading