ASM X86, linux, открыть файл: не получается!
Господа, я пытаюсь постичь магию сисколов (syscalls).
В языке C все не очень сложно.
я попробовал сделать эту - прямо скажем - нехитрую операцию на ассемблере раза четыре. я потратил на это два дня.
я прочитал несколько советов, в в них буква в букву написано одно и тоже. Не получается.
читал вот это: https://stackoverflow.com/questions/8312290/how-to-open-a-file-in-assembler-and-modify-it и вот это (как я понял, просто перевод): Как открыть файл в ассемблере и модифицировать его? - CodeRoad https://coderoad.ru/8312290/Как-открыть-файл-в-ассемблере-и-модифицировать-его
Что я делаю.
я создаю на диске директорю asm, захожу туда, создаю там один файл с названием test.asm
буквально такой:
bits 64
global _start
section .bss
section .rodata
filename: db "test.asm", 0;
section .text
_start:
mov eax, 5 ; sys_open
mov ebx, filename ; const char *filename
mov ecx, 0 ;read mode
syscall
Здесь написано: положи в ebx ссылку на имя файла, положи номер системного вызова (5, открытие файла) в eax, положи режим открытия а ecx. Имя - совпадает с именем ассемблерного файла. То есть не быть такого файла в директории не может. Имя - null terminated.
Потом я компилирую и собраю программу:
nasm -felf64 test.asm -o test.o
ld test.o -o test
Потом я запускаю дебаггер:
edb --run test
Потом я 4 раза нажимаю на клавишу F8 - сделать шаг. Дохожу до syscall. И всегда получаю в eax код ошибки.
Картинку дебаггера - прилагаю.
Что я делал: я попробовал менять режми открытия. Не влияет.
я попробовал взять сишный код
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
int main(){
int input_fd = open ("test.txt", O_RDONLY);
return 0;
}
собрать его командой gcc -S -fverbose-asm -O1 foo.c и посмотреть в получившийся файл - но там ТАКАЯ МЕШАНИНА всего, несмотря на отсутствие оптимизации, что я сдался.
я не понимаю, чего этой железной дуре не хватвает в моей прекрасной программе из четрых команд асембелра? То есть, я понимаю, что я что то делаю не так. Но я не могу понять, что именно.
Может, сискол неправильный?
Проверим и эту гипотезу. Действительно, вот в этой статье
https://stackoverflow.com/questions/26254949/assembly-code-to-open-file-wrong
пишут, что "коды сисколов для 64 битного режима отличаются от кодов для 32 битного" (а я, коненчно же, слишком горд, чтобы писать для 32 бит. И вообще, я бы хотел посмотреть в глаза людям, которые склонны к столь дикой смене стандартов - зачем, черт побери, зачем менять коды привычных сисколов?)
Итак,
mov eax, 2 ; sys_open
mov ebx, filename ; const char *filename
mov ecx, 0 ;read mode
syscall
Результат - не меняется. По прежнему после вызова syscall в регистре eax находится код ошибки.
Подскажите мне, пожалуйста, что я делаю не так?
Спасибо.
Ответы (2 шт):
А ларчик просто открывался...
В общем, документацию читать надо.
Вот пример, когда код работает:
bits 64
global _start
section .bss
section .rodata
filename: db "test.asm", 0;
section .text
_start:
mov rax, 2 ; sys_open
mov rdi, filename ; const char *filename
mov rsi, 0
mov rdx, 0 ;read mode
syscall
Не только номера сисколов поменялись, но и регистры, в которые надо помещать аргументы. Как только я нашел хоть чуть чуть понятную таблицу с аргументами и номерами сисколов для 64-битного режима - все встало на свои места.
Таблица:
https://blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64/
На amd64 отличаются не только номера системных вызовов, но и регистры, через которые передаются параметры. Аргументы системного вызова распихиваются по регистрам в порядке: rdi, rsi, rdx, r10, r8,r9. Открытие файла будет выглядеть как-то так:
mov rax, 2 ; sys_open
mov rdi, filename ; const char *filename
mov rsi, 0 ; read mode
mov rdx, 0 ; permissions
syscall
