我的操作系统是64位窗口。
这是我的代码
first.c:
$(".moving").not(this).animate(...
second.asm:
#include <stdio.h>
extern long second(int, int);
void main()
{
int val1, val2;
long result;
scanf("%d %d", &val1, &val2);
result = second(val1, val2);
printf("%ld", result);
}
编译好了,但是“ mov ax,[bp + 4] ”此行有错误“0xC0000005:访问冲突读取位置0x00000004。”
出了什么问题?
答案 0 :(得分:3)
您正在以16位模式汇编代码并将其链接到以32位模式执行的32位程序。组成second
函数的机器代码最终会得到与预期不同的解释。这个代码实际执行了:
_second:
00407800: 55 push ebp
00407801: 8B EC mov ebp,esp
00407803: 8B 46 04 mov eax,dword ptr [esi+4]
00407806: 8B 5E 06 mov ebx,dword ptr [esi+6]
00407809: 03 C3 add eax,ebx
0040780B: 5D pop ebp
0040780C: C3 ret
代码不使用16位寄存器,而是使用32位寄存器。而是在寻址堆栈上的参数时使用BP寄存器作为基础,它使用ESI作为基础。由于ESI未在函数中初始化为任何内容,因此它保留了在调用之前发生的任何随机值(例如0)。无论在哪里都不是有效的可读地址,因此访问它会导致崩溃。
您的问题是您已经采用了用于16位编译器的汇编代码,用于16位操作系统(例如MS-DOS),并将其与32位编译器一起用于Windows。你不能盲目削减&amp;粘贴代码示例。这是32位版本的汇编代码:
.MODEL FLAT
.CODE
PUBLIC _second
_second PROC
push ebp
mov ebp, esp
mov eax, [ebp+8]
mov edx, [ebp+12]
add eax, edx
pop ebp
ret
_second ENDP
END
.MODEL FLAT
指令告诉汇编器你正在生成32位代码。我已将代码更改为使用32位寄存器,并调整帧指针(EBP)相对偏移量以反映32位模式下的堆栈槽长为4个字节的事实。我还将代码更改为使用EDX而不是EBX,因为在32位C调用约定中,EBX寄存器需要由函数保留,而EDX(如16位C调用约定中的BX)则不需要。
答案 1 :(得分:0)
在这种特定情况下,SP和BP可能为0。但请注意,SP和BP分别是RSP和RBP的最低16位四分之一,因此堆栈指针实际上并非为0。
答案 2 :(得分:0)
将参数从 .c 传递到 .asm 的另一种解决方案是使用“fastcall”约定,它允许您在寄存器CX
中传递两个参数和DX
(实际上它是ECX
和EDX
,但您在代码中使用了16位寄存器。接下来是在VS 2013中测试的一个简短示例,它向asm函数发送两个整数(2,5),函数返回这些值的加法(7):
<强> first.cpp 强>
#include "stdafx.h"
extern "C" int __fastcall second(int,int); // ◄■■ KEYWORDS "C" AND __FASTCALL.
int _tmain(int argc, _TCHAR* argv[])
{
short int result = second(2,5); // ◄■■ "RESULT" = 7.
return 0;
}
<强> second.asm 强>
.model small
.code
public @second@8 ◄■■ NOTICE THE @ AND THE 8.
@second@8 proc near ◄■■ NOTICE THE @ AND THE 8.
mov ax,cx ◄■■ AX = 2.
add ax,dx ◄■■ AX + 5 (RETURN VALUE).
ret
@second@8 endp ◄■■ NOTICE THE @ AND THE 8.
end