Skip to content

Commit

Permalink
wasys: standalone/unsafe program runner
Browse files Browse the repository at this point in the history
  • Loading branch information
tsavola committed Aug 16, 2018
1 parent 8688906 commit 0075b15
Show file tree
Hide file tree
Showing 10 changed files with 1,429 additions and 0 deletions.
9 changes: 9 additions & 0 deletions cmd/wasys/exec.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Copyright (c) 2018 Timo Savola. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

func exec(textBase, stackLimit, memoryBase, memoryLimit, memoryGrowLimit, stackPtr uintptr)

func callSys()
56 changes: 56 additions & 0 deletions cmd/wasys/exec_amd64.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright (c) 2018 Timo Savola. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

#include "textflag.h"

// func exec(textBase, stackLimit, memoryBase, memoryLimit, memoryGrowLimit, stackPtr uintptr)
TEXT ·exec(SB),NOSPLIT,$0-48
MOVQ textBase+0(FP), R12
MOVQ stackLimit+8(FP), R13
MOVQ memoryBase+16(FP), R14
MOVQ memoryLimit+24(FP), R15
MOVQ memoryGrowLimit+32(FP), BX
MOVQ stackPtr+40(FP), CX

LEAQ traphandler<>(SB), AX
MOVQ AX, M0 // trap handler
MOVQ BX, M1 // memory grow limit
MOVQ CX, SP // stack ptr

XORL AX, AX
XORL BX, BX
XORL CX, CX
XORL BP, BP
XORL SI, SI
XORL DI, DI
XORL R8, R8
XORL R9, R9 // suspend flag

MOVQ R12, DX
ADDQ $16, DX // init code after trap trampoline
JMP DX

TEXT traphandler<>(SB),NOSPLIT,$0
CMPL AX, $0 // exit trap (lower 32 bits)
JE exittrap
ADDL $100, AX // 100 + trap id
JMP sysexit

exittrap:
SHRQ $32, AX // exit code (higher 32 bits)
sysexit:
MOVL AX, DI
MOVL $231, AX // exit_group syscall
SYSCALL

TEXT ·callSys(SB),NOSPLIT,$0
MOVQ R8, R9 // arg 6 (suspend flag)
MOVQ DI, R8 // arg 5
MOVQ SI, R10 // arg 4
MOVQ BP, DX // arg 3
MOVQ BX, SI // arg 2
MOVQ CX, DI // arg 1
SYSCALL
XORL R9, R9 // suspend flag
RET
173 changes: 173 additions & 0 deletions cmd/wasys/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
// Copyright (c) 2018 Timo Savola. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

//go:generate go run ../../internal/cmd/syscalls/generate.go

import (
"bytes"
"flag"
"fmt"
"io/ioutil"
"log"
"os"
"reflect"
"syscall"
"unsafe"

"github.com/tsavola/wag"
"github.com/tsavola/wag/types"
)

var (
verbose = false
)

var importFuncs = make(map[string]uint64)

type env struct{}

func (*env) ImportFunction(module, field string, sig types.Function) (variadic bool, absAddr uint64, err error) {
if verbose {
log.Printf("import %s%s", field, sig)
}

if module != "env" {
err = fmt.Errorf("imported function's module is unknown: %s %s", module, field)
return
}

absAddr = importFuncs[field]
if absAddr == 0 {
err = fmt.Errorf("imported function not supported: %s %s", module, field)
return
}

return
}

func (*env) ImportGlobal(module, field string, t types.T) (valueBits uint64, err error) {
err = fmt.Errorf("imported global not supported: %s %s", module, field)
return
}

type fixedBuf struct {
b []byte
}

func (f *fixedBuf) Bytes() []byte { return f.b }
func (f *fixedBuf) Grow(n int) {}
func (f *fixedBuf) Len() int { return len(f.b) }

func (f *fixedBuf) Write(b []byte) (n int, err error) {
offset := len(f.b)
n = len(b)
f.b = f.b[:len(f.b)+n]
copy(f.b[offset:], b)
return
}

func (f *fixedBuf) WriteByte(b byte) (err error) {
offset := len(f.b)
f.b = f.b[:offset+1]
f.b[offset] = b
return
}

func makeMem(size int, extraProt, extraFlags int) (mem []byte, err error) {
if size > 0 {
mem, err = syscall.Mmap(-1, 0, size, syscall.PROT_READ|syscall.PROT_WRITE|extraProt, syscall.MAP_PRIVATE|syscall.MAP_ANONYMOUS|extraFlags)
}
return
}

func memAddr(mem []byte) uintptr {
return (*reflect.SliceHeader)(unsafe.Pointer(&mem)).Data
}

func main() {
log.SetFlags(0)

flag.Usage = func() {
fmt.Fprintf(flag.CommandLine.Output(), "Usage: %s [options] wasmfile\n\n", os.Args[0])
fmt.Fprintf(flag.CommandLine.Output(), "Options:\n")
flag.PrintDefaults()
}

var (
textSize = 128 * 1024 * 1024
roDataSize = 4 * 1024 * 1024
stackSize = 64 * 1024
entrySymbol = "main"
)

flag.BoolVar(&verbose, "v", verbose, "verbose logging")
flag.IntVar(&textSize, "textsize", textSize, "maximum program text size")
flag.IntVar(&roDataSize, "rodatasize", roDataSize, "maximum read-only data size")
flag.IntVar(&stackSize, "stacksize", stackSize, "call stack size")
flag.StringVar(&entrySymbol, "func", entrySymbol, "function to run")
flag.Parse()

if flag.NArg() != 1 {
flag.Usage()
os.Exit(2)
}
filename := flag.Arg(0)

prog, err := ioutil.ReadFile(filename)
if err != nil {
log.Fatal(err)
}

roDataMem, err := makeMem(roDataSize, 0, syscall.MAP_32BIT)
if err != nil {
log.Fatal(err)
}
roDataAddr := memAddr(roDataMem)

textMem, err := makeMem(textSize, syscall.PROT_EXEC, 0)
if err != nil {
log.Fatal(err)
}
textAddr := memAddr(textMem)
textBuf := &fixedBuf{textMem[:0]}

m := wag.Module{
EntrySymbol: entrySymbol,
EntryArgs: make([]uint64, 2),
}
err = m.Load(bytes.NewReader(prog), &env{}, textBuf, roDataMem, int32(roDataAddr), nil)
if err != nil {
log.Fatal(err)
}

if err := syscall.Mprotect(roDataMem, syscall.PROT_READ); err != nil {
log.Fatal(err)
}

if err := syscall.Mprotect(textMem, syscall.PROT_EXEC); err != nil {
log.Fatal(err)
}

data, memoryOffset := m.Data()
initMemorySize, growMemorySize := m.MemoryLimits()
globalsMemoryMem, err := makeMem(memoryOffset+int(growMemorySize), 0, 0)
if err != nil {
log.Fatal(err)
}
copy(globalsMemoryMem, data)
memoryAddr := memAddr(globalsMemoryMem) + uintptr(memoryOffset)
initMemoryEnd := memoryAddr + uintptr(initMemorySize)
growMemoryEnd := memoryAddr + uintptr(growMemorySize)

stackMem, err := makeMem(stackSize, 0, syscall.MAP_STACK)
if err != nil {
log.Fatal(err)
}
stackAddr := memAddr(stackMem)
stackEnd := stackAddr + uintptr(stackSize)

exec(textAddr, stackAddr, memoryAddr, initMemoryEnd, growMemoryEnd, stackEnd)
}
137 changes: 137 additions & 0 deletions cmd/wasys/syscall.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
// Generated by internal/cmd/syscalls/generate.go

package main

func importRead() uint64
func importWrite() uint64
func importOpen() uint64
func importClose() uint64
func importLseek() uint64
func importPread() uint64
func importPwrite() uint64
func importAccess() uint64
func importPipe() uint64
func importDup() uint64
func importDup2() uint64
func importGetpid() uint64
func importSendfile() uint64
func importShutdown() uint64
func importSocketpair() uint64
func importFlock() uint64
func importFsync() uint64
func importFdatasync() uint64
func importTruncate() uint64
func importFtruncate() uint64
func importGetcwd() uint64
func importChdir() uint64
func importFchdir() uint64
func importRename() uint64
func importMkdir() uint64
func importRmdir() uint64
func importCreat() uint64
func importLink() uint64
func importUnlink() uint64
func importSymlink() uint64
func importReadlink() uint64
func importChmod() uint64
func importFchmod() uint64
func importChown() uint64
func importFchown() uint64
func importLchown() uint64
func importUmask() uint64
func importGetuid() uint64
func importGetgid() uint64
func importVhangup() uint64
func importSync() uint64
func importGettid() uint64
func importTime() uint64
func importPosixFadvise() uint64
func importExit() uint64
func importInotifyInit() uint64
func importInotifyAddWatch() uint64
func importInotifyRmWatch() uint64
func importOpenat() uint64
func importMkdirat() uint64
func importFchownat() uint64
func importUnlinkat() uint64
func importRenameat() uint64
func importLinkat() uint64
func importSymlinkat() uint64
func importReadlinkat() uint64
func importFchmodat() uint64
func importFaccessat() uint64
func importSplice() uint64
func importTee() uint64
func importSyncFileRange() uint64
func importFallocate() uint64
func importEventfd() uint64
func importDup3() uint64
func importPipe2() uint64

func init() {
importFuncs["read"] = importRead()
importFuncs["write"] = importWrite()
importFuncs["open"] = importOpen()
importFuncs["close"] = importClose()
importFuncs["lseek"] = importLseek()
importFuncs["pread"] = importPread()
importFuncs["pwrite"] = importPwrite()
importFuncs["access"] = importAccess()
importFuncs["pipe"] = importPipe()
importFuncs["dup"] = importDup()
importFuncs["dup2"] = importDup2()
importFuncs["getpid"] = importGetpid()
importFuncs["sendfile"] = importSendfile()
importFuncs["shutdown"] = importShutdown()
importFuncs["socketpair"] = importSocketpair()
importFuncs["flock"] = importFlock()
importFuncs["fsync"] = importFsync()
importFuncs["fdatasync"] = importFdatasync()
importFuncs["truncate"] = importTruncate()
importFuncs["ftruncate"] = importFtruncate()
importFuncs["getcwd"] = importGetcwd()
importFuncs["chdir"] = importChdir()
importFuncs["fchdir"] = importFchdir()
importFuncs["rename"] = importRename()
importFuncs["mkdir"] = importMkdir()
importFuncs["rmdir"] = importRmdir()
importFuncs["creat"] = importCreat()
importFuncs["link"] = importLink()
importFuncs["unlink"] = importUnlink()
importFuncs["symlink"] = importSymlink()
importFuncs["readlink"] = importReadlink()
importFuncs["chmod"] = importChmod()
importFuncs["fchmod"] = importFchmod()
importFuncs["chown"] = importChown()
importFuncs["fchown"] = importFchown()
importFuncs["lchown"] = importLchown()
importFuncs["umask"] = importUmask()
importFuncs["getuid"] = importGetuid()
importFuncs["getgid"] = importGetgid()
importFuncs["vhangup"] = importVhangup()
importFuncs["sync"] = importSync()
importFuncs["gettid"] = importGettid()
importFuncs["time"] = importTime()
importFuncs["posix_fadvise"] = importPosixFadvise()
importFuncs["_exit"] = importExit()
importFuncs["inotify_init"] = importInotifyInit()
importFuncs["inotify_add_watch"] = importInotifyAddWatch()
importFuncs["inotify_rm_watch"] = importInotifyRmWatch()
importFuncs["openat"] = importOpenat()
importFuncs["mkdirat"] = importMkdirat()
importFuncs["fchownat"] = importFchownat()
importFuncs["unlinkat"] = importUnlinkat()
importFuncs["renameat"] = importRenameat()
importFuncs["linkat"] = importLinkat()
importFuncs["symlinkat"] = importSymlinkat()
importFuncs["readlinkat"] = importReadlinkat()
importFuncs["fchmodat"] = importFchmodat()
importFuncs["faccessat"] = importFaccessat()
importFuncs["splice"] = importSplice()
importFuncs["tee"] = importTee()
importFuncs["sync_file_range"] = importSyncFileRange()
importFuncs["fallocate"] = importFallocate()
importFuncs["eventfd"] = importEventfd()
importFuncs["dup3"] = importDup3()
importFuncs["pipe2"] = importPipe2()
}
Loading

0 comments on commit 0075b15

Please sign in to comment.