WebAssembly原理与核心技术
上QQ阅读APP看书,第一时间看更新

2.4 实现dump命令

在2.1节和2.2节,我们定义好了模块的内存表示。在2.3节,我们讨论了如何解码二进制模块。有了这两项基础,我们就可以自己写一个wasm-objdump工具了。Go工程的最佳实践是把命令行工具统一放在项目的cmd包里,我们也采用这种做法,下面是本章代码的完整目录结构。


code/go/ch02/wasm.go/
├── binary/
├── cmd/
│   └── wasmgo/
│       ├── dumper.go
│       └── main.go
├── go.mod
└── go.sum

相比模块的解码逻辑,打印逻辑更为简单,有关代码全部在dumper.go文件里。下面给出main.go文件的全部代码。


package main
import (

    "flag"
    "fmt"
    "os"
    "wasm.go/binary"
)

func main() {
    dumpFlag := flag.Bool("d", false, "dump")
    flag.Parse()
    if flag.NArg() != 1 {
        fmt.Println("Usage: wasmgo [-d] filename")
        os.Exit(1)
    }

    module, err := binary.DecodeFile(flag.Args()[0])
    if err != nil {
        fmt.Println(err.Error())
        os.Exit(1)
    }

    if *dumpFlag {
        dump(module) // 在dumper.go文件里
    }
}

执行命令查看结果。


$ cd code/go/ch02/wasm.go/
$ go run wasm.go/cmd/wasmgo -d ../../../js/ch01_hw.wasm
Version: 0x01
Type[5]:
  type[0]: (i32)->()
  type[1]: ()->()
  type[2]: (i32,i32)->(i32)
  type[3]: (i32)->(i32)
  type[4]: (i32,i32,i32)->()
Import[1]:
  func[0]: env.print_char, sig=0
Function[11]:
  func[1]: sig=1
  func[2]: sig=2
  ...
Table[1]:
  table[0]: {min: 1, max: 1}
Memory[1]:
  memory[0]: {min: 17, max: 0}
Global[3]:
  global[0]: {type: i32, mut: 1}
  global[1]: {type: i32, mut: 0}
  global[2]: {type: i32, mut: 0}
Export[4]:
  memory[0]: name=memory
  global[1]: name=__data_end
  global[2]: name=__heap_base
  func[1]: name=main
Start:
Element[0]:
Code[11]:
  func[1]: locals=[i32 x 22]
  func[2]: locals=[i32 x 1]
  ...
Data[1]:
  data[0]: mem=0
Custom[1]:
  custom[0]: name=name