code wiki / _hdl_build / nx_codegen_exec.nx
nx_codegen_exec.nx source
↩ module page · 78 lines · 3222 B
1// nx_codegen_exec.nx -- shared build/run primitives for the team's codegen-
2// integration capabilities (the differential gate + the candidate self-host
3// verifier both build on this). Pure NishiLang fork/exec: invoke a compiler, link
4// with gcc, run an ELF, capture exit codes -- the sovereign build pipeline the
5// team drives to improve codegen WITHOUT a human running shell. DRY (Cardinal #15).
6
7import "nx_syscalls.nx"
8
9func gd_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
10func gd_emit(name: *u8, v: i64) -> i64 {
11 gd_puts(name)
12 let b: *u8 = sys_mmap(28); var m: i64 = v; if m < 0 { m = 0 - m }
13 let t: *u8 = sys_mmap(28); var k: i64 = 0
14 if m == 0 { t[0] = 48; k = 1 }
15 while m > 0 { t[k] = 48 + (m % 10); m = m / 10; k = k + 1 }
16 var i: i64 = 0; while i < k { b[i] = t[k - 1 - i]; i = i + 1 }
17 b[k] = 10; sys_write(1, b, k + 1); return 0
18}
19
20// fork/exec argv (null-terminated *u8 ptr array). stdout -> out_path if non-null;
21// stderr -> /dev/null if quiet. A minimal PATH is passed so gcc finds cc1/as/ld;
22// the static compilers/ELFs ignore it. Returns the child's exit code (<0 on fork).
23func gd_exec(argv: *i64, out_path: *u8, quiet: i64) -> i64 {
24 let envp: *i64 = sys_mmap(16) as *i64
25 envp[0] = ("PATH=/usr/bin:/bin:/usr/local/bin" as *u8) as i64
26 envp[1] = 0
27 let pid: i64 = sys_fork()
28 if pid < 0 { return 0 - 1000 }
29 if pid == 0 {
30 if out_path != (0 as *u8) {
31 let fd: i64 = sys_openat_wr(out_path, 0x1a4)
32 if fd >= 0 { sys_dup3(fd, 1, 0); sys_close(fd) }
33 }
34 if quiet == 1 {
35 let dn: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4)
36 if dn >= 0 { sys_dup3(dn, 2, 0); sys_close(dn) }
37 }
38 sys_execve(argv[0] as *u8, argv, envp)
39 sys_exit(127)
40 }
41 let status: *i64 = sys_mmap(16) as *i64
42 status[0] = 0
43 sys_wait4(pid, status, 0)
44 return wait_exit_code(status[0])
45}
46
47// compile <src> with <compiler> -> sout (.s) ; link -> eout (.elf). Returns 0 on a
48// clean build, or a negative sentinel (-1 compile, -2 link). Does NOT run.
49func gd_build(compiler: *u8, src: *u8, sout: *u8, eout: *u8) -> i64 {
50 let av: *i64 = sys_mmap(8 * 8) as *i64
51 av[0] = compiler as i64; av[1] = src as i64; av[2] = 0
52 if gd_exec(av, sout, 1) != 0 { return 0 - 1 }
53 av[0] = ("/usr/bin/gcc" as *u8) as i64
54 av[1] = ("-nostdlib" as *u8) as i64
55 av[2] = ("-no-pie" as *u8) as i64
56 av[3] = ("-static" as *u8) as i64
57 av[4] = sout as i64
58 av[5] = ("-o" as *u8) as i64
59 av[6] = eout as i64
60 av[7] = 0
61 if gd_exec(av, 0 as *u8, 1) != 0 { return 0 - 2 }
62 return 0
63}
64
65// run a built ELF, return its exit code (its self-verifying verdict).
66func gd_run(eout: *u8) -> i64 {
67 let av: *i64 = sys_mmap(16) as *i64
68 av[0] = eout as i64; av[1] = 0
69 return gd_exec(av, ("/dev/null" as *u8), 1)
70}
71
72// compile+link+run <src> with <compiler>: returns the run exit code, or a negative
73// sentinel on a pipeline failure.
74func gd_build_run(compiler: *u8, src: *u8, sout: *u8, eout: *u8) -> i64 {
75 let rc: i64 = gd_build(compiler, src, sout, eout)
76 if rc != 0 { return rc }
77 return gd_run(eout)
78}