Операционная система
ПО, которое организует доступ к ресурсам компьютера:
- унифицирует (драйверы, файловая система, ...);
- разделяет (вытесняющая многозадачность, виртуальная память, ...);
- разграничивает (права доступа для пользователей, ...).
Чтобы ОС могла выполнять свои функции, нужна поддержка со стороны процессора: привилегированный режим, в котором будет исполняться часть ОС, называемая ядром (kernel).
Прикладные программы
Системные утилиты
Userspace
────────────────────────────────────────────────────────
Kernelspace
Ядро ОС (привилегированный
режим)
Переносимость и совместимость
API (application programming interface) — контракт на уровне исходного кода (source-level).
Пример — API стандартной библиотеки языка Си.
ABI (application binary interface) — контракт на уровне машинного кода и двоичного представления данных: соглашения о вызовах, способы компоновки, порядок загрузки и запуска программы, интерфейс взаимодействия с ядром ОС.
Семейство юниксовых
Картинка из Википедии:
В 70-х Кен Tомпсон и Деннис Ричи разработали ОС Research UNIX. В 80-е AT&T ее коммерциализировала. В это же время Ричард Столлман придумал проект GNU, для него не хватало ядра. В 90-е Линус Торвальс начал разрабатывать Linux, проект GNU его подхватил. Теперь мы пользуемся ОС GNU/Linux, название означает OC GNU и ядро Linux.
Все это развивалось в разных направлениях, переносить программы между разными юниксами было тяжело, были попытки обеспечить переносимость программ между разными юниксами.
В 1985 году компания AT&T специфицировала UNIX System V в документе System V Interface Definition (SVID).
В 1988 рабочая группа IEEE выпустила первый стандарт POSIX (portable operating system interface), который стандартизировал, что такое UNIX.
xkcd: How standards proliferate
1994, X/Open: Single UNIX Specification (SUS).
Системные вызовы на Linux/amd64
Осуществляются (пока что магической) инструкцией syscall
.
В регистре rax
должен быть номер системного вызова,
а в регистрах rdi
, rsi
, rdx
, r10
(sic), r8
, r9
–
аргументы.
Результат системного вызова возвращается в регистре rax
.
Механизм системного вызова использует регистры rcx
и r11
для
хранения временных данных, так что их содержимое будет утрачено.
Системный вызов через inline assembly:
long long result, arg1, arg2, arg3;
asm volatile("syscall"
: "=a"(result) // output
: "a"(SYS_...), // input: syscall number (in eax/rax)
"D"(arg1), "S"(arg2), "d"(arg3) // inputs: arguments (rdi, rsi, rdx)
: "rcx", "r11", "memory") // clobbers
Напишем программу bare.S
, которая делает системный вызов exit
,
не пользуясь стандартной библиотекой языка Си:
#include <sys/syscall.h>
.intel_syntax noprefix
.global _start
_start:
mov eax, SYS_exit
mov rdi, 42
syscall
Соберём её:
gcc -static -nostdlib bare.S -o bare
То же самое в виде программы на языке Си:
#include <sys/syscall.h>
#include <unistd.h>
void _start() {
asm("syscall" : : "a"(SYS_exit), "D"(42));
}
Системные вызовы документированы в секции 2 руководства
(manual), поэтому почитать документацию на системный вызов
exit можно так: man 2 exit
.