Сбой проверки времени выполнения встроенной сборки С++ # 0

Я работаю над кодом С++, который должен иметь встроенный код сборки для изменения строки. Итак, если мой ввод: «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 не было должным образом сохранено при вызове функции. Обычно это результат вызова функции, объявленной с одним соглашением о вызовах, с указателем на функцию, объявленным с другим соглашением о вызовах.

Что я делаю неправильно?


person gkamani2011    schedule 21.11.2013    source источник
comment
возможный дубликат Ошибка проверки во время выполнения #0 во встроенном ассемблерном коде   -  person Zac Howland    schedule 22.11.2013
comment
Я предполагаю, что это академическое задание (поскольку не было бы разумной причины делать это во встроенной сборке), поэтому, имея это в виду, также нет причин использовать стек. Вы можете сделать это в одном цикле и поменять местами символы.   -  person Zac Howland    schedule 22.11.2013
comment
Да, я только что понял часть обмена. И это работает. Я просто хотел попробовать реализовать стек.   -  person gkamani2011    schedule 22.11.2013


Ответы (2)


В дополнение к ответу Зака, нажимать ediactually не нужно, потому что кажется, что компилятор автоматически делает это за вас, по крайней мере, для msvc.

Другая проблема с вашим кодом выше заключается в том, что вы делаете pop al, который увеличивает esp только на один байт. Это, очевидно, вызывает проблему, поскольку ожидается, что обычные операции push-pop будут выровнены по 4 байтам до 32-бит. Когда ваша функция завершает работу, она восстанавливает неправильное значение для ebp, возвращается к какому-то ошибочному адресу возврата, и возникает хаос.

Вы можете исправить это следующим образом:

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

Редактировать. Чтобы добавить пояснение, al недопустимый размер операнда для использования в push pop. Не уверен, почему msvc не выдал ошибку. Ваша вышеприведенная сборка в конечном итоге переводится в push eax и pop ax, из-за чего возникает дисбаланс.

person greatwolf    schedule 21.11.2013
comment
Хороший! Я только что предположил, что push al и pop al допустимы. Поделом со мной, что не проверил руководство. - person zwol; 22.11.2013

Мне кажется слегка нелепым, что вы захотите сделать это на ассемблере, но неважно. Ваша проблема прямо здесь:

push ecx
push edi
push eax

Вы никогда не выталкивали их из стека! Все, что вы положили в стек, вы должны снова убрать, прежде чем покинуть блок __asm { ... }.

Обратите внимание, что может не потребоваться сохранять все эти регистры. Я не уверен в этом на 100%, но у меня сложилось впечатление, что Windows ABI говорит, что eax, ecx и edx являются затертыми вызовами, что означает, что вам не нужно сохранять и восстанавливать их в листовая процедура, подобная этой.

person zwol    schedule 21.11.2013
comment
Пробовал так делать, все равно выдает ту же ошибку. Как вы предлагаете перевернуть строку, и это должно быть сделано в сборке. И когда я попытался отладить его, после того, как он когда-либо char, появился странный символ, такой как «i». Символ 'М' - person gkamani2011; 22.11.2013
comment
Я бы сделал это на C, используя стандартный алгоритм перестановки строк на месте (см., например, stackoverflow.com/a/199891/388520< /а> ). Вы можете перевести это на ассемблер, если хотите. Я не знаю, что происходит со странными персонажами. - person zwol; 22.11.2013
comment
На самом деле это задание, в котором мы должны использовать встроенный ассемблер для реверсивной части. - person gkamani2011; 22.11.2013