1

我有这个函数,它主要由内联汇编组成。

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。

4

3 回答 3

8

您未能正确管理堆栈指针。特别是,您malloc对堆栈的调用不平衡,并且您pop esp最终将错误的值弹出到esp. 因此,当您尝试ret从无效堆栈(CPU 无法读取返回地址)时,会发生访问冲突。目前尚不清楚您为什么要推动和弹出esp;那一事无成。

于 2012-12-31T22:12:46.600 回答
0

正如您所发现的,您永远不应该使用指令 POP ESP - 当您在代码中看到它时,您就知道发生了一些非常错误的事情。当然,在汇编代码中调用 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
    }
}

改进:在每个循环中删除乘以四。只是增加esi。在 ecx 上使用递减,而不是递增,并在循环之前加载成员。这允许在循环中只使用一次跳转,而不是两次。从 edx 到 eax 删除多余的移动。直接使用eax。

于 2012-12-31T22:28:52.027 回答
0

我已经自己想出了答案。

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

实际异常发生在用户代码之后,当 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
    }
}
于 2012-12-31T22:12:54.523 回答