【问题标题】:Wrong function address函数地址错误
【发布时间】:2019-05-05 13:21:55
【问题描述】:

代码如下:

__declspec ( naked ) void nseel_asm_assign(void)
{
  __asm 
  {
    fld qword ptr [eax]
    fstp qword ptr [ebx]
  }
}
__declspec ( naked ) void nseel_asm_assign_end(void) {}

使用它们的代码崩溃。调试器显示地址正常,例如

&nseel_asm_assign   0x0f45e4a0 {vis_avs.dll!nseel_asm_assign(void)} void(*)()
&nseel_asm_assign_end   0x0f45e4b0 {vis_avs.dll!nseel_asm_assign_end(void)} void(*)()

但是,当这些函数的地址由实际的 C 代码而不是由调试器获取时,它就不再正确并且消费代码由于大小为负而崩溃:

    fn  0x0f455056 {vis_avs.dll!_nseel_asm_assign}  void(*)()
    fn_e    0x0f45295f {vis_avs.dll!_nseel_asm_assign_end}  void(*)()

带下划线的函数只包含一条指令,例如jmp nseel_asm_assign

如何获取实函数的地址,不带下划线?

更新:如果您想知道我为什么要编写这样的代码,那不是我,it’s third party,而且它在使用 VC++ 6.0 构建时运行良好。

【问题讨论】:

  • “因为大小是负数”鉴于size_t 未签名,这怎么可能?
  • 另外,您使用的是什么工具链和编译器(和版本)?您的目标是什么平台?
  • @Dai 消费代码是一个 JIT 编译器,它通过减去这两个函数的地址来计算大小,然后复制函数的代码。 Win32,VC++ 2017。
  • naked 表示编译器不会为您发出ret 指令,或任何将指针放入寄存器的设置。您没有展示您如何“使用”此代码,但您将得到的只是 2 个 asm 指令上的标签,然后进入下一步。
  • 您需要使用 /Zi 而不是 /ZI 进行编译,以击败 MSVC++ 用于支持增量链接和编辑+继续的技巧。查看报告的地址,您现在应该会在那里看到一条跳转到实际代码的 JMP 指令。修改 JMP 目标是允许链接器和调试器随意替换函数的原因。这无助于您测量函数大小和移动代码。

标签: c windows visual-c++ inline-assembly function-address


【解决方案1】:

这是获取真实地址的方法。

static void* unwrapJumpAddress( void *f )
{
    const uint8_t* pb = (const uint8_t*)f;
    if( *pb == 0xE9 )   // JMP: http://felixcloutier.com/x86/JMP.html
    {
        const int offset = *(const int*)( pb + 1 );
        // The jump offset is relative to the start of the next instruction.
        // This JMP takes 5 bytes.
        return (void*)( pb + 5 + offset );
    }
    return f;
}

【讨论】:

    猜你喜欢
    • 2018-08-31
    • 2011-12-05
    • 1970-01-01
    • 1970-01-01
    • 2016-04-27
    • 2011-10-31
    • 2012-09-05
    • 2013-12-25
    相关资源
    最近更新 更多