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
22 changes: 21 additions & 1 deletion src/vmslink/mk_decc_shr.sh
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,27 @@ if [ "$OVMX_DECC_ARCH" = alpha ]; then
# (x86_64/aarch64) DECC$SHR.
# ovmx_get_libc -- OVMX loader glue (ovmx_libc_stub.c), likewise a
# plain OVMX-original name never decorated.
VEC="$VEC,__init_libc=PROCEDURE,__copy_tls=PROCEDURE,__init_tp=PROCEDURE,ovmx_get_libc=PROCEDURE"
# ___errno_location -- the port's errno ACCESSOR. musl's <errno.h> defines
# `errno` as `(*__errno_location())` (a plain, undecorated C name), so
# EVERY consumer TU that touches errno emits a reference to it. It is
# "musl-internal", NOT a recognized DEC C RTL surface name, so the alpha
# cc1 does NOT decorate it to decc$* and the ^decc$ enumeration above
# misses it -- exactly as it misses __init_tp/__copy_tls. (The DEC-C-
# decorated decc$get_errno_addr IS exported via the bootstrap surface
# above, but that is DEC C's own errno ABI, not the accessor musl-
# compiled consumer code references.)
# NAME FORM: the C symbol is `__errno_location` (two leading
# underscores; that is how GNU nm reports it in libc.a). LINK.EXE's EVAX
# symbol reader represents an external C symbol with ONE leading
# underscore prepended, uniformly for the musl DEFINITION and for every
# consumer REFERENCE -- so at the link/vector level the name is
# `___errno_location` (THREE underscores). A real port consumer that uses
# errno (gzread.c in zlib, and most real C) references `___errno_location`
# and fails %LINK-F-UNDEF without this export; the two-underscore C form
# does NOT match it. Defined in musl-alpha libc.a
# (src/errno/__errno_location.c), resolved by the strict whole-archive
# link below.
VEC="$VEC,__init_libc=PROCEDURE,__copy_tls=PROCEDURE,__init_tp=PROCEDURE,ovmx_get_libc=PROCEDURE,___errno_location=PROCEDURE"

# stdin/stdout/stderr -- the C stdio stream FILE* objects, plain DATA names
# the decc$ filter above cannot catch. The alpha cc1 does NOT decorate the
Expand Down
16 changes: 13 additions & 3 deletions tools/cross-alpha-vms/joint-e2e/build-joint-image.sh
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,19 @@ echo "-- compiling joint_main.obj (cross cc1, -mpointer-size=64) --"
"$ALPHA_CC" -mpointer-size=64 -g0 -c /joint/joint_main.c -o "$OUT/joint_main.obj"

# ---- 6. the JOINT-E2E IMAGE: real crt0 + real main, --use the genuine
# alpha DECC$SHR, STRICT (no --allow-undefined; expect zero deferred) ----
echo "== linking joint-e2e image (strict, expect zero deferred) =="
"$WORK/LINK.EXE" --transfer __main --use "$WORK/DECC\$SHR.EXE" \
# alpha DECC$SHR *and* LIBOTS$SHR, STRICT (no --allow-undefined;
# expect zero deferred) ----
# LIBOTS$SHR.EXE is added to the canonical consumer link recipe alongside
# DECC$SHR.EXE (zlib-crtl-rungs). The alpha-dec-vms port compiler lowers every
# integer divide/remainder to an OTS$DIV_*/OTS$REM_* call (Alpha has no integer-
# divide instruction), and those universals live in the SEPARATE LIBOTS$
# shareable -- DECC$SHR imports OTS$ for its OWN use but does NOT transitively
# re-export it, so a consumer that divides (zlib, and most real C) would defer
# OTS$DIV_UL/OTS$REM_UI against DECC$SHR alone. LINK binds only REFERENCED
# imports, so adding --use LIBOTS$ is inert for programs (like this joint_main)
# that emit no OTS$ call, and closes the gap for those that do.
"$WORK/LINK.EXE" --transfer __main \
--use "$WORK/DECC\$SHR.EXE" --use "$WORK/libots/LIBOTS_SHR.EXE" \
-o "$OUT/joint_e2e.exe" "$OUT/crt0.obj" "$OUT/joint_main.obj"

cp "$WORK/LINK.EXE" "$WORK/DECC\$SHR.EXE" "$WORK/libots/LIBOTS_SHR.EXE" "$OUT/"
Expand Down
59 changes: 59 additions & 0 deletions tools/cross-alpha-vms/musl-arch/arch/alpha-dec-vms/unixio.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* unixio.h -- DEC C UNIX-I/O emulation declarations for the OVMX
* alpha-dec-vms musl port CRTL include surface (bead: zlib-crtl-rungs).
*
* WHAT THIS IS. On a genuine OpenVMS DEC C toolchain, <unixio.h> is the
* CRTL header that declares the UNIX-style low-level I/O emulation entry
* points (open/close/read/write/lseek/... on RMS underneath). Portable C
* that targets VMS routinely does `#ifdef VMS #include <unixio.h>` (zlib's
* zconf.h is the canonical example) because on VMS these decls do NOT come
* from <unistd.h>. The alpha-dec-vms GCC port predefines VMS/__VMS, so that
* `#ifdef VMS` fires -- correctly, it IS a VMS toolchain -- and the compile
* then needs <unixio.h> on the include path.
*
* WHY IT LIVES HERE. The OVMX alpha-dec-vms port's C run-time is musl
* (whole-archived into DECC$SHR.EXE). musl already IMPLEMENTS every one of
* these UNIX-I/O entry points -- this header only DECLARES them (no bodies),
* so it is a faithful, minimal shim: it makes the VMS-only header name
* resolvable without adding or faking any functionality. It is scoped to the
* alpha-dec-vms arch overlay (a VMS-target-only header, exactly as on a real
* DEC C kit), never surfaced for a non-VMS target.
*
* Signatures track musl's own <unistd.h>/<fcntl.h> declarations exactly, so a
* translation unit that includes BOTH <unixio.h> and <unistd.h> sees identical
* prototypes (no conflicting-declaration diagnostic). Types come from
* <sys/types.h> (size_t/ssize_t/off_t/mode_t), same as the real header.
*
* CLEAN-ROOM (Rule 8): declarations derived from the public DEC C RTL
* Reference Manual's <unixio.h> surface + musl's own prototypes. No VSI/HPE
* header source was read or copied.
*/
#ifndef _OVMX_UNIXIO_H
#define _OVMX_UNIXIO_H

#include <sys/types.h>

#ifdef __cplusplus
extern "C" {
#endif

int open(const char *, int, ...);
int close(int);
ssize_t read(int, void *, size_t);
ssize_t write(int, const void *, size_t);
off_t lseek(int, off_t, int);
int dup(int);
int dup2(int, int);
int isatty(int);
int unlink(const char *);
int access(const char *, int);
int ftruncate(int, off_t);
int fsync(int);
int chdir(const char *);
char *getcwd(char *, size_t);

#ifdef __cplusplus
}
#endif

#endif /* _OVMX_UNIXIO_H */