首先,我想说我研究了这个问题但是找不到与之相关的任何相关内容。
我正在msvc 2013上以32位发布模式编写c ++控制台程序。 我在其中一个文件中使用内联,它很有效,除非我的内联汇编function_1调用我的function_2,当发生这种情况时,会有一些内容被添加到function_2,因此堆栈会被损坏并且程序崩溃。 如果我停止使用电话但仅仅是#e; lea ebx,[eip + 5]",请推送ebx,jmp xxxxxx,而不是正常工作。
所以在我的情况下,为了更具体的功能2定义如下:
void test()
{
_asm{
f_01758630: // ; <= Procedure Start
PUSH EBP
MOV EBP, ESP
PUSH ESI
PUSH EDI
mov edi, [ebp + 0x0C]
XOR ESI, ESI
SHR EDI, 0x2
TEST EDI, EDI
JLE f_0175866B
PUSH EBX
mov ebx, [ebp + 0x08]
f_01758645:
MOV EDX, DWORD PTR DS : [EBX + ESI * 0x4]
ROL EDX, 0x10
MOV ECX, EDX
MOV EAX, EDX
SHR ECX, 0x8
SHL EAX, 0x8
XOR ECX, EAX
SHL EDX, 0x8
AND ECX, 0xFF00FF
XOR ECX, EDX
MOV DWORD PTR DS : [EBX + ESI * 0x4], ECX
INC ESI
CMP ESI, EDI
JL TERA_01758645
POP EBX
f_0175866B :
POP EDI
POP ESI
POP EBP
RETN//; <= Procedure End
}
}
然而,当我调试正在运行的程序时,我可以看到该函数是这样实现的:
push ebx push esi push edi push ebp mov ebp,esp push esi push edi
即msvc实现了3次推送,是否可能与_asm {}相关,这是在函数内部如何解决这个问题?
答案 0 :(得分:1)
第一个
push ebp
mov ebp, esp
push ebx
push esi
push edi
是自动生成的函数序言。功能结束时是结语:
pop ebx
pop edi
pop esi
pop ebx
pop ebp
ret
你的_asm
块有自己的序言和尾声,所以代码完成了两次。更糟糕的是,ret
块中的_asm
获取了错误的返回地址,程序将崩溃。您可以通过将函数声明为naked
来避免函数序言/结尾:
__declspec (naked) void test()
{
_asm
{
own prolog
...
own epilog
ret
}
}
这很危险,因为您可以忘记保留要更改的寄存器,“callee saved registers”:EBX,EBP,EDI,ESI。在MSVC内联汇编中,使用函数参数和局部变量很容易,因此没有必要对epilog和prolog进行控制。
查看此示例(尽可能接近您的代码):
#include <stdio.h>
void function_2(unsigned* reg_ebx, unsigned reg_edi)
{
_asm
{
mov edi, reg_edi // take the second argument
xor esi, esi
shr edi, 2
test edi, edi
jle f_0175866b
mov ebx, reg_ebx // take the first argument
f_01758645:
mov edx, dword ptr ds : [ebx + esi * 0x4]
rol edx, 16
mov ecx, edx
mov eax, edx
shr ecx, 8
shl eax, 8
xor ecx, eax
shl edx, 8
and ecx, 0xff00ff
xor ecx, edx
mov dword ptr ds : [ebx + esi * 0x4], ecx
inc esi
cmp esi, edi
jl f_01758645
f_0175866b :
}
}
void function_1 ()
{
unsigned arr[8] = {1000,2000,3000,4000,5000,6000,7000,8000};
int i;
for (i=0; i < sizeof(arr)/sizeof(arr[0]); ++i) printf ("%08X ",arr[i]); puts ("");
_asm
{
push LENGTH arr
lea eax, arr
push eax
call function_2
}
for (i=0; i < sizeof(arr)/sizeof(arr[0]); ++i) printf ("%08X ",arr[i]); puts ("");
}
int main ( void )
{
function_1();
return 0;
}