github.com/wasilibs/wazerox@v0.0.0-20240124024944-4923be63ab5f/internal/platform/mmap_unix.go (about)

     1  //go:build darwin || linux || freebsd
     2  
     3  package platform
     4  
     5  import (
     6  	"syscall"
     7  	"unsafe"
     8  )
     9  
    10  const (
    11  	mmapProtAMD64 = syscall.PROT_READ | syscall.PROT_WRITE | syscall.PROT_EXEC
    12  	mmapProtARM64 = syscall.PROT_READ | syscall.PROT_WRITE
    13  )
    14  
    15  func mmapMemory(size int) ([]byte, error) {
    16  	return syscall.Mmap(
    17  		-1,
    18  		0,
    19  		size,
    20  		syscall.PROT_READ|syscall.PROT_WRITE,
    21  		// Anonymous as this is not an actual file, but a memory,
    22  		// Private as this is in-process memory region.
    23  		syscall.MAP_ANON|syscall.MAP_PRIVATE,
    24  	)
    25  }
    26  
    27  func munmapCodeSegment(code []byte) error {
    28  	return syscall.Munmap(code)
    29  }
    30  
    31  // mmapCodeSegmentAMD64 gives all read-write-exec permission to the mmap region
    32  // to enter the function. Otherwise, segmentation fault exception is raised.
    33  func mmapCodeSegmentAMD64(size int) ([]byte, error) {
    34  	// The region must be RWX: RW for writing native codes, X for executing the region.
    35  	return mmapCodeSegment(size, mmapProtAMD64)
    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 so that we can write contents at call-sites. Callers are responsible to
    41  // execute MprotectRX on the returned buffer.
    42  func mmapCodeSegmentARM64(size int) ([]byte, error) {
    43  	// The region must be RW: RW for writing native codes.
    44  	return mmapCodeSegment(size, mmapProtARM64)
    45  }
    46  
    47  // MprotectRX is like syscall.Mprotect with RX permission, defined locally so that freebsd compiles.
    48  func MprotectRX(b []byte) (err error) {
    49  	var _p0 unsafe.Pointer
    50  	if len(b) > 0 {
    51  		_p0 = unsafe.Pointer(&b[0])
    52  	}
    53  	const prot = syscall.PROT_READ | syscall.PROT_EXEC
    54  	_, _, e1 := syscall.Syscall(syscall.SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot))
    55  	if e1 != 0 {
    56  		err = syscall.Errno(e1)
    57  	}
    58  	return
    59  }