如何找到 .NET InternalCall 方法的实现

How to find implementation of .NET InternalCall methods

出于好奇,我想看看实现一些内部方法的汇编代码。在这个例子中,我试图从 Interlocked.Increment 方法开始。

通过在我的源代码上设置断点然后显示反汇编 window 我得到以下显示...

    29:             Interlocked.Increment(ref xx);
00007FFDBC110279  lea         rcx,[rbp+1FCh]  
00007FFDBC110280  call        00007FFE1AD90020  
00007FFDBC110285  mov         dword ptr [rbp+68h],eax  
00007FFDBC110288  nop 

实施似乎在位置 00007FFE1AD90020。但是怎么才能看到这个地址的反汇编呢?将其输入反汇编 window 的地址字段会出现以下错误...

The specified address cannot be displayed. End of expression expected.

即使我输入断点位置的地址 (00007FFE1AD90020),我们知道这是一个有效的地址,因为我们在这里断点,我得到同样的错误。

我对如何进行目标方法的反汇编有什么想法吗?

注意:我在 64 位机器上使用 Windows 8.1 Pro,Visual Studio 2013 Update 2。如果这有什么不同的话。

您可以使用 .NET Reflector to see .NET functions' source code in any(?) .NET language, but not the assmebly code, because assembly code is generated at runtime (JIT) and only visible if you debug your program with some debugger.(If you debug within Visual Studio, its debugger will not allow you to step into .NET internal calls, because those methods has the attribute: DebuggerStepThroughAttribute)

在您的例子中,InterlockedIncrement 不是 .NET 内部调用。 InterlockedIncrement 是 kernel32.dll 中的 Windows API 函数(它的源代码可能不可见,因为该函数可能包含 syscall/sysenter 指令,除了你可以 运行 rdmsr 汇编命令获取 syscall/sysenter 地址)

你的出发点很好。您正在使用 x64 调试器,它是 VS2012 中首次提供的新调试引擎。所以你可以看到实际的代码地址,而不是从 0 开始编号的假代码地址。换句话说,调试器显示的调用地址是准确的,你不必通过较旧的地址计算所必需的痛苦地址计算调试器。

您还需要做两件非常不直观的事情:

  • 按原样,调试器在托管模式下运行,并且将拒绝显示它认为包含本机代码的地址。首先需要启用非托管调试,Project + Properties,Debugging,勾选"Enable native code debugging"选项。然后,您必须强制调试器将模式从托管调试引擎切换到非托管调试引擎。使用 Debug + Windows + Call Stack 并双击非托管堆栈帧以强制切换模式。显示ntdll.dll!RtlUserThreadStart的就是好的

  • 您已将显示值中的地址复制到“地址”框中。不够好,您需要告诉调试器您指的是 十六进制 值。这需要将 0x 放在它前面。换句话说,要输入的正确地址是 0x00007FFE1AD90020

现在调试器将反编译您要查找的代码。在我的机器上(与你的地址不同)它看起来像这样:

00007FFDE1C863B0  mov         eax,1  
00007FFDE1C863B5  lock xadd   dword ptr [rcx],eax  
00007FFDE1C863B9  inc         eax  
00007FFDE1C863BB  ret  

另一个令人痛苦的细节,您正在查看在抖动优化器关闭的情况下生成的机器代码。那并不能告诉你那么多,优化器可以大大修改代码。确实非常重要的是,您应该查看在用户计算机上实际 运行 的代码。这里也有很大的不同,CALL 被优化掉并且抖动生成该方法的内联版本。

切换到发布版本并更改设置:工具 + 选项、调试、常规,取消勾选 "Suppress JIT optimization" 选项。您现在将看到您不再需要跳过上面列出的环节,并且 Interlocked.Increment() 方法调用变成

00007FFD82F03AC4  mov         eax,1  
00007FFD82F03AC9  lock xadd   dword ptr [rsp+20h],eax