在c#中分配引用时添加神秘调用

时间:2015-12-29 00:40:26

标签: c# assembly native-code

我知道其他人写了类似的问题,但我认为我的情况不同,因为我找不到任何解决方案。

我有一个对象赋值,这个非常简单:

_buffer3 = buffer; //they are just simple reference types

生成的汇编代码如下

 mov         edx,dword ptr [ebp-3Ch] 
 mov         eax,dword ptr [ebp-40h] 
 lea         edx,[edx+4] 
 call        69C322F0 

现在,只是为了理解发生了什么,我想进入呼叫(为什么应该在分配中使用呼叫?)。但是该地址的代码不存在,我无法介入。 如果我在地址代码字段中输入地址,那就是显示的内容:

69C322F0  ???  

试图解决这个问题的任何帮助? :)

编辑..显然,当在类的方法中分配引用时,会添加神秘的调用。

如果我有这门课程:

        private class Test
        {
            int _X;
            int _Y;
            Test _t;

            public void SetValues(int x, int y, Test t)
            {
                _X = x;
                _Y = y;
            }
        }

为方法SetValues生成的程序集是:

                _X = x;
00000028  mov         eax,dword ptr [ebp-3Ch] 
0000002b  mov         edx,dword ptr [ebp-40h] 
0000002e  mov         dword ptr [eax+8],edx 
                _Y = y;
00000031  mov         eax,dword ptr [ebp-3Ch] 
00000034  mov         edx,dword ptr [ebp+0Ch] 
00000037  mov         dword ptr [eax+0Ch],edx 

这是有道理的

但是,如果我写这个

        private class Test
        {
            int _X;
            int _Y;
            Test _t;

            public void SetValues(int x, int y, Test t)
            {
                _X = x;
                _Y = y;
                _t = t;
            }
        }

神秘的电话出现

                _X = x;
00000028  mov         eax,dword ptr [ebp-3Ch] 
0000002b  mov         edx,dword ptr [ebp-40h] 
0000002e  mov         dword ptr [eax+8],edx 
                _Y = y;
00000031  mov         eax,dword ptr [ebp-3Ch] 
00000034  mov         edx,dword ptr [ebp+0Ch] 
00000037  mov         dword ptr [eax+0Ch],edx 
                _t = t;
0000003a  mov         edx,dword ptr [ebp-3Ch] 
0000003d  mov         eax,dword ptr [ebp+8] 
00000040  lea         edx,[edx+4] 
00000043  call        515E2E48 

恕我直言,它与垃圾收集有关,但我无法理解它是什么,我真的想弄明白。我知道有人必须知道:)

答案的附录,这是我通过C#从书籍CLR中获取的摘录:

This is an extract I took from Google Books of the book: CLR via C#

1 个答案:

答案 0 :(得分:4)

我会稍微谈谈这个问题,一个完整的答案会填满一本让每个人都入睡的书。您正在获得非常不准确的机器代码视图,32位反汇编程序在转换CALL地址方面做得很差。在最近的VS版本中,如果你查看64位代码,它已经有了相当大的改进,它不再伪造机器代码指令的地址。到达那里:

  • 项目>属性>构建选项卡:平台目标= AnyCPU,取消选中“首选32位”
  • 项目>属性>调试选项卡:勾选“启用本机代码调试”
  • 工具>选项>调试>符号:启用Microsoft Symbol Server
  • 工具>选项>调试>一般:解开“抑制JIT优化”。

只有在您想要查看真实机器代码(用户机器上运行的那种)时,才需要进行最后一次设置更改。请注意,您现在正在查看未经优化的调试代码。与此问题无关。

尽管它仍然远非理想,但它很好地点亮了反汇编程序。 Test.SetValues()方法的尾端现在看起来像这样:

                _t = t;
00007FFA1ECB0C58  mov         rdx,qword ptr [rbp+50h]  
00007FFA1ECB0C5C  lea         rcx,[rdx+8]  
00007FFA1ECB0C60  mov         rdx,qword ptr [rbp+68h]  
00007FFA1ECB0C64  call        JIT_WriteBarrier (07FFA7E3312B0h)  

显示的地址现在是准确的,0x07FFA7E3312B0。查看该代码需要一个额外的步骤,您必须强制调试器进入本机模式。调试> Windows>调用堆栈并双击跟踪底部的本机函数,如RtlUserThreadStart。现在,您可以将“07FFA7E3312B0”复制/粘贴到反汇编程序的“地址”框中,先键入“0x”。我不会在这里展示它,这是一个手写的汇编代码,它做了一个相当神秘的事情,你永远不能从代码中进行逆向工程。

查找这些抖动辅助函数的最佳位置是源代码,虽然它不完全匹配,github CoreCLR project是您最好的选择。带你here

通常,抖动会根据需要发出这些直接CLR函数调用,它们的名称通常以“JIT”开头。这个碰巧是用汇编写的,但不是很常见;大多数是用C ++编写的。