【问题标题】:How and where is syscall.Syscall() defined for Windows-specific system calls in Golang's syscall package?syscall.Syscall() 在 Golang 的 syscall 包中是如何以及在哪里为特定于 Windows 的系统调用定义的?
【发布时间】:2020-02-03 07:21:24
【问题描述】:

我正在尝试了解 Golangs 系统调用包的一些低级细节。特别是,我对特定于 Windows 的系统调用感兴趣(参见下面的示例)。

我可以找到基于 UNIX 系统的syscall.Syscall() 的定义:

但是,对于基于 Windows 的系统,我找不到任何此类定义,例如 asm_windows_amd64.s

特别是,asm_unix_amd64.s 具有以下构建指令,因此它的 ·Syscall(SB),NOSPLIT,$0-56 定义不能是 Windows 系统调用也调用的那个:

 1// +build netbsd freebsd openbsd dragonfly

在哪里为基于 Windows 的系统定义了syscall.Syscall()

示例: https://godoc.org/golang.org/x/sys/windows#example-LoadLibrary

h, err := windows.LoadLibrary("kernel32.dll")
if err != nil {
    abort("LoadLibrary", err)
}
defer windows.FreeLibrary(h)
proc, err := windows.GetProcAddress(h, "GetVersion")
if err != nil {
    abort("GetProcAddress", err)
}
r, _, _ := syscall.Syscall(uintptr(proc), 0, 0, 0, 0)
major := byte(r)
minor := uint8(r >> 8)
build := uint16(r >> 16)
print("windows version ", major, ".", minor, " (Build ", build, ")\n")

【问题讨论】:

  • 因为 Windows renumbers 系统每隔一小时左右(好吧,也许是每个月左右)调用一次,没有人在他头脑正常的情况下实际上直接使用它们。调用总是通过一些 DLL,该 DLL 使用未发布的 Microsoft 机密将名称映射到系统调用号。 Go 似乎在做同样的事情,而且,在构建时生成代码以调用 DLL,使用 github.com/golang/sys/blob/master/windows/mkwinsyscall/…
  • @torek - 你能找到上面例子中调用的syscall.Syscall() 的定义吗:r, _, _ := syscall.Syscall(uintptr(proc), 0, 0, 0, 0)?另外,这里我没有使用系统调用号,而是函数的 DLL 地址:windows.GetProcAddress(h, "GetVersion")
  • ... 我想。窗户是个谜;我建议不要自己使用它,也不要拥有它。啊哈:不,它在runtime/syscall_windows.go
  • Linkname pragma 导出具有给定名称的函数

标签: windows go


【解决方案1】:

我没有或没有使用 Windows,但是一些 grep 使用源代码发现了这一点:

  • syscall.Syscallsyscall.Syscall6 等在runtime/syscall_windows.go 中定义。例如,从第 179 行开始(当前):

    //go:linkname syscall_Syscall syscall.Syscall
    //go:nosplit
    func syscall_Syscall(fn, nargs, a1, a2, a3 uintptr) (r1, r2, err uintptr) {
        lockOSThread()
        defer unlockOSThread()
        c := &getg().m.syscall
        c.fn = fn
        c.n = nargs
        c.args = uintptr(noescape(unsafe.Pointer(&a1)))
        cgocall(asmstdcallAddr, unsafe.Pointer(c))
        return c.r1, c.r2, c.err
    

    }

    go:linkname 是使该函数命名为 syscall.Syscall 的魔力,尽管此处将其命名为 runtime.syscall_Syscall

  • 这些使用较早加载的 DLL 来确定如何真正进行系统调用。 (这就是 c.fn 的意义所在。)要调用 DLL,Go 运行时必须锁定线程(参见前两个调用)并使用 cgocall 来调用 DLL。此外,使用getc().m.syscall获得的结构传递参数需要特殊技巧。

  • 启动加载似乎是通过runtime/os_windows.go 进行的。请注意,_GetProcAddress(和其他函数)由 Windows 加载程序填充,允许引导。

【讨论】:

  • 谢谢。你不是说它被命名为runtime.syscall_Syscall吗?这是一个奇怪的决定,Unix 系统调用在 syscall 包中定义,而 Windows 系统调用在 runtime 中定义 - 我不知道在那里看。这些功能是如何联系起来的?是静态链接还是动态链接?
  • 哎呀,对,应该是runtime.syscall_Syscall,但要使用链接名技巧。会修复的。
  • 您还知道链接是如何发生的吗? //go:linkname 并不是真正指“二进制链接”吗?它只是在运行时创建一个别名,对吧?
  • 关于链接,我没有研究过 Go 编译器和链接器是如何工作的,但它们是 Go 构建系统私有的。
猜你喜欢
  • 1970-01-01
  • 2014-01-27
  • 2012-12-12
  • 2020-08-15
  • 2020-04-19
  • 2019-08-05
  • 2012-04-16
  • 2017-05-05
  • 2014-10-23
相关资源
最近更新 更多