4 (export "memory" (memory 0))
6 (global $WASI_RIGHT_FD_READ i64 (i64.const 2))
7 (global $WASI_ESUCCESS i32 0)
8 (global $WASI_EBADF i32 8)
9 (global $WASI_PREOPENTYPE_DIR i32 0)
11 (import "wasi_unstable" "args_get" (func $args_get (param i32 i32) (result i32)))
12 (import "wasi_unstable" "args_sizes_get" (func $args_sizes_get (param i32 i32) (result i32)))
13 (import "wasi_unstable" "clock_time_get" (func $clock_time_get (param i32 i64 i32) (result i32)))
14 (import "wasi_unstable" "fd_prestat_get" (func $fd_prestat_get (param i32 i32) (result i32)))
15 (import "wasi_unstable" "fd_prestat_dir_name" (func $fd_prestat_dir_name (param i32 i32 i32) (result i32)))
16 (import "wasi_unstable" "fd_read" (func $fd_read (param i32 i32 i32 i32) (result i32)))
17 (import "wasi_unstable" "fd_write" (func $fd_write (param i32 i32 i32 i32) (result i32)))
18 (import "wasi_unstable" "path_open" (func $path_open (param i32 i32 i32 i32 i32 i64 i64 i32 i32) (result i32)))
19 (import "wasi_unstable" "proc_exit" (func $proc_exit (param i32)))
21 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
23 (func $fatal (param $code i32 $msg i32)
28 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
30 (func $print (param $addr i32)
32 $nwritten_ptr (STATIC_ARRAY 4 4)
33 $iovec (STATIC_ARRAY 8 8))
34 (i32.store $iovec $addr)
35 (i32.store offset=4 $iovec ($strlen $addr))
36 (local.set $ret ($fd_write 1 $iovec 1 $nwritten_ptr))
39 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
41 (func $readline (param $prompt i32 $buf i32) (result i32)
43 $nread_ptr (STATIC_ARRAY 4 4)
44 $iovec (STATIC_ARRAY 8 8))
46 (i32.store $iovec $buf)
47 (i32.store offset=4 $iovec 200) ;; TODO: not hardcoded length
48 (local.set $ret ($fd_read 0 $iovec 1 $nread_ptr))
49 (if (i32.le_s (i32.load $nread_ptr) 0)
51 ;; Replace ending newline with NULL
52 (i32.store8 (i32.add $buf (i32.sub (i32.load $nread_ptr) 1)) 0)
56 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
58 (func $read_file (param $path i32 $buf i32) (result i32)
61 $prestat_ptr (STATIC_ARRAY 8 4)
64 $prepath (STATIC_ARRAY 1024)
67 $fd_ptr (STATIC_ARRAY 4 4)
68 $nread_ptr (STATIC_ARRAY 4 4)
69 $iovec (STATIC_ARRAY 8 8))
71 ;; Find the pre-opened dir fd with the same prefix as the our path
72 ;; following the algorithm at:
73 ;; https://github.com/CraneStation/wasi-sysroot/blob/1cc98f27f5ab8afdc033e16eac8799ee606eb769/libc-bottom-half/crt/crt1.c#L71
74 ;; The matching dir fd is then used to open and read the path.
77 ;; prestat the fd from 3 onward until EBADF is returned
78 (local.set $ret ($fd_prestat_get $fd $prestat_ptr))
79 (if (i32.eq (global.get $WASI_EBADF) $ret)
81 (if (i32.ne (global.get $WASI_ESUCCESS) $ret)
83 (local.set $fd (i32.add 1 $fd))
86 (local.set $pr_type (i32.load $prestat_ptr))
87 (local.set $pr_name_len (i32.load offset=4 $prestat_ptr))
88 ;; Read the pre-opened path name
89 (local.set $ret ($fd_prestat_dir_name $fd $prepath $pr_name_len))
90 (if (i32.ne (global.get $WASI_ESUCCESS) $ret)
92 ;; if pr_name_len includes a null, exclude it from the compare
93 ;;($printf_2 "here1 pr_name_len: %d, char is %d\n" $pr_name_len (i32.load8_u (i32.add $prepath (i32.sub $pr_name_len 1))))
94 (if (i32.eqz (i32.load8_u (i32.add $prepath (i32.sub $pr_name_len 1))))
96 (local.set $pr_name_len (i32.sub $pr_name_len 1))))
97 ;; if it is a dir and the path prefix matches, use it
98 ;;($printf_5 "fd: %d, ret: %d, pr_type: %d, pr_name_len: %d, prepath: %s\n"
99 ;; $fd $ret $pr_type $pr_name_len $prepath)
100 (if (AND (i32.eq $pr_type (global.get $WASI_PREOPENTYPE_DIR))
101 (i32.eqz ($strncmp $prepath $path $pr_name_len)))
103 (local.set $path (i32.add $pr_name_len $path))
104 (local.set $dirfd $fd)
106 (local.set $fd (i32.add 1 $fd))
111 ;;($printf_3 "final dirfd: %d, adjusted path: %s (%d)\n" $dirfd $path ($strlen $path))
113 (if (i32.eq $dirfd -1)
115 ($printf_1 "ERROR: could not find permission for '%s'\n" $orig_path)
118 (local.set $ret ($path_open $dirfd
119 1 ;; dirflags (symlink follow)
123 (global.get $WASI_RIGHT_FD_READ)
124 (global.get $WASI_RIGHT_FD_READ)
127 (if (i32.ne (global.get $WASI_ESUCCESS) $ret)
129 ($printf_2 "ERROR: failed to open '%s', error %d\n" $orig_path $ret)
132 (i32.store $iovec $buf)
133 ;; TODO: use stat result instead of not hardcoded length
134 (i32.store offset=4 $iovec 16384)
135 (local.set $ret ($fd_read (i32.load $fd_ptr) $iovec 1 $nread_ptr))
136 (if (i32.ne (global.get $WASI_ESUCCESS) $ret)
138 ($printf_2 "ERROR: failed to read '%s', error %d\n" $orig_path $ret)
141 ;; Add null to string
142 (i32.store8 (i32.add $buf (i32.load $nread_ptr)) 0)
143 (i32.add 1 (i32.load $nread_ptr))
146 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
148 (func $get_time_ms (result i32)
149 (LET $tv (STATIC_ARRAY 8 8))
150 (drop (call $clock_time_get 0 (i64.const 0) $tv))
152 ;; convert nanoseconds to milliseconds
153 (i64.div_u (i64.load $tv) (i64.const 1000000)))
156 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
158 ;; Returns an i64 with argc in high 32 and argv in low 32.
159 ;; String memory is: argv + (argc * 4)
160 (func $get_argc_argv (result i64)
161 (LET $argc_ptr (STATIC_ARRAY 4 4)
162 $argv_size_ptr (STATIC_ARRAY 4 4)
164 $argv (STATIC_ARRAY 1024 4))
165 (drop ($args_sizes_get $argc_ptr $argv_size_ptr))
166 (local.set $argc (i32.load $argc_ptr))
167 (if (i32.gt_u (i32.add (i32.mul 4 $argc)
168 (i32.load $argv_size_ptr))
170 ($fatal 2 "Command line arguments memory exceeds 1024 bytes"))
171 (drop ($args_get $argv (i32.add $argv (i32.mul 4 $argc))))
172 (i64.or (i64.shl (i64.extend_i32_u $argc) (i64.const 32))
173 (i64.extend_i32_u $argv))
177 (local $argc_argv i64)
179 (local.set $argc_argv ($get_argc_argv))
181 ($main (i32.wrap_i64 (i64.shr_u $argc_argv (i64.const 32)))
182 (i32.wrap_i64 $argc_argv)))
186 (export "_start" (func $entry))