go:linkname使用

1,055 阅读1分钟

阅读sync包的代码时,发现有这种调用方式:pid := runtime_procPin(),但在sync包下找不到这个方法的实现

所以查看了下runtime的代码,发现以下方法:

//go:linkname sync_runtime_procPin sync.runtime_procPin
//go:nosplit
func sync_runtime_procPin() int {
	return procPin()
}

即sync包里进行函数的声明,具体实现是在runtime包

要使用这种调用方式,需要有以下几个条件:

1.添加go编译器指令 go:linkname localname [importpath.name]

2.函数声明 eg: func Hello()

3.提供.s文件,以便编译器绕过 -complete 的检查,允许不完整的函数定义

4.引入unsafe包

实践一下:

创建目录和文件

mkdir demo
cd demo
mkdir runtime
mkdir hello
touch runtime/runtime.go
touch hello/hello.go
touch hello/aa.s
touch main.go

runtime.go

package runtime

import (
   "fmt"
   _ "unsafe" // for go:linkname
)

//go:linkname hello_print demo/hello.Hello
func hello_print() {
   fmt.Println("hello world...")
}

hello.go

package hello

import (
   _ "demo/runtime"
)

func Hello()

main.go

package main

import (
   "demo/hello"
)

func main() {
   hello.Hello()
}

打印出:hello world...