在Go语言中, package中包含函数与变量经过identifier的首字母是否大写来决定它是否能够被其它package所访问。当一个函数或变量名称为小写字母时,默认是没法被其余package引用的.
有没有办法突破这个限制呢?
实际上在go官方文档中已有说明, 这须要用到一个编译器指令 安全
//go:linkname localname importpath.name ide
官方的解释是: 模块化
The //go:linkname directive instructs the compiler to use “importpath.name” as the object file symbol name for the variable or function declared as “localname” in the source code. Because this directive can subvert the type system and package modularity, it is only enabled in files that have imported "unsafe". 函数
//go:linkname指令指示编译器使用importpath.name做为源代码中声明为localname的变量或函数的对象文件符号名。由于这个指令能够破坏类型系统和包的模块化,因此它只在导入“不安全”的文件中启用。ui
个人理解就是使用localname做为当前package本地函数或变量名称,关联到importpath.name实际的符号引用.实际上locaname只是一个做为连接符号,这个跟WINDOWS中的DLL符号关联有点相似.this
示例
如下示例引用了runtime.sysMmap一系列私有函数与变量,用于建立一个huagepage共享内存区域
code
package main /* #cgo CFLAGS: #include <sys/types.h> #include <sys/mman.h> #include <sys/signal.h> #include <sys/time.h> #include <sys/ucontext.h> #include <sys/unistd.h> #include <errno.h> #include <signal.h> */ import "C" import ( "fmt" "os" "encoding/hex" "syscall" "reflect" _ "runtime" "unsafe" "os/exec" ) const ( PROT_NONE = C.PROT_NONE PROT_READ = C.PROT_READ PROT_WRITE = C.PROT_WRITE PROT_EXEC = C.PROT_EXEC MAP_SHARED = 0x1 MAP_ANON = C.MAP_ANONYMOUS MAP_PRIVATE = C.MAP_PRIVATE MAP_FIXED = C.MAP_FIXED ) //go:linkname physPageSize runtime.physPageSize //go:linkname callCgoMmap runtime.callCgoMmap //go:linkname callCgoMunmap runtime.callCgoMunmap //go:linkname sysMmap runtime.sysMmap //go:linkname sysMunmap runtime.sysMunmap //go:linkname Mmap runtime.mmap //go:linkname Munmap runtime.munmap // sysMmap calls the mmap system call. It is implemented in assembly. func sysMmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) (p unsafe.Pointer, err int) // callCgoMmap calls the mmap function in the runtime/cgo package // using the GCC calling convention. It is implemented in assembly. func callCgoMmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) uintptr // sysMunmap calls the munmap system call. It is implemented in assembly. func sysMunmap(addr unsafe.Pointer, n uintptr) // callCgoMunmap calls the munmap function in the runtime/cgo package // using the GCC calling convention. It is implemented in assembly. func callCgoMunmap(addr unsafe.Pointer, n uintptr) func Mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) (p unsafe.Pointer, err int) func Munmap(addr unsafe.Pointer, n uintptr) var physPageSize uintptr const ( ENOMEM = 12 ) func GetPhysPageSize() uintptr { return physPageSize } func TestHugePage() { file := "/dev/hugepages/hp" f, err := os.OpenFile(file, os.O_CREATE|os.O_RDWR, 0644) if err != nil { fmt.Printf("Open: %v", err) return } var length uintptr = 2 * 1024 * 1024; var flags int32 = MAP_SHARED; var proto int32 = PROT_READ|PROT_WRITE; addr, e := sysMmap(nil, length, proto, flags, int32(f.Fd()), 0) if e != 0 { fmt.Printf("Mmap occur error %d\n", e); return } fmt.Printf("Mmap %p\n", addr); var x reflect.SliceHeader x.Len = 512 x.Cap = 512 x.Data = uintptr(addr) var payload []byte = *(*[]byte)(unsafe.Pointer(&x)) stdoutDumper := hex.Dumper(os.Stdout) defer stdoutDumper.Close() stdoutDumper.Write(payload) // Munmap(addr, length) } func main() { var pid int pid = syscall.Getpid() fmt.Println("GetPhysPageSize:", GetPhysPageSize()) TestHugePage() cmd := exec.Command("cat", str) out, err := cmd.CombinedOutput() if err != nil { fmt.Printf("cmd.Run() failed with %s\n", err) return } fmt.Printf("combined out:\n%s\n", string(out)) }