Запутался насчет 64-битных регистров - ASM - PullRequest
0 голосов
/ 26 марта 2020

Я сейчас изучаю ассемблер, я использую синтаксис Intel на 64-битной Ubuntu, используя nasm.

Итак, я нашел два веб-сайта, которые ссылаются на номера системных вызовов:

Этот для 32-битные регистры (eax, ebx, ...): https://syscalls.kernelgrok.com

Этот для 64-битных регистров (rax, rbx, ...): https://blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64

Дело в том, что мой код не работает, когда я использую 64-битные числа системных вызовов, но он работает, когда я заменяю 'e' из 32-битных регистров на 'r' Так, например, в sys_write я использую rbx для хранения fd вместо rdi как и это работает.

Я сейчас совершенно заблудился. Этот код не работает:

message db 'Hello, World', 10

section .text
global _start
_start: mov rax,4
        mov rdi, 1
        mov rsi, message
        mov rdx, 13
        syscall
        mov rax, 1
        mov rdi, 0
        syscall

1 Ответ

4 голосов
/ 26 марта 2020

Выполнить strace ./my_program - вы делаете фиктивный stat системный вызов, затем write, который завершается успешно, затем падает до конца и segfault.

$ strace ./foo 
execve("./foo", ["./foo"], 0x7ffe6b91aa00 /* 51 vars */) = 0
stat(0x1, 0x401000)                     = -1 EFAULT (Bad address)
write(0, "Hello, World\n", 13Hello, World
)          = 13
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0xd} ---
+++ killed by SIGSEGV (core dumped) +++
Segmentation fault (core dumped)

Это не имена регистров, которые твоя проблема, это звонки. Вы используете 32-разрядные номера вызовов, но вызываете 64-разрядный syscall ABI.

Номера вызовов и Соглашение о вызовах различается.

* Системные вызовы 1016 * обращают внимание только на младшие 32-битные регистры, поэтому не следует использовать их в 64-битном коде.

Код, который вы разместили в комментарии с mov rcx, message, будет работать нормально mov ecx, message и т. Д. , если работает с mov rcx, message. См. Что произойдет, если вы используете 32-битный int 0x80 Linux ABI в 64-битном коде? .

Обратите внимание, что запись нулевого 32-битного регистра расширяется до полного 64 регистр, поэтому вы всегда должны использовать mov edi, 1 вместо mov rdi, 1. (Хотя NASM сделает эту оптимизацию для вас, чтобы сохранить размер кода; они настолько эквивалентны, что некоторые ассемблеры сделают это за вас.)

...