【问题标题】:Access violation on 'ret' instruction'ret' 指令的访问冲突
【发布时间】:2012-12-15 21:28:35
【问题描述】:

我有这个函数,它主要由内联 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 后从堆栈中清除大小 (eax)。并将ret 留在您的代码之外,让编译器处理该部分。
  • ret 崩溃了吗?堆栈粉碎。 飞走了
  • 使用内联汇编时,编译器会自动保存需要的寄存器吗?如果没有,则需要将ESIEDIEBXEBPESP在开头(如果您修改它们)用pushes保存,并在末尾用@987654332恢复@s

标签: c++ assembly access-violation inline-assembly


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    正如您所发现的,您永远不应该使用指令 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。

    【讨论】:

    • 我这样做是为了解释,所以优化它对我没有任何好处。谢谢你。
    • 简化代码永远不会有坏处。添加了一些 cmets 并更正了几个错别字。
    【解决方案3】:

    我自己想出了答案。

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

    实际异常发生在用户代码之后,当 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
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-02-10
      • 1970-01-01
      • 2017-08-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-27
      • 1970-01-01
      相关资源
      最近更新 更多