github.com/bananabytelabs/wazero@v0.0.0-20240105073314-54b22a776da8/internal/gojs/argsenv.go (about) 1 package gojs 2 3 import ( 4 "encoding/binary" 5 "errors" 6 7 "github.com/bananabytelabs/wazero/api" 8 "github.com/bananabytelabs/wazero/internal/gojs/util" 9 "github.com/bananabytelabs/wazero/internal/wasm" 10 ) 11 12 // Constants about memory layout. See REFERENCE.md 13 const ( 14 endOfPageZero = uint32(4096) // runtime.minLegalPointer 15 maxArgsAndEnviron = uint32(8192) // ld.wasmMinDataAddr - runtime.minLegalPointer 16 wasmMinDataAddr = endOfPageZero + maxArgsAndEnviron // ld.wasmMinDataAddr 17 ) 18 19 var le = binary.LittleEndian 20 21 // WriteArgsAndEnviron writes arguments and environment variables to memory, so 22 // they can be read by main, Go compiles as the function export "run". 23 func WriteArgsAndEnviron(mod api.Module) (argc, argv uint32, err error) { 24 mem := mod.Memory() 25 sysCtx := mod.(*wasm.ModuleInstance).Sys 26 args := sysCtx.Args() 27 environ := sysCtx.Environ() 28 29 argc = uint32(len(args)) 30 offset := endOfPageZero 31 32 strPtr := func(val []byte, field string, i int) (ptr uint32) { 33 // TODO: return err and format "%s[%d], field, i" 34 ptr = offset 35 util.MustWrite(mem, field, offset, append(val, 0)) 36 offset += uint32(len(val) + 1) 37 if pad := offset % 8; pad != 0 { 38 offset += 8 - pad 39 } 40 return 41 } 42 43 argvPtrLen := len(args) + 1 + len(environ) + 1 44 argvPtrs := make([]uint32, 0, argvPtrLen) 45 for i, arg := range args { 46 argvPtrs = append(argvPtrs, strPtr(arg, "args", i)) 47 } 48 argvPtrs = append(argvPtrs, 0) 49 50 for i, env := range environ { 51 argvPtrs = append(argvPtrs, strPtr(env, "env", i)) 52 } 53 argvPtrs = append(argvPtrs, 0) 54 55 argv = offset 56 57 stop := uint32(argvPtrLen << 3) // argvPtrLen * 8 58 if offset+stop >= wasmMinDataAddr { 59 err = errors.New("total length of command line and environment variables exceeds limit") 60 } 61 62 buf, ok := mem.Read(argv, stop) 63 if !ok { 64 panic("out of memory reading argvPtrs") 65 } 66 pos := uint32(0) 67 for _, ptr := range argvPtrs { 68 le.PutUint64(buf[pos:], uint64(ptr)) 69 pos += 8 70 } 71 72 return 73 }