Как переписать адрес возврата стека ассемблера с адресом, данным C ++? - PullRequest
1 голос
/ 18 мая 2019

Я получил функцию switchContext(void*& from, void*& to).Он получает два указателя стека и должен изменить контекст процесса.Поэтому, если я получил сопрограмму A и она использует определенную функцию resume(), сопрограмма B продолжит работать.В настоящее время у меня возникают проблемы при работе моего кода.

Я использую Nasm & GCC для компиляции.

Программа ассемблера: (switchContext(void*& from, void*& to)):

switchContext:

    ; epb = esp
    mov     ebp, esp

    ; save registers
    push    ebp
    push    ebx
    push    esi
    push    edi

    ; from <= returnadress
    ; eax <= returnadress
    mov     eax, [ebp+16] 
    mov     edx, ebp
    add     edx, 20 ; make edx point to 'from'
    ; overwrite 'from' with returnadress
    mov     [edx], eax

    ; what to do now: returnadress <= to
    ; eax <= to
    mov     eax, [ebp+24]
    mov     edx, ebp
    add     edx, 16 ; make edx point to returnadress
    ; overwrite returnadress with 'to'
    mov     [edx], eax

    pop     edi ; RSA = esp + 12
    pop     esi ; RSA = esp + 8
    pop     ebx ; RSA = esp + 4
    pop     ebp ; RSA = esp + 0

    ; use new returnadress to jump to 'to'
    ret     

Иэто соответствующий класс C ++:

extern "C" {
    void switchContext(void*& from, void*& to);
}

class Coroutine {
public:

    const char* name;
    Coroutine(void* tos = 0)
    {
        setup(tos);
    }

    void resume(Coroutine* next)
    {

        switchContext(this->sp, next->sp);
    }

    virtual void body() = 0;
    virtual void exit() = 0;

private:
    static void startup(Coroutine* obj) {
        obj->body();
        obj->exit();
    };

    void setup(void* tos) {
        if (tos == 0) {
            unsigned temp_stack[1024];
            this->sp = &temp_stack;
            return;
        }

        this->sp = &tos;
        return;
    };

    void* sp;
};

В настоящее время моя программа просто падает.Но это происходит только путем замены адреса возврата в ассемблере на «.».

Где я допускаю ошибку в этом процессе?

1 Ответ

3 голосов
/ 18 мая 2019

Ваш mov ebp,esp находится не в том месте.Это должно быть после сохранения регистра.

Вы не разыменовываете ссылки.С точки зрения ассемблера, ссылка на C ++ - это просто указатель, поэтому ваши параметры void **.Так как вы хотите сохранить / загрузить адреса возврата на то, на что указывает, вам нужно дополнительное косвенное обращение, чтобы сохранить значение на указанном адресе.

Не связано с этой проблемой: Некоторые вычисления вашего адреса с использованием edx может быть сведено к меньшему количеству инструкцийВы также можете отказаться от использования ebp и использовать смещения на основе esp.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...