wa-lang.org/wazero@v1.0.2/internal/platform/mmap.go (about)

     1  // This uses syscall.Mprotect. Go's SDK only supports this on darwin and linux.
     2  //go:build darwin || linux || freebsd
     3  
     4  package platform
     5  
     6  import (
     7  	"io"
     8  	"syscall"
     9  	"unsafe"
    10  )
    11  
    12  func munmapCodeSegment(code []byte) error {
    13  	return syscall.Munmap(code)
    14  }
    15  
    16  // mmapCodeSegmentAMD64 gives all read-write-exec permission to the mmap region
    17  // to enter the function. Otherwise, segmentation fault exception is raised.
    18  func mmapCodeSegmentAMD64(code io.Reader, size int) ([]byte, error) {
    19  	mmapFunc, err := syscall.Mmap(
    20  		-1,
    21  		0,
    22  		size,
    23  		// The region must be RWX: RW for writing native codes, X for executing the region.
    24  		syscall.PROT_READ|syscall.PROT_WRITE|syscall.PROT_EXEC,
    25  		// Anonymous as this is not an actual file, but a memory,
    26  		// Private as this is in-process memory region.
    27  		syscall.MAP_ANON|syscall.MAP_PRIVATE,
    28  	)
    29  	if err != nil {
    30  		return nil, err
    31  	}
    32  
    33  	w := &bufWriter{underlying: mmapFunc}
    34  	_, err = io.CopyN(w, code, int64(size))
    35  	return mmapFunc, err
    36  }
    37  
    38  // mmapCodeSegmentARM64 cannot give all read-write-exec permission to the mmap region.
    39  // Otherwise, the mmap systemcall would raise an error. Here we give read-write
    40  // to the region at first, write the native code and then change the perm to
    41  // read-exec, so we can execute the native code.
    42  func mmapCodeSegmentARM64(code io.Reader, size int) ([]byte, error) {
    43  	mmapFunc, err := syscall.Mmap(
    44  		-1,
    45  		0,
    46  		size,
    47  		// The region must be RW: RW for writing native codes.
    48  		syscall.PROT_READ|syscall.PROT_WRITE,
    49  		// Anonymous as this is not an actual file, but a memory,
    50  		// Private as this is in-process memory region.
    51  		syscall.MAP_ANON|syscall.MAP_PRIVATE,
    52  	)
    53  	if err != nil {
    54  		return nil, err
    55  	}
    56  
    57  	w := &bufWriter{underlying: mmapFunc}
    58  	_, err = io.CopyN(w, code, int64(size))
    59  	if err != nil {
    60  		return nil, err
    61  	}
    62  
    63  	// Then we're done with writing code, change the permission to RX.
    64  	err = mprotect(mmapFunc, syscall.PROT_READ|syscall.PROT_EXEC)
    65  	return mmapFunc, err
    66  }
    67  
    68  var _zero uintptr
    69  
    70  // mprotect is like syscall.Mprotect, defined locally so that freebsd compiles.
    71  func mprotect(b []byte, prot int) (err error) {
    72  	var _p0 unsafe.Pointer
    73  	if len(b) > 0 {
    74  		_p0 = unsafe.Pointer(&b[0])
    75  	} else {
    76  		_p0 = unsafe.Pointer(&_zero)
    77  	}
    78  	_, _, e1 := syscall.Syscall(syscall.SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot))
    79  	if e1 != 0 {
    80  		err = syscall.Errno(e1)
    81  	}
    82  	return
    83  }