github.com/cloudwego/frugal@v0.1.15/internal/loader/loader.go (about) 1 /* 2 * Copyright 2022 ByteDance Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package loader 18 19 import ( 20 `fmt` 21 `os` 22 `sync/atomic` 23 `syscall` 24 `unsafe` 25 26 `github.com/cloudwego/frugal/internal/rt` 27 ) 28 29 const ( 30 MAP_BASE = 0x7ff00000000 31 ) 32 33 const ( 34 _AP = syscall.MAP_ANON | syscall.MAP_PRIVATE 35 _RX = syscall.PROT_READ | syscall.PROT_EXEC 36 _RW = syscall.PROT_READ | syscall.PROT_WRITE 37 ) 38 39 type ( 40 Loader []byte 41 Function unsafe.Pointer 42 ) 43 44 var ( 45 FnCount uint32 46 LoadSize uintptr 47 LoadBase uintptr = MAP_BASE 48 ) 49 50 func mkptr(m uintptr) unsafe.Pointer { 51 return *(*unsafe.Pointer)(unsafe.Pointer(&m)) 52 } 53 54 func alignUp(n uintptr, a int) uintptr { 55 return (n + uintptr(a) - 1) &^ (uintptr(a) - 1) 56 } 57 58 func (self Loader) Load(fn string, frame rt.Frame) (f Function) { 59 var mm uintptr 60 var er syscall.Errno 61 62 /* align the size to pages */ 63 nf := uintptr(len(self)) 64 nb := alignUp(nf, os.Getpagesize()) 65 fp := atomic.AddUintptr(&LoadBase, nb) - nb 66 67 /* allocate a block of memory */ 68 if mm, _, er = syscall.Syscall6(syscall.SYS_MMAP, fp, nb, _RW, _AP, 0, 0); er != 0 { 69 panic(er) 70 } 71 72 /* copy code into the memory, and register the function */ 73 copy(rt.BytesFrom(mkptr(mm), len(self), int(nb)), self) 74 registerFunction(fmt.Sprintf("(frugal).%s_%x", fn, mm), mm, nf, frame) 75 76 /* make it executable */ 77 if _, _, err := syscall.Syscall(syscall.SYS_MPROTECT, mm, nb, _RX); err != 0 { 78 panic(err) 79 } 80 81 /* record statistics */ 82 atomic.AddUint32(&FnCount, 1) 83 atomic.AddUintptr(&LoadSize, nb) 84 return Function(&mm) 85 }