Ошибка проверки времени выполнения #0 во встроенном коде asm

Я немного новичок в ассемблере, но я пытаюсь найти параметры из метода C++ в esp стек, используя встроенный ассемблерный код. До сих пор я даже не смог скопировать esp указатель на ebp так что я могу взять стек (в случае его изменения). Даже этот маленький кусочек кода дает мне ошибку:

#include <stdlib.h>

int main(int argc, char* argv[])
{
    __asm
    {
        mov ebp, esp
    }
    system("pause");
    return 0;
}

После этого я получаю:

Ошибка проверки времени выполнения #0 - значение ESP не было должным образом сохранено при вызове функции. Это обычно является результатом вызова функции, объявленной с одним соглашением о вызовах с указателем функции, объявленным с другим соглашением о вызовах.

Не знаю что делать. Помогите мне, пожалуйста, и заранее спасибо.

1 ответ

Решение

В общем, вы должны нажать текущее значение EBP в стеке, прежде чем переместить значение ESP в EBP, EBP является регистром "сохранения-вызова" на 32-битных платформах, то есть если вы собираетесь изменить его в функции, вы должны сначала сохранить его.

Если вы хотите, чтобы ваша функция возвращала значение того, куда указывает стек (или куда она вернется после вызова функции), лучше всего сделать следующее:

void* get_stack_addr()
{
        void* stack_ptr = NULL;

        //on 32-bit systems
        //EBP is pointing at top of stack frame
        //EBP + 4 is the return instruction address
        //EBP + 8 is the value that was in ESP before function call for a function with no arguments
        __asm__
        (
                "movl %%ebp, %0\n\t"
                "addl $8, %0\n\t"
                : "=r" (stack_ptr)
        );

        return stack_ptr;
}

Сюда EAX теперь содержит адрес значения, на которое указывал стек перед вызовом get_stack_addr() сделан. Если вы только что вернули значение ESP в этой функции вы на самом деле понятия не имеете, на что указываете, поскольку компилятор часто дополняет стек в функции C/C++, чтобы обеспечить правильное выравнивание стека. Он также часто резервирует место в стеке для всех локальных переменных, что опять-таки скинет вычисление стека. Используя EBP, который указывает на вершину стека фрейма, вы можете точно рассчитать на 32-битной платформе значение стека перед вызовом функции. Наконец, мы помещаем возвращаемое значение в EAX так как в большинстве приложений ОС бинарные интерфейсы для C/C++, EAX содержит возвращаемое значение функции, а не EBP,

Еще одна вещь... если вы хотите запуск параметров в стеке для фактической функции, которая вызывает get_stack_addr()затем поменяй movl %%ebp, %0\n\t в movl (%%ebp), %0)\n\t, Таким образом, теперь вы получаете предыдущий базовый указатель стекового кадра (т. Е. Базовый указатель стекового кадра вызывающего абонента), и, добавив значение +8 к этому адресу, вы получаете либо начало сохраненных параметров выше адреса возврата, или вы смотрите на адрес, указывающий на кадр стека для вызывающей стороны текущей функции (т. е. предыдущего кадра стека).


Как улучшение "leal 8(%%ebp), %0\n\t" можно заменить:

"movl %%ebp, %0\n\t"
"addl $8, %0\n\t"

это leal Инструкция добавит 8 к значению EBP и сохранит результат в выходном операнде.

Другие вопросы по тегам