MSVC:以64位代码读取特定的64位或32位寄存器(例如R10)?

时间:2019-01-14 16:05:54

标签: c++ visual-studio assembly

MSVC是否可以通过普通的C ++函数直接读取特定的64(或32)位寄存器?

例如,我可以通过任何内在函数或类似方式读取r10的内容吗?


对于上下文:

我正在实现一个可变参数函数(我们称其为my_func),该函数需要将其调用转发给另一个可变参数函数,并在此过程中再添加一个参数(如果可以,则为ID,任何数字类型都可以-例如16、32或64位整数并不重要)。

我需要在尽可能少的指令中进行此转发,因此我无法在初始函数中处理可变参数列表,而只能转发va_list等。

因此,我已经在程序集中实现了my_func:

; This function needs to be as compact as possible
my_func PROC
  ; assume 123 is the ID to be passed along with the arguments that my_func is called with
  mov r10, 123 
  jmp address_of_the_real_target_function
my_func

我只是跳转到目标函数,并将ID传递到单独的寄存器-在这种情况下为R10。

ARG* the_real_target_function(ARG* arg0, ...)
{
    auto id = ReadRegister();
    // ... do stuff ...
}

到目前为止,该方法运行良好-唯一麻烦的是,我需要另一个汇编帮助程序函数才能以适当的C ++函数读取R10,

ReadRegister PROC
  mov rax, r10
  ret
ReadRegister ENDP

这有点烦人,因为该调用不会被内联。

出现问题-有什么方法可以直接在C ++中读取此寄存器吗?

(否则,我正在考虑使用SSE寄存器,该寄存器应该可以通过内部函数读取-但很好奇是否有办法仅使用64位或32位寄存器来做到这一点)

谢谢

-

编辑:我相信这不是链接主题的重复。其中列出的解决方案特定于其他编译器,或者仅适用于os MSVC(仅32位)(x64不支持内联汇编)

-

编辑2:有关我为什么要这样做的更多背景信息。

这实际上是一个Excel插件(基本上将用于托管插件并将其功能公开给Excel)。

为了在Excel中注册功能,我需要将其绑定到由DLL导出的特定功能。我事先不知道(=在编译时)需要注册多少个或调用什么插件函数。 因此,我需要实现大量导出功能。始终具有所有可用插件的注册位。

为了控制DLL的整体大小,我需要注册的函数非常纤细,并且理想情况下还应该能够处理可变参数args(因为我不知道插件函数的形状如何)编译时;由于空间限制,我想避免为任何可能的参数怪异创建回调)

为了获得更多乐趣,它需要在x64和x86中工作-尽管在后一种情况下,该函数是由Excel通过stdcall约定调用的,因此通常的C ++可变参数无法使用。但是,至少在运行时,我可以找到传递给函数的args的数量(和类型),因此我应该能够自己处理堆栈。

所以,最重要的是,我的想法是拥有这些苗条的蹦床函数,这些函数会将所有参数及其ID转发给某个中央处理程序(如X64中所述;并通过X86中的堆栈)。

然后处理程序将事情弄得井井有条-即为参数创建一些标准化的迭代器,调用通过该ID注册的实际插件函数,等等。

1 个答案:

答案 0 :(得分:1)

static thread_local变量将只需要很少的指令,因此它并不是您想要的那么苗条。 但是它将完全可移植。

可移植性较低,但指令效率更高。 注意TEB中的任意数据槽。 因此,x86上的__readfsdword(0x14) / __writefsdword(0x14)和x64上的__readgsqword(0x28) / __writegsqword(0x28)可以解决这个问题。如果没有其他人将相同的额外空间用于其他目的。