【问题标题】:C++ inline assembly run time check failure #0C++ 内联汇编运行时检查失败 #0
【发布时间】:2013-11-21 20:01:51
【问题描述】:

我正在编写一个需要内联汇编代码来反转字符串的 c++ 代码。 因此,如果我的输入是:“qwerasd”,则输出应该是“dsarewq”。 我想过使用堆栈来实现这一点。我的代码是:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void reverseString(char* buffer, int len){

__asm {

    push ecx
    push edi
    push eax

    mov     ecx, len
    mov     edi, buffer

 top:
    mov     al, BYTE PTR [edi]
    push    al
    inc     edi
    loop    top

    mov     ecx, len
    mov     edi, buffer

refill:
    pop     al
    mov     BYTE PTR [edi], al
    inc     edi
    loop    refill
  }
}

int main()  {

    char    s[64];
    char    *ptr = s;
    int size;

    printf("\nEnter text: ");
    scanf("%s", s);
    size = strlen(s);

    reverseString(ptr, size);

    printf("\nThe new text is: %s\n\n", s);
    exit(0);
}

我正在尝试将字符一个一个地推入堆栈,然后将它们一个一个地弹出并将其存储回字符串中。

当我运行代码时,我收到以下错误: 运行时检查失败 #0 - ESP 的值未在函数调用中正确保存。这通常是调用使用一种调用约定声明的函数和使用另一种调用约定声明的函数指针的结果。

我做错了什么?

【问题讨论】:

  • 我假设这是一项学术作业(因为在内联汇编中没有合理的理由这样做),因此考虑到这一点,也没有理由使用堆栈。您可以在一个循环中完成并交换字符。
  • 是的,我刚刚弄清楚了交换部分。它有效。我只是想尝试实现堆栈。

标签: c++ assembly x86 inline-assembly


【解决方案1】:

除了 Zack 的回答之外,实际上没有必要推送 edi,因为编译器似乎会自动为您执行此操作,至少对于 msvc 而言。

您上面的代码的另一个问题是您正在执行pop al,它只会将esp 增加一个字节。这显然会导致问题,因为正常的 push pop 操作预计在 32 位下是 4 字节对齐的。当您的函数退出时,它最终会恢复 ebp 的错误值,它会返回到一些错误的返回地址并随之而来。

你可以这样修复它:

top:
  movzx   eax, BYTE PTR [edi]
  push    eax
// ...
refill:
  pop     eax
  mov     BYTE PTR [edi], al

编辑:只是为了澄清一下,al 不是用于push pop 的有效操作数大小。不知道为什么 msvc 没有给出错误。您的上述程序集最终被翻译成push eaxpop ax,而不是不平衡的来源。

【讨论】:

  • 不错!我刚刚假设push alpop al 是有效的。为我不检查手册服务。
【解决方案2】:

在我看来,你想用汇编语言来做这件事有点可笑,但无论如何。你的问题就在这里:

push ecx
push edi
push eax

你从来没有从堆栈中弹出那些!您放入堆栈的所有内容,在离开 __asm { ... } 块之前必须再次取出。

请注意,可能没有必要保存所有这些寄存器。我对此不是 100% 确定,但我的印象是 Windows ABI 说 eaxecxedxcall clobbered,这意味着你没有在像这样的叶子过程中保存和恢复它们。

【讨论】:

  • 我试过这样做,它仍然给我同样的错误。您如何建议我将字符串反转,并且必须在汇编中完成。当我尝试调试它时,在它烧焦之后,弹出了一个像“i”这样的奇怪字符。字符是'Ì'
  • 我会在 C 中使用标准的就地算法来反转字符串(例如参见 stackoverflow.com/a/199891/388520 )。如果你真的想要,你可以把它翻译成汇编。我不知道奇怪的字符是怎么回事。
  • 这实际上是一个赋值,我们需要在反转部分使用内联asm。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-16
相关资源
最近更新 更多