C/C++ 内联汇编不正确的操作数类型
Posted
技术标签:
【中文标题】C/C++ 内联汇编不正确的操作数类型【英文标题】:C/C++ Inline asm improper operand type 【发布时间】:2016-06-15 21:30:06 【问题描述】:我有以下代码,应该对一块内存进行异或:
void XorBlock(DWORD dwStartAddress, DWORD dwSize, DWORD dwsKey)
DWORD dwKey;
__asm
push eax
push ecx
mov ecx, dwStartAddress // Move Start Address to ECX
add ecx, dwSize // Add the size of the function to ECX
mov eax, dwStartAddress // Copy the Start Address to EAX
crypt_loop: // Start of the loop
xor byte ptr ds:[eax], dwKey // XOR The current byte with 0x4D
inc eax // Increment EAX with dwStartAddress++
cmp eax,ecx // Check if every byte is XORed
jl crypt_loop; // Else jump back to the start label
pop ecx // pop ECX from stack
pop eax // pop EAX from stack
但是,参数 dwKey 给了我一个错误。例如,如果将 dwKey 替换为 0x5D,则代码可以完美运行。
【问题讨论】:
是什么让你认为这比用 C 或 C++ 编写更快?而且它有多快并不重要,因为凯撒密码可以在几毫秒内破解。DWORD dwsKey
是错字。似乎额外的s
是一个错误?然后删除局部变量DWORD dwKey;
?
这段代码有什么意义?您是否故意编写慢速 asm 以阻止编译器使用 4 字节异或或 SSE2 PXOR?
【参考方案1】:
我认为你有两个问题。
首先,“xor”不能取两个内存操作数(ds:[eax]是内存位置,dwKey是内存位置);其次,您使用“byte ptr”表示您需要一个字节,但您尝试使用 DWORD 并且程序集无法自动转换它们。
因此,您可能必须将值加载到 8 位寄存器中,然后再执行此操作。例如:
void XorBlock(DWORD dwStartAddress, DWORD dwSize, DWORD dwsKey)
DWORD dwKey;
__asm
push eax
push ecx
mov ecx, dwStartAddress // Move Start Address to ECX
add ecx, dwSize // Add the size of the function to ECX
mov eax, dwStartAddress // Copy the Start Address to EAX
mov ebx, dwKey // <---- LOAD dwKey into EBX
crypt_loop : // Start of the loop
xor byte ptr ds : [eax], bl // XOR The current byte with the low byte of EBX
inc eax // Increment EAX with dwStartAddress++
cmp eax, ecx // Check if every byte is XORed
jl crypt_loop; // Else jump back to the start label
pop ecx // pop ECX from stack
pop eax // pop EAX from stack
虽然,看起来 dwKey 在您的代码中未初始化;也许你应该只是“mov bl,0x42”。我也不确定您是否需要推送和弹出寄存器;我不记得允许使用 MSVC++ 内联汇编器破坏哪些寄存器。
但是,最后,我认为 Alan Stokes 在他的评论中是正确的:在这种情况下,汇编实际上不太可能比 C/C++ 代码更快。编译器可以轻松地自行生成此代码,并且您可能会发现编译器实际上进行了意想不到的优化,使其运行速度比“明显”的程序集运行得更快(例如,loop unrolling)。
【讨论】:
我相信__asm
会在需要时负责保存和恢复__asm
语句中使用的寄存器。 MSVC 分析 __asm 以确定寄存器使用情况。关于唯一需要手动处理(保留)的寄存器(除了选择器)是 ESP 和 EBP。 GCC 不分析内联汇编语句,但 MSVC 可以。
"当使用 __asm 在 C/C++ 函数中编写汇编语言时,您不需要保留 EAX、EBX、ECX、EDX、ESI 或 EDI 寄存器" (msdn.microsoft.com/en-us/library/k1a8ss06.aspx)。该页面还暗示它会执行 Michael 提到的分析,以优化需要自动保存/恢复的寄存器。以上是关于C/C++ 内联汇编不正确的操作数类型的主要内容,如果未能解决你的问题,请参考以下文章
高级CGNU C/C++ 内联汇编——Intel与ATT汇编语法对比
(C/C++) 内联汇编“add dword ptr [address]”增加地址而不是它的值