在c#中分配引用时添加神秘调用
Mysterious call is added when reference is assigned in c#
我知道其他人也写过类似的问题,但我认为我的情况不同,因为我找不到任何解决方案。
我有一个对象分配,像这样非常简单:
_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 ???
对解决这个谜团有什么帮助吗? :)
编辑..显然,当在 class.
的方法中分配引用时,添加了神秘调用
如果我有这个class:
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
恕我直言,它与垃圾收集有关,但我不明白它是什么,我真的很想弄清楚。我知道你们当中一定有人知道 :)
答案的附录,这是我摘自 Google CLR via C# 的书籍:
我会对此稍加思考,一个完整的答案会填满一本书,让每个人都入睡。您对机器代码的看法非常不准确,32 位反汇编程序在转换 CALL 地址方面做得很差。如果您查看 64 位代码,这在最近的 VS 版本中有了很大改进,因为它不再伪造机器代码指令的地址。到达那里:
- 项目 > 属性 > 构建选项卡:平台目标 = AnyCPU,取消勾选 "Prefer 32-bit"
- 项目 > 属性 > 调试选项卡:勾选 "Enable native code debugging"
- 工具 > 选项 > 调试 > 符号:启用 Microsoft 符号服务器
- 工具 > 选项 > 调试 > 常规:取消勾选 "Suppress JIT optimization"。
仅当您想查看 真正的 机器代码(在您用户的机器上运行的那种)时,才需要最后的设置更改。请注意,您现在正在查看未优化的调试代码。与此问题无关。
这很好地点亮了反汇编程序,尽管它仍然远非理想。 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。查看该代码需要一个额外的步骤,您必须强制调试器进入本机模式。 Debug > Windows > Call Stack 和 double-click 跟踪底部的本机函数,如 RtlUserThreadStart。现在你可以copy/paste“07FFA7E3312B0”进入反汇编程序的地址框,先输入“0x”。我不会在这里展示它,这是 hand-written 汇编代码,它做了一件你永远无法从代码中 reverse-engineer 做的相当神秘的事情。
寻找这些抖动辅助函数的更好的地方是源代码,虽然它不是完全匹配,github CoreCLR project is your best bet. Takes you here。
通常,抖动会根据需要发出这些类型的直接 CLR 函数调用,它们的名称通常以 "JIT" 开头。这个恰好是用汇编语言编写的,但是并不常见;大多数是用 C++ 编写的。
我知道其他人也写过类似的问题,但我认为我的情况不同,因为我找不到任何解决方案。
我有一个对象分配,像这样非常简单:
_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 ???
对解决这个谜团有什么帮助吗? :)
编辑..显然,当在 class.
的方法中分配引用时,添加了神秘调用如果我有这个class:
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
恕我直言,它与垃圾收集有关,但我不明白它是什么,我真的很想弄清楚。我知道你们当中一定有人知道 :)
答案的附录,这是我摘自 Google CLR via C# 的书籍:
我会对此稍加思考,一个完整的答案会填满一本书,让每个人都入睡。您对机器代码的看法非常不准确,32 位反汇编程序在转换 CALL 地址方面做得很差。如果您查看 64 位代码,这在最近的 VS 版本中有了很大改进,因为它不再伪造机器代码指令的地址。到达那里:
- 项目 > 属性 > 构建选项卡:平台目标 = AnyCPU,取消勾选 "Prefer 32-bit"
- 项目 > 属性 > 调试选项卡:勾选 "Enable native code debugging"
- 工具 > 选项 > 调试 > 符号:启用 Microsoft 符号服务器
- 工具 > 选项 > 调试 > 常规:取消勾选 "Suppress JIT optimization"。
仅当您想查看 真正的 机器代码(在您用户的机器上运行的那种)时,才需要最后的设置更改。请注意,您现在正在查看未优化的调试代码。与此问题无关。
这很好地点亮了反汇编程序,尽管它仍然远非理想。 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。查看该代码需要一个额外的步骤,您必须强制调试器进入本机模式。 Debug > Windows > Call Stack 和 double-click 跟踪底部的本机函数,如 RtlUserThreadStart。现在你可以copy/paste“07FFA7E3312B0”进入反汇编程序的地址框,先输入“0x”。我不会在这里展示它,这是 hand-written 汇编代码,它做了一件你永远无法从代码中 reverse-engineer 做的相当神秘的事情。
寻找这些抖动辅助函数的更好的地方是源代码,虽然它不是完全匹配,github CoreCLR project is your best bet. Takes you here。
通常,抖动会根据需要发出这些类型的直接 CLR 函数调用,它们的名称通常以 "JIT" 开头。这个恰好是用汇编语言编写的,但是并不常见;大多数是用 C++ 编写的。