无法检查MSVC ++中的字节代码

时间:2009-02-06 21:36:07

标签: c++ visual-c++ x86 bytecode ia-32

我一直在忙着处理免费的数字火星编译器(我知道顽皮),并创建了一些代码来检查编译的函数并查看用于学习目的的字节代码,看看我是否可以从如何学习有价值的东西编译器构建其功能。但是,在MSVC ++中重新创建相同的方法已经失败了,我得到的结果非常令人困惑。我有这样的功能:

unsigned int __stdcall test()
{
  return 42;
}

然后我做:

unsigned char* testCode = (unsigned char*)test;

我似乎无法在这种情况下使C ++ static_cast工作(它会引发编译器错误)...因此是C风格的演员,但除此之外......我也试过使用参考和测试,但这没有帮助。

现在,当我检查testCode指向的内存的内容时,我感到困惑,因为我看到的内容甚至看起来都不像有效的代码,甚至还有一个调试断点卡在那里......它看起来像这样(目标是IA-32):

0xe9,0xbc,0x18,0x00,0x00,0xcc ......

这显然是错误的,0xe9是一个相对跳转指令,看起来像0xbc字节,它看起来像这样:

0xcc,0xcc,0xcc ......

即。内存初始化为调试断点操作码,与未分配或未使用的内存一样。

对于返回42的函数我期望的是:

0x8b,0x2a,0x00,0x00,0x00,0xc3

或至少某种风格的mov后跟一个ret(0xc2,0xc3,0xca或0xcb)稍微向下

MSVC ++是否采取措施阻止我出于安全原因做这类事情,或者我做了一些愚蠢而没有意识到的事情?使用DMC作为编译器,这种方法似乎工作正常......

我也遇到了麻烦(执行字节),但我怀疑其根本原因是相同的。

非常感谢任何帮助或提示。

4 个答案:

答案 0 :(得分:2)

我只能猜测,但我很确定你正在检查调试版本。 在调试模式下,MSVC ++编译器通过调用跳转存根来替换所有调用。这意味着,每个函数都以跳转到实际函数开始,这正是您在这里所面临的 周围的0xCC字节确实是断点指令,以便在您执行不应该执行的代码时触发可能连接的调试器。
尝试使用发布版本。这应该按预期工作。

修改 这实际上受链接器设置/ INCREMENTAL的影响。您正在描述的效果未在发布版本中显示的原因是,如果启用任何类型的优化,这些跳转存根将被简化优化(当然通常是发布版本的情况)。

答案 1 :(得分:2)

对于你想要的演员:

unsigned char* testCode = reinterpret_cast<unsigned char*>( test );

从“用于编辑的程序数据库”中切换调试信息格式在项目中继续(/ ZI)'到'程序数据库(/ Zi)' - &gt;属性 - &gt; C / C ++ - &gt;一般。我相信这是设置导致编译器插入跳转代码,以便调试器可以重建一个函数并在程序运行时对其进行热补丁。可能还会关闭“启用最小重建”。

在MSVC中检查代码的一种更简单的方法是简单地设置断点并检查反汇编(右键单击该行并从弹出菜单中选择“转到反汇编”。它用源代码注释反汇编代码,这样你就可以看到每行编译成什么。

答案 2 :(得分:1)

如果要查看给定编译函数的程序集和机器代码,将更容易向编译器提供/ FAcs命令行选项并查看随后的.asm文件。

我不确定将一个函数指针转换为字节流的定义行为是什么 - 它甚至可能无法正常工作 - 但另外一个混淆的可能来源是x86函数都是可变大小而且很少 - 也是印度人。

答案 3 :(得分:1)

如果启用增量链接,那么您看到的是jmp [destination]。您可以运行调试器并查看要进行验证的反汇编。