【问题标题】:Passing integer to x86 ASM in C++在 C++ 中将整数传递给 x86 ASM
【发布时间】:2021-12-29 12:54:07
【问题描述】:

我正在尝试在 C++ 中做一些脚本挂钩,并为此案例设置了一个简单的测试函数。

   void __declspec(naked) testFunct()
{
    int myInt;
    myInt = 2000;
    __asm{
        mov eax, myInt
        jmp [jmp_back_address]
    }
}

使用this传入整数时,函数调用失败,项目崩溃。但是,当使用 this 代替时,没有整数值,它成功通过。

   void __declspec(naked) testFunct()
{
    __asm{
        mov eax, 2000
        jmp [jmp_back_address]
    }
} 

如何才能成功传递整数?

【问题讨论】:

  • 第一个版本生成的程序集是什么样子的?
  • 用 C++ 编写函数。告诉编译器打印汇编语言。检查参数传递的汇编语言。完成。
  • mov dword ptr ss:[ebp-8],7D0 mov eax,dword ptr ss:[ebp-8] jmp dword ptr ds:[<unsigned long jmp_back_address>]
  • 地址存储在jmp_back_address中的代码是做什么的?请提供minimal reproducible example

标签: c++ assembly visual-c++ x86 inline-assembly


【解决方案1】:

针对我的情况,正确的解决方案是通过 ASM 在 ourFunct() 中简单地执行所有操作,因为混合 C++ 和 ASM 来传递变量会产生错误的汇编代码。有效的函数调用示例:

int CalculateTotalScore()
{
    return (int)*Game::current_speed_score;
}

DWORD jmpBackAddress;
void __declspec(naked) ourFunct()
{
    __asm{
        call CalculateTotalScore
        jmp [jmpBackAddress]
    }
}

【讨论】:

  • 所以可能就像在 GNU C 中一样,naked 函数只能使用 asm{} 块,而不是任何普通的 C++ 代码。
  • 正确,即使它没有抛出任何警告,并且仍然会编译,它编译的 x86 代码不会考虑手写的 asm 代码。
  • 实际上问题在于编译器生成的代码没有考虑到它在一个裸函数中,并且会假设 EBP 被设置为帧指针而不发出代码来执行此操作。 godbolt.org/z/5n41KK5zz。手写的 asm 本身不是问题。但是,是的,奇怪的是,MSVC 至少没有警告 naked 函数中的非 asm 代码。
【解决方案2】:

汇编器不知道“myInt”是什么意思。大多数编译器都支持内联汇编,并可以传递值。例如,使用 GCC,您可以尝试定义一个宏,如

#define MY_ASM_MACRO(myInt) ({ asm volatile("mov eax,%0\n\t \
          jmp [jmp_back_address]" : : "r"(myInt) : ); })

并像使用它

void __declspec(naked) testFunct()
{
   int myInt;
   myInt = 2000;
   MY_ASM_MACRO(myInt)
}

【讨论】:

  • MSVC inline asm 完全不同;它确实在 asm blocks 中使用 C var 名称。 (如clang -fasm-blocks)。那和__declspec 是我们如何判断这是Visual C++,而不是GNU C++ 语法。 What is the difference between 'asm', '__asm' and '__asm__'?
  • 另外,你的宏也不安全;您需要在 asm 语句之后添加一个 __builtin_unreachable();,因为您无条件地跳出它。此外,只需在 EAX 中首先使用"a"(myInt) 请求myInt。让编译器在不同的寄存器中实现值是愚蠢的,甚至不让它使用立即数。
  • 或者实际上这是一个__attribute__((naked)) 函数,所以不需要__builtin_unreachable(),但也不支持使用GNU C Extended Asm。 GNU C 中的裸函数仅支持 Basic Asm。gcc.gnu.org/onlinedocs/gcc/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-04
相关资源
最近更新 更多