Изменение стека выполнения в x86 из Rust - PullRequest
0 голосов
/ 16 февраля 2020

Я пытаюсь вручную установить RSP и начать выполнение с пользовательского адреса в Rust с помощью встроенной сборки x86_64.

У меня есть C код, который работает:

#include <stddef.h>

void __attribute ((noreturn)) jump_with_stack(size_t jump_addr, size_t *jump_stack) {
            __asm__ volatile ( \
                        "movq %[stack], %%rsp\n" \
                        "xor %%rdx, %%rdx\n" \
                        "jmp *%[entry]" \
                        : /* None  */ \
                        : [stack] "r" (jump_stack), [entry] "r" (jump_addr) \
                        : "rdx", "memory" \
                        );
}

Это это разборка:

jump_with_stack:
        push    rbp
        mov     rbp, rsp
        mov     QWORD PTR [rbp-8], rdi
        mov     QWORD PTR [rbp-16], rsi
        mov     rax, QWORD PTR [rbp-16]
        mov     rcx, QWORD PTR [rbp-8]
        movq rax, %rsp
        xor %rdx, %rdx
        jmp *rcx
        nop
        pop     rbp
        ret

И этот код Rust, который не делает:

#![feature(asm)]

pub unsafe extern fn rust_jump_with_stack(target: usize, targ_stack: *mut usize) -> ! {

    asm!("mov rsp, $0
         xor rdx, rdx
         jmp [$1]"
         :
         :"r"(targ_stack), "r"(target)
         : "rdx", "memory"
         : "intel");
    unreachable!();
}

Вот ржавчина разборки:

example::rust_jump_with_stack:
    push    rax

    mov     rsp, rsi
    xor     rdx, rdx
    jmp     qword ptr [rdi]

    lea     rdi, [rip + .L__unnamed_3]
    lea     rdx, [rip + .L__unnamed_4]
    mov     rax, qword ptr [rip + std::panicking::begin_panic@GOTPCREL]
    mov     esi, 40
    call    rax
    ud2

(Оба выхода разборки от Godbolt Explorer)

Я не понимаю разницы между ними или того, что означает разница в сгенерированном коде.

1 Ответ

1 голос
/ 16 февраля 2020

jmp [$1] - это дополнительный уровень косвенности, которого нет в вашей версии AT & T.

AT & T jmp *%1 эквивалентен Intel jmp %1.

Обратите внимание, что %[entry] - это просто символический c способ написания %1; квадратные скобки являются частью синтаксиса имени операнда и не заканчиваются в конечном выводе asm как синтаксис режима адресации.

(Также ваш вопрос - полный беспорядок, потому что вы используете -masm=intel на Godbolt, в то время как ваш встроенный ассемблер GNU C написан для сборки со значением по умолчанию -masm=att.)


Другие существенные различия состоят в том, что G CC по умолчанию равен -O0 (анти-оптимизированный) режим отладки), пока вы строите свой код Rust с включенной оптимизацией.


Возможно, вам следует использовать __builtin_unreachable() после вашего оператора C asm(""), чтобы убедиться, что компилятор знает, что выполнение действительно не ' выйти на другую сторону asm-заявления. Я бы опасался, что маркировки функции-оболочки noreturn может быть недостаточно, чтобы компилятор не предполагал, что он может отложить сохранение до после оператора asm, после встраивания. (Для выполнения оператора asm обычно требуется asm goto для известных меток, в противном случае рекомендуется __builtin_unreachable().)

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