Skip to content

Commit

Permalink
feat: support for Windows
Browse files Browse the repository at this point in the history
* fix (loader): default loader now has build tag: for linux and darwin
* feat (loader): add memory allocator support for Windows
  • Loading branch information
ii64 committed May 19, 2022
1 parent 5086cb2 commit 7566192
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 8 deletions.
3 changes: 3 additions & 0 deletions internal/loader/loader.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
//go:build linux || darwin
// +build linux darwin

/*
* Copyright 2021 ByteDance Inc.
*
Expand Down
112 changes: 112 additions & 0 deletions internal/loader/loader_windows_amd64.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/*
* Copyright 2021 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package loader

import (
`fmt`
`os`
`reflect`
`syscall`
`unsafe`
)

const (
MEM_COMMIT = 0x00001000
MEM_RESERVE = 0x00002000
)

var (
libKernel32 = syscall.NewLazyDLL("KERNEL32.DLL")
libKernel32_VirtualAlloc = libKernel32.NewProc("VirtualAlloc")
libKernel32_VirtualProtect = libKernel32.NewProc("VirtualProtect")
)

type Loader []byte
type Function unsafe.Pointer

func (self Loader) LoadWithFaker(fn string, fp int, args int, faker interface{}) (f Function) {
p := os.Getpagesize()
n := (((len(self) - 1) / p) + 1) * p

/* register the function */
m := mmap(n)
v := fmt.Sprintf("runtime.__%s_%x", fn, m)
argsptr, localsptr := stackMap(faker)
registerFunction(v, m, uintptr(n), fp, args, uintptr(len(self)), argsptr, localsptr)

/* reference as a slice */
s := *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader {
Data : m,
Cap : n,
Len : len(self),
}))

/* copy the machine code, and make it executable */
copy(s, self)
mprotect(m, n)
return Function(&m)
}

func (self Loader) Load(fn string, fp int, args int) (f Function) {
return self.LoadWithFaker(fn, fp, args, func(){})
}

func mmap(nb int) uintptr {
addr, err := winapi_VirtualAlloc(0, nb, MEM_COMMIT|MEM_RESERVE, syscall.PAGE_READWRITE)
if err != nil {
panic(err)
}
return addr
}

func mprotect(p uintptr, nb int) (oldProtect int) {
err := winapi_VirtualProtect(p, nb, syscall.PAGE_EXECUTE_READ, &oldProtect)
if err != nil {
panic(err)
}
return
}

// winapi_VirtualAlloc allocate memory
// Doc: https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualalloc
func winapi_VirtualAlloc(lpAddr uintptr, dwSize int, flAllocationType int, flProtect int) (uintptr, error) {
r1, _, err := libKernel32_VirtualAlloc.Call(
lpAddr,
uintptr(dwSize),
uintptr(flAllocationType),
uintptr(flProtect),
)
if r1 == 0 {
return 0, err
}
return r1, nil
}

// winapi_VirtualProtect change memory protection
// Doc: https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualprotect
func winapi_VirtualProtect(lpAddr uintptr, dwSize int, flNewProtect int, lpflOldProtect *int) error {
r1, _, err := libKernel32_VirtualProtect.Call(
lpAddr,
uintptr(dwSize),
uintptr(flNewProtect),
uintptr(unsafe.Pointer(lpflOldProtect)),
)
if r1 == 0 {
return err
}
return nil
}
16 changes: 8 additions & 8 deletions issue_test/plugin_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// +build !race
//go:build (linux && !race) || (unix && !race)
// +build linux,!race unix,!race

/*
* Copyright 2021 ByteDance Inc.
Expand All @@ -23,9 +24,9 @@ import (
`fmt`
`os/exec`
`plugin`
`reflect`
`runtime`
`testing`
`reflect`

_ `github.com/bytedance/sonic`
)
Expand All @@ -37,8 +38,8 @@ func buildPlugin() {
panic(err)
}
cmd0 := exec.Cmd{
Path: bin0,
Args: []string{"rm", "-f", "plugin/plugin."+runtime.Version()+".so"},
Path: bin0,
Args: []string{"rm", "-f", "plugin/plugin." + runtime.Version() + ".so"},
Stdout: out,
Stderr: out,
}
Expand All @@ -51,8 +52,8 @@ func buildPlugin() {
panic(err)
}
cmd := exec.Cmd{
Path: bin,
Args: []string{"go", "build", "-buildmode", "plugin", "-o", "plugin/plugin."+runtime.Version()+".so", "plugin/main.go"},
Path: bin,
Args: []string{"go", "build", "-buildmode", "plugin", "-o", "plugin/plugin." + runtime.Version() + ".so", "plugin/main.go"},
Stdout: out,
Stderr: out,
}
Expand All @@ -61,10 +62,9 @@ func buildPlugin() {
}
}


func TestPlugin(t *testing.T) {
buildPlugin()
p, err := plugin.Open("plugin/plugin."+runtime.Version()+".so")
p, err := plugin.Open("plugin/plugin." + runtime.Version() + ".so")
if err != nil {
t.Fatal(err)
}
Expand Down

0 comments on commit 7566192

Please sign in to comment.