Операционная система

ПО, которое организует доступ к ресурсам компьютера:

  • унифицирует (драйверы, файловая система, ...);
  • разделяет (вытесняющая многозадачность, виртуальная память, ...);
  • разграничивает (права доступа для пользователей, ...).

Чтобы ОС могла выполнять свои функции, нужна поддержка со стороны процессора: привилегированный режим, в котором будет исполняться часть ОС, называемая ядром (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.