Windows本机回调仅在64位平台上返回32位结果

时间:2018-12-19 05:17:56

标签: go

我正在调用一个带有回调函数的DLL函数,该回调函数返回指向某些数据结构的指针,并且DLL将对该数据结构执行某些操作。

package main

import (
    "golang.org/x/sys/windows"
    "unsafe"
)

type A struct {}
var a = &A{}

func Callback() uintptr {
    ptr := uintptr(unsafe.Pointer(a))
    fmt.Printf("Address: 0x%X\n", ptr)
    return ptr
}

func main() {
    dll := windows.MustLoadDLL("some.dll")
    init := dll.MustFindProc("init")
    init.Call(windows.NewCallback(Callback))
    fmt.Printf("This never get prints\n")
}

我正在Windows 64位计算机上运行,​​该DLL也是64位。

$ go version
go version go1.11.4 windows/amd64

上面的代码将打印指针的地址0xC000080018,但是对DLL的调用将以静默方式失败。我没有DLL的源代码,所以我无法使其显示所获得的值。因此,我使用IDA pro动态调试了程序,发现Go回调函数实际上返回的是32位值而不是64位值。这是Go回调例程的最终代码,然后返回到DLL:

main.exe:00000000004537E7     mov     eax, [rcx+rdx-8]
main.exe:00000000004537EB     pop     qword ptr [rcx+rdx-8]
main.exe:00000000004537EF     retn

如您所见,Go在eax中而不是在rax中写入返回值,这将丢弃较高的地址,因此DLL将仅获得0x80018并引起错误。 / p>

尽管我知道它有什么问题,但我不知道如何解决它。

更新

我对Go的回调实现做了一些深入的研究,并在src/runtime/sys_windows_amd64.s找到了汇编代码。我注意到在runtime·callbackasm1中,返回值是使用MOVL而不是MOVQ设置的。所以我将其更改为MOVQ,一切正常。

我不确定这是错误还是实际意图,所以我会open an issue on GitHub

1 个答案:

答案 0 :(得分:0)

此错误已作为问题发布在 golang 存储库 (issue 29331) 上并由 golang 团队修复。