diff --git a/build.sh b/build.sh deleted file mode 100755 index c9905a9..0000000 --- a/build.sh +++ /dev/null @@ -1,11 +0,0 @@ -#! /bin/sh -e -cd "cmd/land" -vgo build -o ../../bin/land -cd "../../userland/src/lib" -node ../../compile.js counter.walt counter.wasm -node ../../compile.js memory.walt memory.wasm -wat2wasm -o add.wasm add.wast -wat2wasm -o env.wasm env.wast -wat2wasm -o hello.wasm hello.wast -cd "../../.." -go test -v ./cmd/land | tee bin/test.log diff --git a/cmd/land/process.go b/cmd/land/process.go index 04406f6..30d0072 100644 --- a/cmd/land/process.go +++ b/cmd/land/process.go @@ -6,6 +6,7 @@ import ( "io" "os" "reflect" + "strings" "github.com/Xe/ln" "github.com/go-interpreter/wagon/exec" @@ -17,10 +18,10 @@ import ( // Process is a larger level wrapper around a webassembly VM that gives it // system call access. type Process struct { - id int32 - vm *exec.VM - mod *wasm.Module - fs afero.Fs + id int32 + vm *exec.VM + mod *wasm.Module + fs afero.Fs files []afero.File } @@ -44,6 +45,7 @@ func NewProcess(fin io.Reader) (*Process, error) { p.mod = mod p.vm = vm + p.fs = afero.NewMemMapFs() return p, nil } @@ -59,6 +61,11 @@ func (p *Process) importer(name string) (*wasm.Module, error) { ParamTypes: []wasm.ValueType{wasm.ValueTypeI32, wasm.ValueTypeI32}, ReturnTypes: []wasm.ValueType{wasm.ValueTypeI32}, }, + { + Form: 0, + ParamTypes: []wasm.ValueType{wasm.ValueTypeI32, wasm.ValueTypeI32, wasm.ValueTypeI32}, + ReturnTypes: []wasm.ValueType{wasm.ValueTypeI32}, + }, }, } m.FunctionIndexSpace = []wasm.Function{ @@ -67,6 +74,16 @@ func (p *Process) importer(name string) (*wasm.Module, error) { Host: reflect.ValueOf(p.log), Body: &wasm.FunctionBody{}, }, + { + Sig: &m.Types.Entries[0], + Host: reflect.ValueOf(p.open), + Body: &wasm.FunctionBody{}, + }, + { + Sig: &m.Types.Entries[1], + Host: reflect.ValueOf(p.write), + Body: &wasm.FunctionBody{}, + }, } m.Export = &wasm.SectionExports{ Entries: map[string]wasm.ExportEntry{ @@ -75,6 +92,16 @@ func (p *Process) importer(name string) (*wasm.Module, error) { Kind: wasm.ExternalFunction, Index: 0, }, + "open": { + FieldStr: "open", + Kind: wasm.ExternalFunction, + Index: 1, + }, + "write": { + FieldStr: "write", + Kind: wasm.ExternalFunction, + Index: 2, + }, }, } return m, nil @@ -146,6 +173,44 @@ func (p *Process) readMem(ptr int32) []byte { return result } +func (p *Process) open(fnamesP int32, flags int32) int32 { + str := string(p.readMem(fnamesP)) + + var fi afero.File + var err error + switch str { + case "magic://stdout": + fi, err = afero.OsFs{}.Create("/dev/stdout") + + default: + fi, err = p.fs.OpenFile(string(str), int(flags), 0666) + if err != nil { + if strings.Contains(err.Error(), afero.ErrFileNotFound.Error()) { + fi, err = p.fs.Create(str) + } + } + } + + if err != nil { + panic(err) + } + + fd := len(p.files) + p.files = append(p.files, fi) + + return int32(fd) +} + +func (p *Process) write(fd int32, ptr int32, len int32) int32 { + data := p.vm.Memory()[ptr : ptr+len] + n, err := p.files[fd].Write(data) + if err != nil { + panic(err) + } + + return int32(n) +} + func (p *Process) Main() (uint32, error) { foundMain := false mainID := uint32(0) diff --git a/cmd/land/process_test.go b/cmd/land/process_test.go index 9466b3f..72f32a5 100644 --- a/cmd/land/process_test.go +++ b/cmd/land/process_test.go @@ -5,6 +5,28 @@ import ( "testing" ) +func testWasmFile(t *testing.T, fname string) { + fin, err := os.Open(fname) + if err != nil { + t.Fatal(err) + } + defer fin.Close() + + p, err := NewProcess(fin) + if err != nil { + t.Fatal(err) + } + + ret, err := p.Main() + if err != nil { + t.Fatal(err) + } + + if ret != 0 { + t.Fatalf("expected return code to be 0, got: %d", ret) + } +} + func TestHelloWorld(t *testing.T) { fin, err := os.Open("./testdata/hello.wasm") if err != nil { @@ -41,3 +63,7 @@ func TestHelloWorld(t *testing.T) { t.Fatalf("wanted \"goodbye\", got: %q", string(data)) } } + +func TestWriteFile(t *testing.T) { + testWasmFile(t, "./testdata/writefile.wasm") +} diff --git a/cmd/land/testdata/writefile.wasm b/cmd/land/testdata/writefile.wasm new file mode 100644 index 0000000..0ddedad Binary files /dev/null and b/cmd/land/testdata/writefile.wasm differ diff --git a/go.mod b/go.mod index f172049..1ed5346 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module git.xeserv.us/xena/land require ( github.com/Xe/ln v0.0.0-20180508032019-ae4f7456500d github.com/go-interpreter/wagon v0.0.0-20180520092357-d4bc452fd57e + github.com/kr/pretty v0.1.0 github.com/pkg/errors v0.8.0 github.com/spf13/afero v1.1.1 golang.org/x/text v0.3.0 diff --git a/go.modverify b/go.modverify index a2d893c..33b5bef 100644 --- a/go.modverify +++ b/go.modverify @@ -1,5 +1,7 @@ github.com/Xe/ln v0.0.0-20180508032019-ae4f7456500d h1:dQgIfnQayXRfcxefFjA7rfL2hIouSrIEiOyB2hypQTw= github.com/go-interpreter/wagon v0.0.0-20180520092357-d4bc452fd57e h1:l4e38KpmR/OxRvJrZtqQ0yFwuGH8ta8ZZkOA+h5ovPg= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw= github.com/spf13/afero v1.1.1 h1:Lt3ihYMlE+lreX1GS4Qw4ZsNpYQLxIXKBTEOXm3nt6I= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= diff --git a/userland/src/lib/writefile.wast b/userland/src/lib/writefile.wast new file mode 100644 index 0000000..b16b279 --- /dev/null +++ b/userland/src/lib/writefile.wast @@ -0,0 +1,16 @@ +(module + (func $open (import "env" "open") (param i32 i32) (result i32)) + (func $write (import "env" "write") (param i32 i32 i32) (result i32)) + (memory $mem 1) + (data (i32.const 200) "stdout") + (data (i32.const 230) "Hello, world!\n") + (func $main (result i32) + (i32.const 200) + (i32.const 42) + (call $open) + (i32.const 230) + (i32.const 14) + (call $write) + (drop) + (i32.const 0)) + (export "main" (func $main)))