Системные вызовы: syscall в Linux
Урок показывает, как программа просит ядро об услугах: вывести текст, прочитать ввод, завершиться.
Системный вызов (syscall) — обращение программы к ядру операционной системы за услугой, которую сама программа выполнить не может (вывод, файлы, память).
Почему нельзя «просто вывести»
Программа не имеет прямого доступа к экрану, диску или сети — этим управляет ядро ради безопасности. Чтобы что-то вывести, программа делает системный вызов: складывает номер услуги и аргументы в регистры и выполняет команду syscall, передавая управление ядру.
Соглашение системных вызовов
У syscall свои правила (отличаются от обычных функций номером в rax и регистром r10 вместо rcx):
| Регистр | Что содержит |
rax | номер системного вызова |
rdi | 1-й аргумент |
rsi | 2-й аргумент |
rdx | 3-й аргумент |
Несколько важных номеров в Linux x86-64: 1 — write, 0 — read, 60 — exit.
Вывод строки на экран
Чтобы напечатать «Hi», вызываем write (rax=1) в стандартный вывод (rdi=1):
section .data
msg db "Hi", 10 ; текст и перевод строки
len equ $ - msg ; длина = текущий адрес минус адрес msg
section .text
global _start
_start:
mov rax, 1 ; write
mov rdi, 1 ; stdout
mov rsi, msg ; адрес строки
mov rdx, len ; длина
syscall ; ядро печатает строку
mov rax, 60 ; exit
mov rdi, 0 ; код 0
syscallКак работает под капотом
Промоделируем «диспетчер» системных вызовов на Python: по номеру в rax выбираем действие — ровно как ядро.
def syscall(rax, rdi=0, rsi="", rdx=0):
if rax == 1: # write
print("WRITE:", rsi[:rdx])
elif rax == 60: # exit
print("EXIT с кодом", rdi)
syscall(1, rdi=1, rsi="Hi\n", rdx=3) # write(stdout, "Hi\n", 3)
syscall(60, rdi=0) # exit(0)Вывод:
WRITE: Hi EXIT с кодом 0
Ядро по номеру в rax понимает, какую услугу запросили, и выполняет её. Все функции вроде printf в C под капотом в итоге доходят до такого же системного вызова write.
Частые ошибки
- Перепутать
r10иrcx. У syscall четвёртый аргумент вr10, а не вrcx(командаsyscallпортитrcx). - Указать неверную длину строки. Слишком большая
rdxвыведет лишний мусор из памяти. - Забыть про exit. Без явного
exitпосле кода исполнение «провалится» дальше в мусор и упадёт.
Итог
- syscall — это просьба к ядру об услуге (вывод, ввод, завершение).
- Номер вызова кладут в
rax, аргументы — вrdi/rsi/rdx. - В Linux x86-64: write=1, read=0, exit=60.
- Высокоуровневый вывод (
printf,print) в итоге сводится к write через syscall.