Go黑魔法之导出私有函数与私有变量

Go黑魔法之导出私有函数与私有变量

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

Reference

Exported identifiers

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值