导出私有函数与私有变量

在Go语言中, package中包含函数与变量通过identifier的首字母是否大写来决定它是否可以被其它package所访问。当一个函数或变量名称为小写字母时,默认是无法被其他package引用的. 
有没有办法突破这个限制呢? 
实际上在go官方文档中已有说明, 这需要用到一个编译器指令 

//go:linkname localname importpath.name 

官方的解释是: 

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的变量或函数的对象文件符号名。因为这个指令可以破坏类型系统和包的模块化,所以它只在导入“不安全”的文件中启用。

我的理解就是使用localname作为当前package本地函数或变量名称,关联到importpath.name实际的符号引用.实际上locaname只是一个作为链接符号,这个跟WINDOWS中的DLL符号关联有点类似.

示例
以下示例引用了runtime.sysMmap一系列私有函数与变量,用于创建一个huagepage共享内存区域
 

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))
}

猜你喜欢

转载自my.oschina.net/u/3892023/blog/2876840
今日推荐