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

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

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

Чтобы ОС могла выполнять свои функции, нужна поддержка со стороны процессора: привилегированный режим, в котором будет исполняться часть ОС, называемая ядром (kernel).

 Прикладные программы

 Системные утилиты

                                       Userspace
────────────────────────────────────────────────────────
                                       Kernelspace
 Ядро ОС                              (привилегированный
                                       режим)

Переносимость и совместимость

API (application programming interface) — контракт на уровне исходного кода (source-level).

Пример — API стандартной библиотеки языка Си.

ABI (application binary interface) — контракт на уровне машинного кода и двоичного представления данных: соглашения о вызовах, способы компоновки, порядок загрузки и запуска программы, интерфейс взаимодействия с ядром ОС. Нас будет особенно интересовать ABI Linux/x86.

Семейство юниксовых

Картинка из Википедии:

В 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/x86

Осуществляются (пока что магической) инструкцией int $0x80. В регистре eax должен быть номер системного вызова, а в регистрах ebx, ecx и edx — его аргументы по порядку.

Результат системного вызова возвращается в регистре eax.

Напишем программу bare.S, которая делает системный вызов exit, не пользуясь стандартной библиотекой языка Си:

#include <sys/syscall.h>

    .global _start
_start:                  // default ELF entry point
    mov $SYS_exit, %eax  // SYS_exit == 1
    mov $42, %ebx        // exit(int status) ← status = 42
    int $0x80

Соберём её:

gcc -m32 -static -nostdlib bare.S -o bare

То же самое в виде программы на языке Си:

#include <sys/syscall.h>

void _start() {
    asm volatile ("int $0x80" : : "a"(SYS_exit), "b"(42));
}

Системные вызовы документированы в секции 2 руководства (manual), поэтому почитать документацию на системный вызов exit можно так: man 2 exit.