Jednym z najważniejszych i najczęściej używanych wywołań systemowych w systemie Linux jest read
. Dzięki niemu programy mogą odczytywać dane z różnych źródeł — plików, urządzeń, a nawet standardowego wejścia (klawiatury).
W tym artykule przybliżę Ci, czym jest syscall read
, jak działa, oraz pokażę praktyczne przykłady użycia — zarówno w języku C, jak i asemblerze x86-64.
Co to jest syscall read
?
read
to wywołanie systemowe, które pozwala na odczytanie danych z pliku lub innego źródła danych do bufora w pamięci programu.
Jego sygnatura w C wygląda tak:
ssize_t read(int fd, void *buf, size_t count);
fd
— deskryptor pliku (np. uzyskany zopen
).buf
— wskaźnik na bufor, gdzie zostaną zapisane odczytane dane.count
— maksymalna liczba bajtów do odczytania.
Funkcja zwraca liczbę faktycznie odczytanych bajtów, 0 jeśli osiągnięto koniec pliku, lub -1 w przypadku błędu.
read
jako syscall w Linux x86-64
W asemblerze na architekturze x86-64 wywołania systemowe wykonujemy instrukcją syscall
.
Dla syscallu read
:
Rejestr | Znaczenie |
---|---|
rax | numer syscall (0) |
rdi | deskryptor pliku (fd) |
rsi | wskaźnik na bufor |
rdx | liczba bajtów do czytania |
Po wywołaniu syscall
, w rax
zwracana jest liczba odczytanych bajtów lub kod błędu.
Przykład: odczyt z pliku w asemblerze NASM x86-64
Poniżej prosty program, który otwiera plik test.txt
, wczytuje z niego do 64 bajtów, i wypisuje zawartość na ekran:
section .data
filename db "test.txt", 0
buffer resb 64
msg db "Odczytano: ", 0
newline db 10
section .bss
fd resd 1
section .text
global _start
_start:
; open pliku
mov rax, 2 ; sys_open
mov rdi, filename
mov rsi, 0 ; O_RDONLY
syscall
test rax, rax
js open_error
mov [fd], eax
; read z pliku
mov rax, 0 ; sys_read
mov edi, [fd]
mov rsi, buffer
mov rdx, 64
syscall
test rax, rax
jle read_error
mov rcx, rax ; liczba odczytanych bajtów
; write "Odczytano: "
mov rax, 1 ; sys_write
mov rdi, 1 ; stdout
mov rsi, msg
mov rdx, 10
syscall
; write buffer
mov rax, 1
mov rdi, 1
mov rsi, buffer
mov rdx, rcx
syscall
; write newline
mov rax, 1
mov rdi, 1
mov rsi, newline
mov rdx, 1
syscall
; close pliku
mov rax, 3 ; sys_close
mov edi, [fd]
syscall
; exit
mov rax, 60
xor rdi, rdi
syscall
open_error:
; obsługa błędu otwarcia
mov rax, 60
mov rdi, 1
syscall
read_error:
; obsługa błędu odczytu
mov rax, 60
mov rdi, 2
syscall
Uruchomienie programu w NASM na LInux
$ cat ” 123″ > test.txt
$ nasm -f elf64 -o read_file.o read_file.asm
$ ld -o read_file read_file.o
$ ./read_file
Odczytano: 123
Praktyczne zastosowania read
1. Odczyt z plików
read
to podstawowy sposób na czytanie danych z plików, np. konfiguracji, danych wejściowych, logów.
2. Odczyt z terminala
Deskryptor 0
(standardowe wejście) pozwala na czytanie znaków wpisywanych przez użytkownika w terminalu.
3. Komunikacja międzyprocesowa
Pipes i inne kanały do komunikacji między procesami także korzystają z read
do pobierania danych.
Uwaga na błędy i blokowanie
read
może zwrócić mniej bajtów niż żądane (np. na końcu pliku).- W przypadku urządzeń znakowych i terminali może blokować proces do momentu dostępności danych.
- Przy programowaniu asynchronicznym warto zwracać uwagę na zwracane wartości i obsługiwać powtórne wywołania.
Podsumowanie
Syscall read
jest kluczowy w codziennym programowaniu na Linuxie, pozwalając na efektywny i kontrolowany odczyt danych z wielu źródeł.
Opanowanie jego użycia na poziomie asemblera pozwala zrozumieć, jak system operacyjny zarządza danymi i jakie możliwości daje programiście.