// Copyright (c) 2026 Petr BalvĂ­n (https://petrbalvin.org) // SPDX-License-Identifier: BSD-3-Clause // Package verify provides the dynamic-analysis substrate for gasm: it // JIT-assembles Plan 9 kernels for all four supported architectures // (amd64, arm64, riscv64, loong64) into executable memory and calls them // directly, enabling differential testing against portable Go references, // runtime ABI checks and basic-block coverage profiling. // // The execution model is pure Go, stdlib only, with no cgo: machine code is // mapped with syscall.Mmap and invoked through an assembly trampoline that // switches to a prepared ABI0 stack. The toolchain-comparison helpers in // this package (groundtruth.go) are the one exception, shelling out to the // installed Go toolchain and using its assembler as the differential oracle. package verify import ( "encoding/binary" "fmt" "syscall" "unsafe" ) // Executable maps a copy of code into a read-execute memory region suitable // for direct invocation. The mapping is anonymous and private; the original // slice is not retained. Call Unmap to release the region. type Executable struct { addr uintptr // base address of the mapping size int mem []byte // the mmap'd slice (for Unmap) } // Map copies code into a freshly allocated RX region and returns it. // The mapping is PROT_READ|PROT_EXEC; writes are not permitted after the // copy, matching W^X policy. func Map(code []byte) (*Executable, error) { size := len(code) if size == 0 { return nil, fmt.Errorf("verify: cannot map zero-length code") } // Round up to the page size. const pageSize = 4096 mapSize := (size + pageSize - 1) &^ (pageSize - 1) mem, err := syscall.Mmap(-1, 0, mapSize, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_PRIVATE|syscall.MAP_ANON) if err != nil { return nil, fmt.Errorf("verify: mmap: %w", err) } copy(mem, code) // Remove write permission (W^X). if err := syscall.Mprotect(mem, syscall.PROT_READ|syscall.PROT_EXEC); err != nil { syscall.Munmap(mem) return nil, fmt.Errorf("verify: mprotect: %w", err) } return &Executable{ addr: uintptr(unsafe.Pointer(&mem[0])), size: size, mem: mem, }, nil } // Unmap releases the executable region. func (e *Executable) Unmap() { if e.mem != nil { syscall.Munmap(e.mem) e.mem = nil } } // FuncAddr returns the absolute address of a function at the given offset // within the mapped image. func (e *Executable) FuncAddr(offset int) uintptr { return e.addr + uintptr(offset) } // PutUint64 writes v into buf at byte offset off (little-endian). func PutUint64(buf []byte, off int, v uint64) { binary.LittleEndian.PutUint64(buf[off:off+8], v) } // GetUint64 reads a little-endian uint64 from buf at byte offset off. func GetUint64(buf []byte, off int) uint64 { return binary.LittleEndian.Uint64(buf[off : off+8]) } // PutPtr writes a pointer value into buf at byte offset off. func PutPtr(buf []byte, off int, p unsafe.Pointer) { binary.LittleEndian.PutUint64(buf[off:off+8], uint64(uintptr(p))) }