我正在使用MASM和Visual C ++,我正在使用x64进行编译。这是我的C ++代码:
// include directive
#include "stdafx.h"
// external functions
extern "C" int Asm();
// main function
int main()
{
// call asm
Asm();
// get char, return success
_getch();
return EXIT_SUCCESS;
}
和我的汇编代码:
extern Sleep : proc
; code segment
.code
; assembly procedure
Asm proc
; sleep for 1 second
mov ecx, 1000 ; ecx = sleep time
sub rsp, 8 ; 8 bytes of shadow space
call Sleep ; call sleep
add rsp, 8 ; get rid of shadow space
; return
ret
Asm endp
end
使用断点,我已经确定了发生访问冲突的代码行:紧跟在汇编代码中的ret
语句之后。
额外信息:
我正在使用 fastcall 约定将我的参数传递给Sleep
(即使它被声明为 stdcall ),因为{{ 3}},x64将始终使用 fastcall 约定。
当我删除Asm
相关代码时,我的Sleep
程序编译并执行,没有任何错误。
即使我尝试使用 stdcall 约定来调用Sleep
,我仍然会收到访问冲突错误。
很明显,我的问题是,如何摆脱访问冲突错误,我做错了什么?
修改:
这是在C ++中为Sleep(500);
生成的程序集:
mov ecx,1F4h
call qword ptr [__imp_Sleep (13F54B308h)]
这个生成的程序集让我感到困惑......它看起来像fastcall,因为它将参数移动到ecx中,但同时它不会创建任何阴影空间。我不知道这意味着什么:
qword ptr [__imp_Sleep (13F54B308h)]
。
再次编辑main
的完整反汇编。
int main()
{
000000013F991020 push rdi
000000013F991022 sub rsp,20h
000000013F991026 mov rdi,rsp
000000013F991029 mov ecx,8
000000013F99102E mov eax,0CCCCCCCCh
000000013F991033 rep stos dword ptr [rdi]
Sleep(500); // this here is the asm generated by the compiler!
000000013F991035 mov ecx,1F4h
000000013F99103A call qword ptr [__imp_Sleep (13F99B308h)]
// call asm
Asm();
000000013F991040 call @ILT+5(Asm) (13F99100Ah)
// get char, return success
_getch();
000000013F991045 call qword ptr [__imp__getch (13F99B540h)]
return EXIT_SUCCESS;
000000013F99104B xor eax,eax
}
答案 0 :(得分:5)
如果Asm()
是正常的C / C ++函数,例如:
void Asm()
{
Sleep(1000);
}
以下是我的x64编译器为它生成的内容:
Asm proc
push rbp ; re-aligns the stack to a 16-byte boundary (CALL pushed 8 bytes for the caller's return address) as well as prepares for setting up a stack frame
sub rsp, 32 ; 32 bytes of shadow space
mov rbp, rsp ; finalizes the stack frame using the current stack pointer
; sleep for 1 second
mov ecx, 1000 ; ecx = sleep time
call Sleep ; call sleep
lea rsp, [rbp+32] ; get rid of shadow space
pop rbp ; clears the stack frame and sets the stack pointer back to the location of the caller's return address
ret ; return to caller
Asm endp
调用者负责为被调用者分配参数空间,并且必须始终为4个寄存器参数分配足够的空间,即使被调用者没有那么多参数。
有关x64如何使用堆栈的更多信息,请查看以下页面: