```markdown # КВС — Ассемблер с русским синтаксисом для x86-64 **КВС** — это экспериментальный ассемблер для архитектуры x86-64, полностью использующий **русскую лексику** для мнемоник инструкций, имён регистров и директив. Проект носит образовательный характер и демонстрирует принципы работы ассемблера, построения ELF-файлов и трансляции высокоуровневых концепций в машинный код. ## 📋 Оглавление - [Особенности](#-особенности) - [Архитектура](#-архитектура) - [Установка](#-установка) - [Быстрый старт](#-быстрый-старт) - [Система тестирования](#-система-тестирования) - [Синтаксис](#-синтаксис) - [Система команд](#-система-команд) - [Регистры](#-регистры-процессора) - [Директивы](#-директивы-ассемблера) - [Примеры программ](#-примеры-программ) - [Отладка и проверка](#-отладка-и-проверка) - [Ограничения](#-ограничения) - [План развития](#-план-развития) - [Лицензия](#-лицензия) ## ✨ Особенности - **Полностью русский синтаксис** — все инструкции, регистры и директивы на кириллице - **Генерация исполняемых ELF-файлов** — 64-битные ELF для Linux, готовые к запуску - **Шестипроходная сборка** — разделение логики на независимые этапы для прозрачности и отладки - **Поддержка секций** — разделение на `.текст` (код), `.данные` (данные) и `.бнд` (неинициализированные данные) - **Гибкая адресация памяти**: - абсолютная адресация по меткам `[переменная]` - абсолютная адресация по числовому адресу `[0x402000]` - косвенная адресация через регистр `[раикс]` - всё с RIP-relative кодированием для 64-битных перемещений - **CSV-логирование** — детальный файл с соответствием адресов, байтов, меток и исходных команд - **Более 50 инструкций** — полный набор основных команд x86-64 - **Автоматическая система регрессионного тестирования** — 9+ тестов, проверяющих все аспекты работы ассемблера - **Минимализм зависимостей** — только стандартная библиотека Python ## 🏗 Архитектура Процесс трансляции исходного кода `.квс` в исполняемый файл `.elf` проходит через **6 этапов**: ``` Исходный файл (.квс) │ ▼ (kvs_lexer.py) ← лексический анализ Файл токенов (.токены) │ ▼ (kvs_parser.py) ← синтаксический анализ AST-представление (.аст) │ ▼ (kvs_pass1.py) ← ПРОХОД 1: генерация CSV с заглушками (0xCC) CSV-файл (.csv) ← содержит все байты программы, метки, виртуальные адреса │ ▼ (kvs_pass2.py) ← ПРОХОД 2: разрешение меток │ ▼ (kvs_pass3.py) ← ПРОХОД 3: подстановка констант (.константа) │ ▼ (kvs_pass4.py) ← ПРОХОД 4: перекодирование инструкций │ ▼ (kvs_pass5.py) ← ПРОХОД 5: генерация корректных таблиц секций для совместимости с toolchain │ ▼ (kvs_pass6.py) ← ПРОХОД 6: постобработка CSV для визуального анализа │ ▼ (kvs_builder.py) ← сборка ELF из CSV ELF-файл (.elf) │ ▼ Исполняемый файл! ``` ### Почему 6 проходов? 1. **Первый проход** — неизвестно, какие адреса будут у меток. Ставим заглушки `0xCC`. 2. **Второй проход** — после того как все адреса меток известны, заменяем заглушки. 3. **Третий проход** — константы могут ссылаться друг на друга и на метки. 4. **Четвёртый проход** — после подстановки чисел перегенерируем машинный код (разная длина инструкций). 5. **Пятый проход** — генерируем корректные таблицы секций для работы `objdump`, `readelf` и GDB. 6. **Шестой проход** — сортируем CSV для удобного визуального анализа человеком. Такой подход позволяет **изолировать логику** каждого этапа и делает отладку прозрачной. ### Модули компилятора | Файл | Назначение | |------|-------------| | `kvs_build.py` | Главный сборочный скрипт | | `kvs_lexer.py` | Лексический анализ | | `kvs_parser.py` | Синтаксический анализ, построение AST | | `kvs_data.py` | Общие данные: регистры, таблица инструкций | | `kvs_encoder.py` | Фасад кодировщика | | `kvs_encoder_fixsize.py` | Кодировщик инструкций фиксированного размера | | `kvs_encoder_mutsize.py` | Кодировщик инструкций переменного размера | | `kvs_pass1.py` | Генерация CSV с заглушками | | `kvs_pass2.py` | Разрешение меток | | `kvs_pass3.py` | Подстановка констант | | `kvs_pass4.py` | Перекодирование инструкций | | `kvs_pass5.py` | Генерация таблиц секций | | `kvs_pass6.py` | Сортировка CSV | | `kvs_builder.py` | Сборка ELF из CSV | ### Структура CSV-файла | Колонка | Назначение | |---------|-------------| | `сегмент` | Имя секции (`.header`, `.text`, `.data`, `.bss`) | | `адрес` | Файловое смещение байта | | `виртуальный_адрес` | Виртуальный адрес байта в памяти | | `байт` | Исходное значение байта (из pass1) | | `приводящая_метка` | Имена меток на этом адресе | | `уводящий_адрес` | Строка `ЗАГЛУШКА имя` для неразрешённых меток | | `исходная_команда` | Исходная инструкция | | `команда_со_значениями` | Инструкция с подставленными адресами/константами | | `рассчитанный_уводящий_адрес` | Реальный адрес метки после разрешения | | `рассчитанный_байт` | Итоговый байт после перекодирования | ## 🔧 Установка ```bash # Клонирование репозитория git clone https://github.com/artradeskz/kvs.git cd kvs # Установка прав на выполнение chmod +x kvs_build.py # Проверка работы python3 kvs_build.py --help ``` ## 🚀 Быстрый старт ### 1. Создайте файл `hello.квс`: ```assembly .текст .глобал _start _start: ; write(1, msg, 21) переместить_имм раикс,1 переместить_имм рдиай,1 переместить_имм рсиай, msg переместить_имм рдикс,21 вызов_системы ; exit(0) переместить_имм раикс,60 переместить_имм рдиай,0 вызов_системы .данные msg: .строка "Привет мир!\n" ``` ### 2. Скомпилируйте: ```bash python3 kvs_build.py hello.квс ``` ### 3. Запустите: ```bash ./hello.elf ``` **Вывод:** ``` Привет мир! ``` ## 🧪 Система тестирования Проект включает автоматическую систему регрессионного тестирования, которая проверяет все аспекты работы ассемблера. ### Структура тестов ``` тесты/ ├── kvs_full_test.py # диспетчер тестов ├── kvs_full_test.csv # таблица активных тестов ├── cleaner.py # очистка артефактов ├── привет/ # тест вывода строки │ ├── привет.квс │ └── привет.py ├── сложный_тест/ # тест запутанных переходов ├── длин_тест/ # тест длинных переходов (jmp rel32) ├── вывод_аргумента/ # тест аргументов командной строки ├── тест_адресации_р8/ # косвенная адресация через R8 ├── тест_адресации1/ # абсолютная адресация по числовому адресу ├── тест_адресации2/ # абсолютная адресация по метке ├── тест_адресации3/ # косвенная адресация через RBX └── тест_бнд/ # проверка BSS секции (.bss) ``` ### Запуск тестов ```bash python3 тесты/kvs_full_test.py ``` ### Добавление нового теста 1. Создать папку `тесты/имя_теста/` 2. Положить туда `имя_теста.квс` и `имя_теста.py` 3. Добавить строку в `kvs_full_test.csv`: ``` 1;имя_теста;Описание теста ``` 4. Запустить `python3 тесты/kvs_full_test.py` ### Что проверяют тесты | Тест | Проверяет | |------|-----------| | `привет` | Вывод строки на русском, exit(0) | | `сложный_тест` | Короткие условные переходы | | `длин_тест` | Длинные переходы (jmp rel32) | | `вывод_аргумента` | Аргументы командной строки (2 сценария) | | `тест_адресации_р8` | Косвенную адресацию через R8 | | `тест_адресации1` | Абсолютную адресацию `[0x402000]` | | `тест_адресации2` | Абсолютную адресацию по метке | | `тест_адресации3` | Косвенную адресацию через RBX | | `тест_бнд` | BSS секцию: NOBITS, размер, p_memsz | ## 📝 Синтаксис ### Структура программы ```assembly .текст ; секция кода (обязательна) ; ... инструкции ... .данные ; секция данных (опциональна) ; ... инициализированные данные ... .бнд ; секция неинициализированных данных (опциональна) ; ... переменные без начального значения ... ``` ### Метки ```assembly _start: ; метка _start переместить_имм раикс,1 переход _start ; переход на метку ``` ### Комментарии ```assembly ; Это комментарий переместить_имм раикс,42 ; комментарий после инструкции ``` ### Работа с памятью ```assembly ; Запись значения в память по метке переместить_имм раикс,42 сохранить [переменная], раикс ; Чтение значения из памяти загрузить рбикс,[переменная] ; Запись по абсолютному адресу сохранить [0x402000], раикс ; Косвенная адресация через регистр переместить_имм рбикс, переменная загрузить раикс, [рбикс] ; Работа с BND-секцией .бнд счётчик: .байт 0 ``` ## 📖 Система команд ### Загрузка констант | Инструкция | Синтаксис | Описание | |------------|-----------|----------| | `переместить_имм` | `переместить_имм рег, значение` | Загрузить константу в регистр | ```assembly переместить_имм раикс,42 ; RAX = 42 переместить_имм еаикс,0x7FFF ; EAX = 32767 переместить_имм ал,0xFF ; AL = 255 ``` ### Работа с памятью | Инструкция | Синтаксис | Описание | |------------|-----------|----------| | `загрузить` | `загрузить рег, [метка/адрес/регистр]` | Загрузить значение из памяти | | `сохранить` | `сохранить [метка/адрес/регистр], рег` | Сохранить значение в память | ```assembly загрузить раикс,[переменная] ; RAX = *переменная сохранить [результат], раикс ; *результат = RAX загрузить рбикс,[0x402000] ; загрузка по абсолютному адресу загрузить раикс,[рбикс] ; косвенная загрузка через регистр ``` ### Арифметика и логика | Инструкция | Синтаксис | Описание | |------------|-----------|----------| | `прибавить` | `прибавить рег1, рег2` | рег1 += рег2 | | `вычесть` | `вычесть рег1, рег2` | рег1 -= рег2 | | `увеличить` | `увеличить рег` | рег++ | | `уменьшить` | `уменьшить рег` | рег-- | | `сравнить` | `сравнить рег1, рег2` | Сравнить регистры | | `сравнить_с` | `сравнить_с рег, значение` | Сравнить с константой | | `проверить` | `проверить рег1, рег2` | TEST (логическое AND) | ```assembly прибавить раикс, рбикс ; RAX += RBX увеличить рсикс ; RCX++ сравнить раикс,10 ; сравнить RAX с 10 ``` ### Переходы | Инструкция | Условие | |------------|---------| | `переход` | Безусловный | | `короткий_переход` | Безусловный (смещение ±127) | | `переход_если_равно` | ZF = 1 | | `переход_если_неравно` | ZF = 0 | | `переход_если_меньше` | SF ≠ OF (signed <) | | `переход_если_больше` | ZF = 0 и SF = OF (signed >) | | `переход_если_меньше_или_равно` | ZF = 1 или SF ≠ OF | | `переход_если_больше_или_равно` | SF = OF | | `переход_если_перенос` | CF = 1 | | `переход_если_нет_переноса` | CF = 0 | ### Системные вызовы | Инструкция | Описание | |------------|----------| | `вызов_системы` | Вызов ядра Linux (syscall) | ```assembly ; Пример: завершение программы переместить_имм раикс,60 ; syscall 60 = exit переместить_имм рдиай,0 ; код возврата 0 вызов_системы ``` ## 💾 Регистры процессора КВС поддерживает все основные 64-битные регистры x86-64: | 64-бит | 32-бит | 16-бит | 8-бит (мл.) | |--------|--------|--------|-------------| | `раикс` | `еаикс` | `аикс` | `ал` | | `рбикс` | `ебикс` | `бикс` | `бл` | | `рсикс` | `есикс` | `сикс` | `кл` | | `рдикс` | `едикс` | `дикс` | `дл` | | `рсипи` | `есипи` | `эсп` | `спл` | | `рбипи` | `ебипи` | `бипи` | `бпл` | | `рсиай` | `есиай` | `эс` | `сил` | | `рдиай` | `едиай` | `ди` | `дил` | ## 🔧 Директивы ассемблера | Директива | Назначение | Пример | |-----------|------------|--------| | `.текст` | Начало секции кода | `.текст` | | `.данные` | Начало секции инициализированных данных | `.данные` | | `.бнд` | Начало секции неинициализированных данных | `.бнд` | | `.глобал` | Объявление глобальной метки | `.глобал _start` | | `.строка` | Строка без завершающего нуля | `.строка "Hello"` | | `.строка_нуль` | Строка с завершающим нулём | `.строка_нуль "Hello"` | | `.байт` | Последовательность байтов | `.байт 0x48, 0x65, 108` | | `.константа` | Определение константы | `.константа LEN = 10` | | `.резб` | Резервирование байтов в BND | `.резб 100` | | `.резс` | Резервирование слов в BND | `.резс 50` | | `.рездс` | Резервирование двойных слов в BND | `.рездс 25` | | `.резкс` | Резервирование квадрослов в BND | `.резкс 10` | ## 📝 Примеры программ ### Работа с памятью (переменные) ```assembly .текст .глобал _start _start: переместить_имм раикс,42 сохранить [переменная], раикс загрузить рбикс,[переменная] переместить_имм раикс,60 загрузить рдиай,[переменная] вызов_системы .данные переменная: .байт 0 ``` ### Цикл и условный переход ```assembly .текст .глобал _start _start: переместить_имм рсикс,10 loop: переместить_имм раикс,1 переместить_имм рдиай,1 переместить_имм рсиай, msg переместить_имм рдикс,10 вызов_системы уменьшить рсикс сравнить_с рсикс,0 переход_если_больше loop переместить_имм раикс,60 переместить_имм рдиай,0 вызов_системы .данные msg: .строка "Iteration\n" ``` ### Вычисление суммы чисел от 1 до 10 ```assembly .текст .глобал _start _start: переместить_имм р8,0 переместить_имм р9,10 loop: прибавить р8, р9 уменьшить р9 сравнить_с р9,0 переход_если_больше loop переместить_имм раикс,60 переместить рдикс, р8 вызов_системы ``` ### Использование BND-секции ```assembly .текст .глобал _start _start: переместить_имм раикс,0 сохранить [счётчик], раикс переместить_имм рсикс,10 loop: загрузить раикс,[счётчик] увеличить раикс сохранить [счётчик], раикс уменьшить рсикс сравнить_с рсикс,0 переход_если_больше loop загрузить рдиай,[счётчик] переместить_имм раикс,60 вызов_системы .бнд счётчик: .байт 0 ``` ### Косвенная адресация ```assembly .текст .глобал _start _start: переместить_имм рбикс, переменная переместить_имм раикс,99 сохранить [рбикс], раикс загрузить раикс,[рбикс] переместить_имм рдиай, раикс переместить_имм раикс,60 вызов_системы .данные переменная: .байт 0 ``` ### Вывод аргумента командной строки ```assembly .текст .глобал _start _start: сравнить_с рдиай, 2 переход_если_не_равно no_arg загрузить р8, [рсиай + 8] переместить рдиай, р8 исключающее_или рдикс, рдикс strlen: загрузить ал, [р8] сравнить_с ал, 0 переход_если_равно strlen_done увеличить р8 увеличить рдикс переход strlen strlen_done: переместить_имм раикс, 1 переместить рсиай, рдиай переместить_имм рдиай, 1 вызов_системы исключающее_или рдиай, рдиай переместить_имм раикс, 60 вызов_системы no_arg: переместить_имм раикс, 1 переместить_имм рдиай, 1 переместить_имм рсиай, msg_no_arg переместить_имм рдикс, 26 вызов_системы переместить_имм рдиай, 1 переместить_имм раикс, 60 вызов_системы .данные msg_no_arg: .строка "Ошибка не передан аргумент\n" ``` ## 🐛 Отладка и проверка ### Просмотр сгенерированного кода ```bash # Дизассемблирование objdump -d программа.elf # Просмотр секций objdump -h программа.elf # Просмотр заголовков программы readelf -l программа.elf # Извлечение строк из ELF strings программа.elf ``` ### CSV-лог После компиляции создаётся файл `программа.csv` с полной информацией о каждом байте программы. ### Трассировка системных вызовов ```bash strace ./программа.elf ``` ### Отладка с GDB ```bash gdb ./программа.elf (gdb) break _start (gdb) run (gdb) info registers (gdb) x/10i $rip (gdb) stepi ``` ## ⚠️ Ограничения ### Поддерживается - 64-битные, 32-битные, 16-битные и 8-битные регистры (AL, BL, CL, DL) - Непосредственная загрузка констант (imm) в регистры - Сравнение регистров и регистров с константами - Условные и безусловные переходы (длинные и короткие) - Арифметические операции (ADD, SUB, INC, DEC) - Логическая операция TEST - Системные вызовы Linux (syscall) - Секции `.текст`, `.данные` и `.бнд` - Строковые литералы с escape-последовательностями (`\n`, `\t`, `\\`, `\"`) - Директива `.байт` для raw-данных - Директива `.константа` для имён констант - Директивы резервирования `.резб`, `.резс`, `.рездс`, `.резкс` - Абсолютная адресация по меткам и числовым адресам `[метка]` / `[0x402000]` - Косвенная адресация через регистр `[раикс]` - RIP-relative кодирование для всех видов адресации - Полная совместимость с `objdump`, `readelf`, `gdb` ### Не поддерживается (в разработке) - Адресация со смещением `[reg + disp]` - Сложная адресация с индексом `[reg + reg*scale]` - Полная SIB-адресация `[reg + reg*scale + disp]` - Поддержка плавающей запятой (FPU/SSE) - Многомодульная компиляция - Макросы ## Инструменты разработчика **Подсветка синтаксиса для VS Code** — доступно расширение [Universal Assembly Syntax Highlighting](https://github.com/artradeskz/Universal-Assembly-Syntax-Highlighting) с поддержкой языка КВС (русские инструкции, регистры, секции и директивы) ## 📈 План развития ### Реализовано (v2.0) - Лексер с поддержкой `[]`, `+`, `-`, `*` - Парсер с поддержкой операндов в квадратных скобках - Шестипроходная схема сборки (включая генерацию таблиц секций и сортировку CSV) - Поддержка меток в операндах памяти `[переменная]` - Поддержка числовых адресов `[0x402000]` - Поддержка косвенной адресации `[регистр]` - Секция `.бнд` для неинициализированных данных - Автоматическая система регрессионного тестирования (9+ тестов) - Полная совместимость со стандартным toolchain Linux ### В планах (v3.0) - Адресация со смещением `[reg + disp]` - Сложная адресация с индексом `[reg + reg*scale]` - Полная SIB-адресация `[reg + reg*scale + disp]` - Стандартная библиотека (`libkvs.квс`): malloc, free, strlen, strcmp, print ## 📄 Лицензия Только для образовательных целей. Используйте на свой страх и риск. --- *КВС Ассемблер | Экспериментальный проект | 2026* *Только для образовательных целей. Используйте на свой страх и риск.* ```