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  }