我有这个功能,主要由内联asm组成。
long *toarrayl(int members, ...){
__asm{
push esp
mov eax, members
imul eax, 4
push eax
call malloc
mov edx, eax
mov edi, eax
xor ecx, ecx
xor esi, esi
loopx:
cmp ecx, members
je done
mov esi, 4
imul esi, ecx
add esi, ebp
mov eax, [esi+0xC]
mov [edi], eax
inc ecx
add edi, 4
jmp loopx
done:
mov eax, edx
pop esp
ret
}
}
运行时,我在返回指令上遇到访问冲突。
我正在使用VC ++ 6,它有时可能意味着指向上面的行,所以可能在'pop esp'上。 如果你能帮助我,那就太好了。 谢谢,iDomo。
答案 0 :(得分:8)
您无法正确管理堆栈指针。特别是,您对malloc
的调用会导致堆栈失衡,而您的pop esp
最终会将错误的值弹出到esp
。因此,当您尝试从无效堆栈ret
(CPU无法读取返回地址)时,会发生访问冲突。目前还不清楚为什么要推动和弹出esp
;什么也没做。
答案 1 :(得分:0)
我自己想出了答案。
对于那些有同样或类似问题的人:
实际的异常是在用户代码之后发生的,当vc ++在调用函数之前自动弹出/恢复寄存器到它们的状态。由于我在调用malloc时错过了对齐堆栈指针,因此从堆栈弹出时存在访问冲突。我无法在编辑器中看到这个,因为它不是我的代码,因此它只显示为函数中的最后一个代码。
要解决此问题,只需在拨打电话后添加一个添加esp(前一次通话的参数大小)。
固定代码:
long *toarrayl(int members, ...){
__asm{
mov eax, members
imul eax, 4
push eax
call malloc
add esp, 4
mov edx, eax
mov edi, eax
xor ecx, ecx
xor esi, esi
loopx:
cmp ecx, members
je done
mov esi, 4
imul esi, ecx
add esi, ebp
mov eax, [esi+0xC]
mov [edi], eax
inc ecx
add edi, 4
jmp loopx
done:
mov eax, edx
ret
}
//return (long*)0;
}
优化代码:
long *toarrayl(int members, ...){
__asm{
mov eax, members
shl eax, 2
push eax
call malloc
add esp, 4
;cmp eax, 0
;je _error
mov edi, eax
mov ecx, members
lea esi, [ebp+0xC]
loopx:
mov edx, [esi]
mov [edi], edx
add edi, 4
add esi, 4
dec ecx
jnz loopx
}
}
答案 2 :(得分:0)
正如您所发现的,您永远不应该使用POP ESP指令 - 当您在代码中看到时,您知道发生了一些非常错误的事情。当然,在asseembler代码中调用malloc也是一件坏事 - 例如你忘了检查它是否返回NULL,所以你可能会崩溃。坚持在汇编程序之外 - 并检查NULL,调试更容易“无法在文件mycode.c中的第54行分配内存”而不是“汇编程序中的某处,我们得到了
这里有一些改进建议,可以加快你的循环:
long *toarrayl(int members, ...){
__asm{
mov eax, members
imul eax, 4
push eax
call malloc
add esp, 4
mov edx, eax
mov edi, eax
mov ecx, members
lea esi, [ebp+0xc]
loopx:
mov eax, [esi]
mov [edi], eax
add edi, 4
add esi, 4
dec ecx
jnz loopx
mov lret, eax
ret
}
}
改进:在每个循环中删除乘以4。只需增加esi
即可。在ecx上使用递减而不是递增,并在循环之前使用成员加载它。这允许在循环中使用一次跳转,而不是两次。从edx移除reduntant移动到eax。直接使用eax。