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 }