我一直在研究为一些典型的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时查看执行的代码。
谢谢汉斯的工作...不知何故;)
没有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中返回递增的值。
虽然我已经设法实现了我的目标,但我遇到了一些困难。
我能够追踪到我想要的东西。但是,如果我的应用程序直接在VS中调试启动,为什么会崩溃呢?我想调试器没有附加到应用程序,就好像它是原生的。但是,如果我们所关心的只是装配窗口中的指令流,为什么会这么重要?