'ret'指令上的访问冲突

Access violation on 'ret' instruction

本文关键字:访问冲突 ret 指令      更新时间:2023-10-16

我得到了这个函数,它主要由内联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。

无法正确管理堆栈指针。特别是,您对malloc的调用使堆栈不平衡,并且您的pop esp最终将错误的值弹出到esp中。因此,当您尝试从无效的堆栈(CPU无法读取返回地址)中访问ret时,就会发生访问冲突。不清楚你为什么要按下和弹出esp;

正如您所看到的,您永远不应该使用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移除多余的移动到eax。直接使用eax。

我自己想出了答案。

对于那些有过相同或类似问题的人:

实际的异常发生在用户代码之后,当vc++自动弹出/恢复寄存器到函数被调用之前的状态时。由于我在调用malloc时没有对齐堆栈指针,因此在从堆栈弹出时存在访问冲突。我无法在编辑器中看到这个,因为它不是我的代码,所以它只是作为函数中我的最后一个代码显示。

要纠正这个问题,只需在呼叫后添加一个add 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
    }
}