раздел 32

Системное программирование: Zig, ассемблер, Verilog

Компьютерные системы по Брайанту и О'Халларону, но на Zig вместо C и с Verilog вместо учебного HCL. Сначала минимум Zig: целые любой ширины, пять видов указателей, раскладка структур, ошибки и аллокаторы, comptime и сборка. Дальше машинный уровень x86-64 и чтение дизассемблера своего кода, процессор Y86-64 проводами на Verilog с конвейером и рисками, производительность и CPE, иерархия кэшей, компоновка, процессы и сигналы, виртуальная память и свой аллокатор, системный ввод/вывод, сети с веб-сервером TINY и конкурентность с кэширующим прокси. Программа это байты, которые процессор читает по протоколу.

73 урока73 тем · 12 кластеров

Начать раздел
Хочу пройти

Раздел открыт для всех. Войди, чтобы отмечать пройденные уроки, вести заметки и решать задачи в редакторе. войти

Уроки раздела

  1. Зачем Zig системщику и путь hello от текста до процессаM~80 мин
  2. Значения, типы и поток управленияM~90 мин
  3. Указатели, срезы и массивыM~70 мин
  4. Структуры, перечисления, объединения и раскладка в памятиM~80 мин
  5. Ошибки, defer и аллокаторыM~90 мин
  6. comptime, сборка, тесты и CMS~110 мин
  7. Биты и целые по-зиговскиM~110 мин
  8. Плавающая точка на уровне битовMS~110 мин
  9. От Zig к машинному кодуMS~110 мин
  10. Операнды, семейство mov и стекMS~150 мин
  11. Арифметика: lea, сдвиги и полное произведениеMS~190 мин
  12. Флаги, переходы и cmovS~170 мин
  13. Циклы и switch на машинном уровнеS~200 мин
  14. Процедуры и стековые кадрыS~170 мин
  15. Массивы, структуры и выравнивание на машинном уровнеS~120 мин
  16. Переполнение буфера и защиты от негоS~55 мин
  17. Числа с плавающей точкой и SIMDS~120 мин
  18. inline-ассемблер и голое железоS~80 мин
  19. JIT: пишем машинный код x86-64L~160 мин
  20. Y86-64: система команд и кодированиеS~120 мин
  21. Ассемблер Y86-64 на ZigS~140 мин
  22. Симулятор Y86-64 на ZigS~140 мин
  23. Вентили и комбинационная логика на VerilogS~80 мин
  24. Verilog: слова, мультиплексоры и ALUS~110 мин
  25. Verilog: такт, регистры и памятьS~90 мин
  26. SEQ: этапы fetch и decodeS~120 мин
  27. SEQ: execute, memory, write back и новый PCS~140 мин
  28. Принципы конвейера: задержка и пропускная способностьS~80 мин
  29. PIPE: риски, продвижение и остановыL~90 мин
  30. PIPE на Verilog и CPIL~140 мин
  31. Границы оптимизирующего компилятора и метрика CPES~130 мин
  32. Инварианты цикла, вызовы и обращения к памятиS~120 мин
  33. Модель современного процессораL~100 мин
  34. Развёртывание циклов и параллелизм на уровне инструкцийL~130 мин
  35. Пределы: регистры, ветвления и памятьL~170 мин
  36. Профилирование и бенчмаркиS~110 мин
  37. Технологии хранения и локальностьS~130 мин
  38. Организация кэшаS~120 мин
  39. Симулятор кэша: cachelab на ZigL~260 мин
  40. Код, дружественный к кэшуL~160 мин
  41. Гора памятиS~100 мин
  42. Объектные файлы, ELF и символыS~290 мин
  43. Разрешение имён и статические библиотекиS~180 мин
  44. Перемещение и загрузкаS~220 мин
  45. Динамическая компоновка, PIC, GOT и PLTL~190 мин
  46. Подмена функций и компоновка на практикеS~170 мин
  47. Исключения и системные вызовыS~330 мин
  48. Процессы: fork, execve, waitpidS~190 мин
  49. СигналыL~300 мин
  50. Ядро на своей машине: таймер, вытеснение и маска прерыванийL~150 мин
  51. Нелокальные переходы и ошибки в ZigS~110 мин
  52. Оболочка с управлением заданиями: shlab на ZigL~230 мин
  53. Виртуальная адресация и страницыS~110 мин
  54. Виртуальная память как менеджер и как защитаS~220 мин
  55. Трансляция адреса и TLBL~120 мин
  56. Отображение в память: mmap, fork, execve и копирование при записиL~270 мин
  57. Как устроен malloc: куча, блоки и неявный списокL~220 мин
  58. Свой аллокатор: malloclab на ZigL~270 мин
  59. Сборка мусора и десять ошибок с памятьюS~240 мин
  60. Unix I/O и короткие счётыS~190 мин
  61. Буферизованный ввод-вывод и метаданные файловS~210 мин
  62. Общие файлы, переадресация и пайпыS~110 мин
  63. Клиент, сервер и устройство сетиS~150 мин
  64. Сокеты: эхо-клиент и эхо-серверS~190 мин
  65. HTTP и веб-контентS~140 мин
  66. Проект: веб-сервер TINYL~240 мин
  67. Проект: песочница как у раннера курсаL~230 мин
  68. Сервер на процессах и мультиплексирование ввода-выводаL~200 мин
  69. ПотокиS~250 мин
  70. Разделяемые переменные и семафорыL~260 мин
  71. Пул потоков и параллельные вычисленияL~300 мин
  72. Потокобезопасность, гонки и взаимоблокировкиL~150 мин
  73. Проект: async в Zig и кэширующий проксиL~260 мин

Понятия курса

Понятия разобраны внутри уроков. Нажми на понятие, чтобы открыть урок, где оно объясняется.

Zig как инструмент системщика

Биты и числа, минимум

  • Биты и целые по-зиговскиБыстрое напоминание про представление целых, но с целыми любой ширины: 4-битные усечения и 5-битное переполнение как буквальные тесты. @bitCast, endianness через readInt/writeInt, тип сдвига Log2Int, умножение на константу и деление на степень двойки глазами компилятора.урок 7 · Биты и целые по-зиговскиопираются: урок 8, урок 9
  • Плавающая точка на уровне битовIEEE-754 через мини-формат и f16/f32/f64/f80/f128 в Zig. Округление до чётного, денормали, NaN. @bitCast между u32 и f32, операции над float на уровне битов: удвоение, деление пополам, преобразования в целое и обратно.урок 8 · Плавающая точка на уровне битовопираются: урок 17

Машинный уровень: x86-64 и ассемблер

  • Арифметика: lea, сдвиги и полное произведениеlea как калькулятор адреса и как умножение, унарные и бинарные операции, сдвиги с %cl, 128-битное умножение через пару %rdx:%rax, idiv с подготовкой делимого через cqto, идиома xor для обнуления.урок 11 · Арифметика: lea, сдвиги и полное произведениеопираются: урок 12
  • Операнды, семейство mov и стекОдиннадцать форм операнда и формула Imm + R[rb] + R[ri] * s, семейство mov без формы память-в-память, правило про imm32 со знаковым расширением и movabsq, movz против movs, push и pop как пара инструкций. Байты ModRM и SIB.урок 10 · Операнды, семейство mov и стекопираются: урок 11
  • От Zig к машинному кодуКак достать листинг через -femit-asm и objdump, шестнадцать регистров во всех ширинах и их роли по System V, суффиксы b/w/l/q, отличие Debug от ReleaseFast в байтах, префикс REX по битам. Первый шаг своего дизассемблера zt disasm.урок 9 · От Zig к машинному кодуопираются: урок 10
  • Массивы, структуры и выравнивание на машинном уровнеАдресная арифметика и вложенные массивы, смещения полей структуры, объединения, выравнивание и padding, @offsetOf и extern struct как способ проверить раскладку. Тегированные указатели: младшие биты выровненной ячейки под тег.урок 15 · Массивы, структуры и выравнивание на машинном уровнеопираются: урок 16
  • Переполнение буфера и защитыЧто перезаписывается в кадре при выходе за границу массива, атака с подменой адреса возврата на своём бинарнике в песочнице, канарейка, ASLR, nop-салазки, NX. Как режимы сборки Zig меняют картину: проверка границ в ReleaseSafe и её отсутствие в ReleaseFast.урок 16 · Переполнение буфера и защиты от негоопираются: урок 17
  • Процедуры и стековые кадрыcall и ret, стек времени выполнения, шесть регистров аргументов и возврат в rax, callee-saved против caller-saved, локальные на стеке и в регистрах, рекурсия как обычный кадр, выравнивание стека на 16.урок 14 · Процедуры и стековые кадрыопираются: урок 15
  • Флаги, переходы и cmovФлаги CF, ZF, SF, OF, инструкции cmp и test, set по условию, кодирование переходов относительно счётчика, if в форме goto, условная передача данных cmov и цена ошибки предсказания ветвления с измерением.урок 12 · Флаги, переходы и cmovопираются: урок 13
  • Циклы и switch на машинном уровнеdo-while, while через jump-to-middle и guarded-do, for и continue на машинном уровне, switch через таблицу переходов и во что Zig превращает switch с диапазонами и labeled switch.урок 13 · Циклы и switch на машинном уровнеопираются: урок 14, урок 31
  • Числа с плавающей точкой и SIMDРегистры XMM и YMM, скалярные операции addsd и movsd, преобразования cvtsi2sd и cvttsd2si, float-константа в .rodata со смещением от rip, знак и модуль через xorps и andps, сравнение ucomisd и NaN через флаг чётности. Дальше книги: @Vector и AVX2, @reduce как дерево свёрток.урок 17 · Числа с плавающей точкой и SIMDопираются: урок 18
  • inline-ассемблер и голое железоasm volatile в Zig: ограничения, clobbers, volatile. Системный вызов write без libc, функция целиком на ассемблере в .s, собранная через zig cc и вызванная из теста, callconv(.naked) и своя _start, минимальный бинарник без std. Врезка про aarch64.урок 18 · inline-ассемблер и голое железоопираются: урок 19, урок 20, урок 42
  • JIT в машинный код x86-64Десять уроков читали машинный код, теперь пишем его сами. Тегированные значения в одно слово, шаблон на каждый узел дерева, вызов примитива через movabs и call, переход с обратной заплаткой, хвостовой вызов как jmp, память от mmap с правами на исполнение и ограничение W^X.урок 19 · JIT: пишем машинный код x86-64

Архитектура процессора: Y86-64 на Zig и Verilog

  • Ассемблер Y86-64 на ZigЛексер, директивы .pos, .align и .quad, два прохода и таблица меток, энкодер, листинг как у yas. Программы sum, rsum, absSum с переходом и с cmov, пузырьковая сортировка, switchv через таблицу переходов.урок 21 · Ассемблер Y86-64 на Zigопираются: урок 22
  • Принципы конвейераЗадержка и пропускная способность, конвейерные регистры, неравномерные этапы, накладные расходы регистров, глубокие конвейеры, обратная связь как проблема.урок 28 · Принципы конвейера: задержка и пропускная способностьопираются: урок 29
  • Симулятор Y86-64 на ZigСимулятор уровня инструкций: fetch, decode, execute, memory, writeback и pc как шесть функций над одной структурой состояния, коды Stat, трасса в формате, который потом печатает и Verilog. Тонкости pushq %rsp и popq %rsp.урок 22 · Симулятор Y86-64 на Zigопираются: урок 23
  • SEQ: этапы fetch и decodeШесть этапов SEQ, таблицы вычислений для каждого класса инструкций, этапы fetch и decode на Verilog: need_regids, need_valC, srcA и srcB, dstE и dstM.урок 26 · SEQ: этапы fetch и decodeопираются: урок 27
  • SEQ: execute, memory, write back и новый PCExecute с ALU и Cnd, memory с mem_addr, mem_data, mem_read и mem_write, Stat, write back, new_pc. SEQ собран целиком, программы урока 21 идут на нём, трасса сверяется с Zig-симулятором. Добавляем iaddq.урок 27 · SEQ: execute, memory, write back и новый PCопираются: урок 28
  • Verilog: вентили и комбинационная логикаЛогические вентили, модуль, wire и logic, assign, тестбенч с $display и $finish, запуск iverilog и vvp, lint через verilator. HCL из книги переводится на Verilog: eq, битовый мультиплексор, 64-битный компаратор.урок 23 · Вентили и комбинационная логика на Verilogопираются: урок 24
  • Verilog: слова, мультиплексоры и ALUСлова и шины, case как мультиплексор, always_comb, ALU Y86-64 с флагами ZF, SF и OF, принадлежность множеству через список меток в одном пункте case. Минимум и медиана трёх слов.урок 24 · Verilog: слова, мультиплексоры и ALUопираются: урок 25
  • Verilog: такт, регистры и памятьТактирование, always_ff по фронту, регистр, регистровый файл с двумя портами чтения и двумя записи, память с байтовой адресацией, дисциплина «читаем в такте, пишем по фронту», задержка и период такта, waveform в VCD.урок 25 · Verilog: такт, регистры и памятьопираются: урок 26
  • Y86-64: система команд и кодированиеСостояние, видимое программисту, полный список инструкций Y86-64 и их байтовое кодирование (icode и ifun, rA и rB, valC), чем учебная ISA отличается от x86-64, коды состояния AOK, HLT, ADR, INS. Кодируем руками, ищем битый байт, проектируем iaddq.урок 20 · Y86-64: система команд и кодированиеопираются: урок 21
  • PIPE на Verilog и CPIPIPE на Verilog: логика продвижения, stall и bubble, комбинации рисков, тесты на программах с известным числом тактов, CPI как единица плюс штрафы, сравнение стратегий предсказания, absSum на cmov против перехода.урок 30 · PIPE на Verilog и CPIопираются: урок 31
  • PIPE: риски, продвижение и остановыSEQ+ и перенос PC update, регистры F, D, E, M и W, предсказание PC, риски по данным, продвижение из пяти точек, риск загрузки и использования, ret и три пузырька, ошибочно предсказанный переход и два пузырька, исключения в конвейере.урок 29 · PIPE: риски, продвижение и остановыопираются: урок 30

Производительность программ

Иерархия памяти и кэши

  • Гора памятиПрограмма гора памяти на Zig: пропускная способность чтения по размеру рабочего множества и шагу, размеры L1, L2 и L3 читаются с графика, предвыборка видна на срезе по шагу, x86-64 против Apple Silicon.урок 41 · Гора памятиопираются: урок 42, урок 53
  • Организация кэшаИерархия как цепочка кэшей, виды промахов, параметры S, E, B и m, разбор адреса на тег, индекс и смещение, прямое отображение, ассоциативный и полностью ассоциативный кэш, LRU, политики записи, иерархия Core i7 и Apple M-серии.урок 38 · Организация кэшаопираются: урок 39
  • Технологии хранения и локальностьSRAM, DRAM, SSD и диск в одной таблице с числами 2026 года, время доступа и ресурс записи SSD. Временная и пространственная локальность данных и инструкций, обход с шагом 1 против шага N, чтение локальности по коду.урок 37 · Технологии хранения и локальностьопираются: урок 38
  • Код, дружественный к кэшуШесть порядков циклов умножения матриц и три класса промахов, блочное разбиение, транспонирование с минимумом промахов, структура массивов против массива структур, cache line и false sharing. cons-ячейки zl и кэш.урок 40 · Код, дружественный к кэшуопираются: урок 41
  • Симулятор кэша: cachelab на ZigПарсер трассы обращений в формате valgrind, симулятор S, E, B с LRU, счётчики попаданий, промахов и вытеснений, сверка с эталонными трассами, генератор трасс из своей программы. Кэш встаёт между Y86 и памятью.урок 39 · Симулятор кэша: cachelab на Zigопираются: урок 40

Компоновка

  • Объектные файлы, ELF и символыДрайвер компиляции, статическая компоновка как разрешение имён плюс перемещение, перемещаемый ELF по секциям, Elf64_Sym и типы символов, псевдосекции ABS, UNDEF и COMMON, что Zig кладёт в какую секцию. zt readelf и zt nm.урок 42 · Объектные файлы, ELF и символыопираются: урок 43
  • Перемещение и загрузкаЗаписи Elf64_Rela, R_X86_64_PC32 и R_X86_64_32 с расчётом руками, модели кода, исполняемый ELF по сегментам, заголовок программы, точка входа, образ процесса, _start и что Zig делает вместо libc. zt ld, второй шаг, и call rel32 в JIT zl.урок 44 · Перемещение и загрузкаопираются: урок 45
  • Подмена функций и компоновка на практикеПодмена на трёх уровнях: макросы и препроцессор, --wrap, LD_PRELOAD с dlsym RTLD_NEXT; трассировщик malloc для чужой программы; binutils на практике; Zig: musl против glibc, -fstrip, --gc-sections, кросс-линковка, zig cc, -lc. zt ltrace.урок 46 · Подмена функций и компоновка на практикеопираются: урок 47
  • Разрешение имён и статические библиотекиСильные и слабые определения, три правила и баги от них, статические библиотеки .a и алгоритм E, U, D, порядок в командной строке, циклические зависимости. В Zig: linkage weak и сборка .a в build.zig. zt ld, первый шаг.урок 43 · Разрешение имён и статические библиотекиопираются: урок 44
  • Динамическая компоновка, PIC, GOT и PLTРазделяемые библиотеки и ld-linux.so, dlopen и dlsym, позиционно-независимый код, GOT для данных, PLT и ленивое связывание для функций, -z now и RELRO. Своя .so на Zig из C и из Zig, LD_DEBUG=bindings. zt ldd.урок 45 · Динамическая компоновка, PIC, GOT и PLTопираются: урок 46

Исключения, процессы, сигналы

  • Исключения и системные вызовыЧетыре класса исключений, таблица исключений, режимы процессора, исключения x86-64, Linux syscall ABI, strace, сисколл руками через asm и через std.os.linux, что добавляют обёртки std.posix. trap в Y86 и zt strace.урок 47 · Исключения и системные вызовыопираются: урок 48
  • Нелокальные переходы и ошибки в Zigsetjmp и longjmp как исключения времени выполнения, sigsetjmp, чем это опасно; как Zig обходится без них: ошибки как значения, errdefer, @panic, свой обработчик паники, трассы стека; сравнение с исключениями C++.урок 51 · Нелокальные переходы и ошибки в Zigопираются: урок 52
  • Процессы: fork, execve, waitpidЛогический поток управления и своё адресное пространство, переключение контекста, fork и графы процессов, execve, waitpid, зомби, std.process.Child, ловушка буферизации при fork. Контексты процессов Y86 и zbox run.урок 48 · Процессы: fork, execve, waitpidопираются: урок 49
  • Проект: оболочка с job controlРазбор командной строки, встроенные jobs, bg, fg и quit, фоновые задания, группы процессов и терминал, SIGINT, SIGTSTP, SIGCHLD и SIGCONT, пайпы и переадресация, проверка трассами как в shlab.урок 52 · Оболочка с управлением заданиями: shlab на Zig
  • Проект: ядро для Y86Таймер как устройство, прерывание по тактам, контекст в PCB, переключение двух процессов по кругу, сисколлы write, yield и exit, маска прерываний в обработчике и что ломается без неё, iret.урок 50 · Ядро на своей машине: таймер, вытеснение и маска прерываний
  • СигналыОтправка и получение сигналов, группы процессов, обработчики, блокировка через sigprocmask, сигналы не копятся в очередь, шесть правил безопасного обработчика, гонка при регистрации задания и sigsuspend. zt prof и лимит времени в zbox.урок 49 · Сигналыопираются: урок 50, урок 51

Виртуальная память и аллокаторы

Системный ввод/вывод

  • Буферизованный ввод/вывод и метаданныеСвой RIO с внутренним буфером, цена системного вызова, std.Io.Reader и Writer с явным буфером и забытый flush, ошибка смешивания буферов, stat и fstat, обход каталога, копирование блоками. Захват вывода в zbox.урок 61 · Буферизованный ввод-вывод и метаданные файловопираются: урок 62
  • Общие файлы, переадресация и пайпыТри таблицы ядра, fork и общая позиция в файле, dup2 и переадресация, конвейер из pipe, dup2 и execve, SIGPIPE и EPIPE, O_CLOEXEC, стандартный ввод/вывод против системного, сокеты как файлы.урок 62 · Общие файлы, переадресация и пайпыопираются: урок 63
  • Unix I/O и короткие счётыФайл как последовательность байтов, open, read, write, lseek и close, правило наименьшего свободного дескриптора, откуда берутся короткие счёты, readn и writen на Zig, std.Io.File как обёртка. Устройства Y86.урок 60 · Unix I/O и короткие счётыопираются: урок 61

Сети и веб-сервер

  • Клиент, сервер и устройство сетиМодель клиент-сервер как транзакции, из чего сделана сеть: LAN, маршрутизаторы, инкапсуляция, IP-адреса в четырёх формах, DNS, соединение как пара сокетов, getaddrinfo и getnameinfo, hostinfo на Zig.урок 63 · Клиент, сервер и устройство сетиопираются: урок 64
  • Сокеты: эхо-клиент и эхо-серверsocket, connect, bind, listen, accept, структуры адресов, open_clientfd и open_listenfd на Zig, эхо-клиент и эхо-сервер, std.Io.net как обёртка, SO_REUSEADDR, что видно в ss и lsof. Сеть выключена в zbox.урок 64 · Сокеты: эхо-клиент и эхо-серверопираются: урок 65
  • HTTP и веб-контентВеб как набор соглашений: URL, статический и динамический контент, MIME, транзакция HTTP по строкам, заголовки и коды ответов, CGI через fork, execve и переменные окружения, буферизация в дочернем процессе.урок 65 · HTTP и веб-контентопираются: урок 66
  • Проект: веб-сервер TINYTINY на Zig: doit, разбор строки запроса и заголовков, parse_uri, serve_static через mmap, serve_dynamic через dup2 в сокет, clienterror, проверка через curl, HEAD, POST, SIGPIPE, видео. POST /run в zbox.урок 66 · Проект: веб-сервер TINYопираются: урок 67
  • Проект: песочница как у раннера курсаФинал zbox: пространства имён через clone и unshare, pivot_root в свою корневую ФС, mount для /proc, PR_SET_NO_NEW_PRIVS, seccomp-фильтр из таблицы разрешённых сисколлов, сверху TINY с POST /run, сравнение с флагами docker run у bs-runner.урок 67 · Проект: песочница как у раннера курсаопираются: урок 68

Конкурентность и прокси

  • ПотокиМодель выполнения потоков, std.Thread над pthreads: spawn, join, detach, передача аргументов и гонка с индексом цикла, сервер на потоках, что общего у потоков с процессами и что нет, zt prof по потокам.урок 69 · Потокиопираются: урок 70
  • Потокобезопасность, гонки и взаимоблокировкиЧетыре класса небезопасных функций, реентерабельность против потокобезопасности, блокировка с копированием, гонки, взаимоблокировка на графе выполнения и правило порядка захвата, ThreadSanitizer.урок 72 · Потокобезопасность, гонки и взаимоблокировкиопираются: урок 73
  • Проект: async в Zig и кэширующий проксиБесцветный async Zig 0.16: Io.Threaded и Io.Evented для одного кода, io.async, Group, Queue, отмена; сравнение с тремя моделями книги. Финал proxylab: кэширующий веб-прокси с пулом, LRU-кэшем под читателями-писателями и тестами.урок 73 · Проект: async в Zig и кэширующий прокси
  • Пул потоков и параллельные вычисленияСервер с заранее созданным пулом на sbuf, psum в пяти версиях от мьютекса на итерацию и атомика до общего массива и локального аккумулятора, ускорение и эффективность, сильное и слабое масштабирование, закон Амдала числом, false sharing.урок 71 · Пул потоков и параллельные вычисленияопираются: урок 72
  • Разделяемые переменные и семафорыКакие переменные общие у потоков, badcnt и граф выполнения, семафоры P и V, мьютекс как двоичный семафор, sbuf производитель-потребитель, читатели и писатели в двух вариантах, Mutex, Semaphore, Condition и RwLock из std.Io.урок 70 · Разделяемые переменные и семафорыопираются: урок 71
  • Сервер на процессах и мультиплексирование ввода-выводаТри способа обслужить много клиентов: процесс на соединение и его цена, select и poll с пулом дескрипторов, событийный сервер как конечный автомат, epoll против select на тысяче соединений, kqueue на macOS.урок 68 · Сервер на процессах и мультиплексирование ввода-выводаопираются: урок 69