Visual Studio调试器不会进入“调用”指令

问题描述 投票:1回答:1

我一直在研究为一些典型的C#构造执行的汇编代码的一些细节。在调试简单的C#代码时,我遵循它在Visual Studio反汇编窗口中的执行(它是具有完整调试信息的应用程序的发布版本)。

我们有以下代码片段:

return Interlocked.Increment(ref _boxedInt);

00007FFD6CFB5522  sub         esp,30h  
00007FFD6CFB5525  lea         rbp,[rsp+30h]  
00007FFD6CFB552A  mov         qword ptr [rbp+10h],rcx  
00007FFD6CFB552E  cmp         dword ptr [7FFD6C166370h],0  
00007FFD6CFB5535  je          00007FFD6CFB553C  
00007FFD6CFB5537  call        00007FFDCBCFFCC0  
00007FFD6CFB553C  mov         rcx,qword ptr [rbp+10h]  
00007FFD6CFB5540  cmp         dword ptr [rcx],ecx  
00007FFD6CFB5542  mov         rcx,qword ptr [rbp+10h]  
00007FFD6CFB5546  add         rcx,8  
00007FFD6CFB554A  call        00007FFDCA6624B0  
00007FFD6CFB554F  mov         dword ptr [rbp-4],eax  
00007FFD6CFB5552  mov         eax,dword ptr [rbp-4]  
00007FFD6CFB5555  lea         rsp,[rbp]  
00007FFD6CFB5559  pop         rbp  
00007FFD6CFB555A  ret  

00007FFD6CFB554A地址处的调用指令存在问题(实际上是对Interlocked.Increment的调用),因为Visual Studio调试器只是简单地跳过调用而不执行子程序。

我打算在执行Interlocked.Increment时查看执行的代码。

  1. 为什么调试器不会执行到被调用的子程序?
  2. 如何强制它进入该调用(已经为C#项目启用了混合调试)?
c# assembly visual-studio-debugging
1个回答
1
投票

谢谢汉斯的工作...不知何故;)

没有JIT优化,它看起来像:

00007FFDCA6624B0  nop         dword ptr [rax+rax]  
00007FFDCA6624B5  mov         eax,1  
00007FFDCA6624BA  lock xadd   dword ptr [rcx],eax  
00007FFDCA6624BE  inc         eax  
00007FFDCA6624C0  ret  

通过JIT优化,一切都变得复杂得多。它只是一段代码,结构很难拥抱,但它存在:

00007FFD6CD7219F  lea         rax,[rsi+8]  
00007FFD6CD721A3  mov         edx,1  
00007FFD6CD721A8  lock xadd   dword ptr [rax],edx  
00007FFD6CD721AC  lea         eax,[rdx+1]  

看起来它在eax中返回递增的值。

虽然我已经设法实现了我的目标,但我遇到了一些困难。

  1. 当关闭“在模块加载时抑制JIT优化”并在代码中放置一个断点时,我无法在Assembly窗口中跟踪执行。当进入第一个调用指令时,进程终止(访问冲突)。我不得不采用不同的方法并在C#代码中的Interlocked.Increment之前切换到Debugger.Break()调用并附加调试器,强制它将其作为本机进程处理我的.NET进程: 启动我的应用程序,无需调 附上调试器就像我的应用程序是本机的一样 触发Interlocked.Increment执行(调试器中断之前)。

我能够追踪到我想要的东西。但是,如果我的应用程序直接在VS中调试启动,为什么会崩溃呢?我想调试器没有附加到应用程序,就好像它是原生的。但是,如果我们所关心的只是装配窗口中的指令流,为什么会这么重要?

  1. 考虑到我们保持“在模块加载时抑制JIT优化”,为什么调试器不会进入调用并显示Interlocked.Increment例程中的代码?再一次 - 这些只是CPU指令。没有托管和本机说明,对吧?
  2. 注释中提到Interlocked.Increment是非托管代码。它以何种方式处于非托管状态,因为所有归结为少量CPU指令?什么使它不受管理,为什么?它不是系统调用或任何依赖于非托管资源的东西。它引用和使用的所有东西实际上都是管理的。那么为什么?
© www.soinside.com 2019 - 2024. All rights reserved.