ww: driver shells to wwstage tools
build_one now invokes 6c_ww / 6a_ww / 6l_ww from $self_dir, not the C-built binaries that share the directory. After this change `ww_ww build foo.ww` touches no cstage code at runtime — the fresh-checkout cstage is still needed to bring the wwstage into existence, but day-to-day work runs on the ww toolchain end to end. The C `ww` driver in cmd/ww/ still drives the C 6c/6a/6l. Test 993 (which used to be trivial — both drivers invoked the same C tools) now meaningfully compares the cstage pipeline against the wwstage pipeline on hello + wwdump and confirms byte-identical exes. The .combined.ww files for 6a/6l/ww/wwdump and smoke are regenerated by the ww driver's `expand()` step; their diff is the lib/os dup2 wrapper and the cgen.ww port from the prior two commits, propagating into the bootstrap inputs.
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
@symbol("rt_syscall") fn syscall1(num: i64, a: i64) i64;
|
||||
@symbol("rt_syscall") fn syscall2(num: i64, a: i64, b: i64) i64;
|
||||
@symbol("rt_syscall") fn syscall3(num: i64, a: i64, b: i64, c: i64) i64;
|
||||
@symbol("rt_syscall") fn syscall4(num: i64, a: i64, b: i64, c: i64, d: i64) i64;
|
||||
|
||||
@symbol("rt_alloc") fn alloc(n: u64) *void;
|
||||
@symbol("rt_free") fn free(p: *void, n: u64) void;
|
||||
@@ -17,12 +18,18 @@ export fn assert(cond: bool, msg: str) void = {
|
||||
if (!cond) { abort(msg); };
|
||||
};
|
||||
|
||||
def SYS_READ: i64 = 0;
|
||||
def SYS_WRITE: i64 = 1;
|
||||
def SYS_OPEN: i64 = 2;
|
||||
def SYS_CLOSE: i64 = 3;
|
||||
def SYS_LSEEK: i64 = 8;
|
||||
def SYS_EXIT: i64 = 60;
|
||||
def SYS_READ: i64 = 0;
|
||||
def SYS_WRITE: i64 = 1;
|
||||
def SYS_OPEN: i64 = 2;
|
||||
def SYS_CLOSE: i64 = 3;
|
||||
def SYS_LSEEK: i64 = 8;
|
||||
def SYS_ACCESS: i64 = 21;
|
||||
def SYS_GETPID: i64 = 39;
|
||||
def SYS_FORK: i64 = 57;
|
||||
def SYS_EXECVE: i64 = 59;
|
||||
def SYS_EXIT: i64 = 60;
|
||||
def SYS_WAIT4: i64 = 61;
|
||||
def SYS_UNLINK: i64 = 87;
|
||||
|
||||
// open(2) flags. Linux values, matching <fcntl.h>.
|
||||
def O_RDONLY: i32 = 0;
|
||||
@@ -127,6 +134,42 @@ export fn writefull(fd: i32, buf: *u8, n: u64) i64 = {
|
||||
return sent: i64;
|
||||
};
|
||||
|
||||
// ---- process and filesystem helpers used by the `ww` driver ----------
|
||||
|
||||
// access(2): returns 0 if the file is reachable, negative errno
|
||||
// otherwise. mode is the bitset described in <unistd.h> (F_OK=0).
|
||||
export fn access(path: *u8, mode: i32) i32 = {
|
||||
return syscall2(SYS_ACCESS, path: i64, mode: i64): i32;
|
||||
};
|
||||
|
||||
// unlink(2).
|
||||
export fn unlink(path: *u8) i32 = {
|
||||
return syscall1(SYS_UNLINK, path: i64): i32;
|
||||
};
|
||||
|
||||
// getpid(2). Used by the driver to mint unique scratch paths.
|
||||
export fn getpid() i32 = {
|
||||
return syscall0(SYS_GETPID): i32;
|
||||
};
|
||||
|
||||
// fork(2): 0 in the child, child pid in the parent, negative errno
|
||||
// on failure.
|
||||
export fn fork() i32 = {
|
||||
return syscall0(SYS_FORK): i32;
|
||||
};
|
||||
|
||||
// execve(2): on success, does not return.
|
||||
export fn execve(path: *u8, argv: **u8, envp: **u8) i32 = {
|
||||
return syscall3(SYS_EXECVE, path: i64, argv: i64, envp: i64): i32;
|
||||
};
|
||||
|
||||
// wait4(2): wait for `pid` (or any child if -1), store status in
|
||||
// `*status_out`, return the pid that ended (or negative errno).
|
||||
export fn wait4(pid: i32, status_out: *i32, options: i32, rusage: *void) i32 = {
|
||||
return syscall4(SYS_WAIT4, pid: i64, status_out: i64,
|
||||
options: i64, rusage: i64): i32;
|
||||
};
|
||||
|
||||
// selfhost/cmd/wwc/mem.ww — port of cmd/wwc/mem.c.
|
||||
//
|
||||
// Bump arena allocator. Backed by the runtime page allocator
|
||||
|
||||
Reference in New Issue
Block a user