```markdown # КВС — Ассемблер с русским синтаксисом для x86-64 **КВС** — это экспериментальный ассемблер для архитектуры x86-64, полностью использующий **русскую лексику** для мнемоник инструкций, имён регистров и директив. Проект носит образовательный характер и демонстрирует принципы работы ассемблера, построения ELF-файлов и трансляции высокоуровневых концепций в машинный код. ## 📋 Оглавление - [Особенности](#-особенности) - [Архитектура](#-архитектура) - [Установка](#-установка) - [Быстрый старт](#-быстрый-старт) - [Синтаксис](#-синтаксис) - [Система команд](#-система-команд) - [Регистры](#-регистры-процессора) - [Директивы](#-директивы-ассемблера) - [Примеры программ](#-примеры-программ) - [Отладка](#-отладка-и-проверка) - [Ограничения](#-ограничения) - [План развития](#-план-развития) - [Лицензия](#-лицензия) ## ✨ Особенности - **Полностью русский синтаксис** — все инструкции, регистры и директивы на кириллице - **Генерация исполняемых ELF-файлов** — 64-битные ELF для Linux, готовые к запуску - **Двухпроходная сборка** — традиционная схема с разрешением меток - **Поддержка секций** — разделение на `.текст` (код), `.данные` (данные) и `.бсс` (неинициализированные данные) - **Гибкая адресация памяти**: - абсолютная адресация по меткам `[переменная]` - абсолютная адресация по числовому адресу `[0x402000]` - косвенная адресация через регистр `[раикс]` - всё с RIP-relative кодированием для 64-битных перемещений - **CSV-логирование** — детальный файл с соответствием адресов, байтов и исходных команд - **Более 50 инструкций** — полный набор основных команд x86-64 - **Минимализм зависимостей** — только стандартная библиотека Python - **Рефакторинг** — кодогенерация вынесена в отдельный модуль `kvs_pass2_encoder.py` ## 🏗 Архитектура Процесс трансляции исходного кода `.квс` в исполняемый файл `.elf` проходит через несколько этапов: ``` Исходный файл (.квс) │ ▼ (kvs_lexer.py) Файл токенов (.токены) │ ▼ (kvs_parser.py) AST-представление (.аст) │ ▼ (kvs_pass1.py) Первый проход: размеры, метки (.проход1) │ ▼ (kvs_pass2.py + kvs_pass2_encoder.py) Второй проход: генерация кода (.csv) │ ▼ (kvs_builder.py) ELF-компоновщик (.elf) │ ▼ Исполняемый файл! ``` ### Модули компилятора | Файл | Назначение | |------|-------------| | `kvs_build.py` | Главный сборочный скрипт | | `kvs_lexer.py` | Лексический анализ, разбор на токены | | `kvs_parser.py` | Синтаксический анализ, построение AST | | `kvs_pass1.py` | Первый проход: вычисление размеров и адресов меток | | `kvs_pass2.py` | Второй проход: обход AST, генерация CSV | | `kvs_pass2_encoder.py` | Кодировщик инструкций (все encode_* функции) | | `kvs_builder.py` | Сборка ELF-файла из CSV | | `kvs_data.py` | Общие данные (регистры, инструкции) | ## 🔧 Установка ```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, 13) переместить_имм раикс,1 переместить_имм рдиай,1 переместить_имм рсиай, msg переместить_имм рдикс,13 вызов_системы ; exit(0) переместить_имм раикс,60 переместить_имм рдиай,0 вызов_системы .данные msg: .строка_нуль "Hello, World!" ``` ### 2. Скомпилируйте: ```bash python3 kvs_build.py hello.квс ``` ### 3. Запустите: ```bash ./hello.elf ``` **Вывод:** ``` Hello, World! ``` ## 📝 Синтаксис ### Структура программы ```assembly .текст ; секция кода (обязательна) ; ... инструкции ... .данные ; секция данных (опциональна) ; ... инициализированные данные ... .бсс ; секция неинициализированных данных (опциональна) ; ... переменные без начального значения ... ``` ### Метки Метка — это имя, за которым следует двоеточие: ```assembly _start: ; метка _start переместить_имм раикс,1 переход _start ; переход на метку ``` ### Комментарии Однострочные комментарии начинаются с `;`: ```assembly ; Это комментарий переместить_имм раикс,42 ; комментарий после инструкции ``` ### Работа с памятью ```assembly ; Запись значения в память по метке переместить_имм раикс,42 сохранить [переменная], раикс ; Чтение значения из памяти загрузить рбикс,[переменная] ; Запись по абсолютному адресу сохранить [0x402000], раикс ; Косвенная адресация через регистр переместить_имм рбикс, переменная загрузить раикс, [рбикс] ; Работа с BSS-секцией .бсс счётчик: .байт 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 | **Короткие условные переходы** (префикс `короткий_`): - `короткий_переход_если_равно`, `короткий_переход_если_неравно`, и т.д. - Генерируют 2-байтовые инструкции (смещение ±127 байт) ### Системные вызовы | Инструкция | Описание | |------------|----------| | `вызов_системы` | Вызов ядра Linux (syscall) | ```assembly ; Пример: завершение программы переместить_имм раикс,60 ; syscall 60 = exit переместить_имм рдиай,0 ; код возврата 0 вызов_системы ``` ## 💾 Регистры процессора КВС поддерживает все основные 64-битные регистры x86-64: | 64-бит | 32-бит | 16-бит | 8-бит (мл.) | |--------|--------|--------|-------------| | `раикс` | `еаикс` | `аикс` | `ал` | | `рбикс` | `ебикс` | `бикс` | `бл` | | `рсикс` | `есикс` | `сикс` | `кл` | | `рдикс` | `едикс` | `дикс` | `дл` | | `рсипи` | `есипи` | `эсп` | `спл` | | `рбипи` | `ебипи` | `бипи` | `бпл` | | `рсиай` | `есиай` | `эс` | `сил` | | `рдиай` | `едиай` | `ди` | `дил` | ## 🔧 Директивы ассемблера | Директива | Назначение | Пример | |-----------|------------|--------| | `.текст` | Начало секции кода | `.текст` | | `.данные` | Начало секции инициализированных данных | `.данные` | | `.бсс` | Начало секции неинициализированных данных | `.бсс` | | `.глобал` | Объявление глобальной метки | `.глобал _start` | | `.строка` | Строка без завершающего нуля | `.строка "Hello"` | | `.строка_нуль` | Строка с завершающим нулём | `.строка_нуль "Hello"` | | `.байт` | Последовательность байтов | `.байт 0x48, 0x65, 108` | | `.константа` | Определение константы | `.константа LEN = 10` | ## 📝 Примеры программ ### Работа с памятью (переменные) ```assembly .текст .глобал _start _start: ; Запись значения в переменную переместить_имм раикс,42 сохранить [переменная], раикс ; Чтение значения из переменной загрузить рбикс,[переменная] ; Завершение с кодом возврата переместить_имм раикс,60 загрузить рдиай,[переменная] вызов_системы .данные переменная: .байт 0 ``` ### Цикл и условный переход ```assembly .текст .глобал _start _start: переместить_имм рсикс,10 ; счетчик = 10 loop: переместить_имм раикс,1 переместить_имм рдиай,1 переместить_имм рсиай, msg переместить_имм рдикс,10 вызов_системы уменьшить рсикс ; счетчик-- сравнить_с рсикс,0 переход_если_больше loop ; если > 0, продолжаем переместить_имм раикс,60 переместить_имм рдиай,0 вызов_системы .данные msg: .строка "Iteration\n" ``` ### Вычисление суммы чисел от 1 до 10 ```assembly .текст .глобал _start _start: переместить_имм р8,0 ; сумма переместить_имм р9,10 ; счётчик loop: прибавить р8, р9 уменьшить р9 сравнить_с р9,0 переход_если_больше loop ; exit(сумма в r8) переместить_имм раикс,60 переместить рдикс, р8 вызов_системы ``` ### Использование BSS-секции ```assembly .текст .глобал _start _start: ; инициализация счётчика в BSS переместить_имм раикс,0 сохранить [счётчик], раикс ; цикл: увеличить счётчик 10 раз переместить_имм рсикс,10 loop: загрузить раикс,[счётчик] увеличить раикс сохранить [счётчик], раикс уменьшить рсикс сравнить_с рсикс,0 переход_если_больше loop ; выход с кодом = значение счётчика загрузить рдиай,[счётчик] переместить_имм раикс,60 вызов_системы .бсс счётчик: .байт 0 ``` ### Косвенная адресация ```assembly .текст .глобал _start _start: ; загружаем адрес переменной в регистр переместить_имм рбикс, переменная ; косвенная запись переместить_имм раикс,99 сохранить [рбикс], раикс ; косвенное чтение загрузить раикс,[рбикс] ; выход переместить_имм рдиай, раикс переместить_имм раикс,60 вызов_системы .данные переменная: .байт 0 ``` ## 🐛 Отладка и проверка ### Просмотр сгенерированного кода ```bash # Дизассемблирование objdump -d программа.elf # Просмотр секций objdump -h программа.elf # Просмотр заголовков программы readelf -l программа.elf # Извлечение строк из ELF strings программа.elf ``` ### CSV-лог После компиляции создаётся файл `программа.csv` со структурой: | адрес | байт | целевой_адрес | исходная_команда | |-------|------|---------------|------------------| | 0x401000 | 48 | | переместить_имм раикс, 1 | | 0x401001 | B8 | | | | 0x401002 | 01 | | | | ... | ... | ... | ... | ### Трассировка системных вызовов ```bash strace ./программа.elf ``` ### Отладка с GDB ```bash gdb ./программа.elf (gdb) break _start ; установить точку останова (gdb) run ; запустить (gdb) info registers ; показать регистры (gdb) x/10i $rip ; показать 10 инструкций (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 кодирование для всех видов адресации ### Не поддерживается (в разработке) - ❌ Адресация со смещением `[reg + disp]` - ❌ Сложная адресация с индексом `[reg + reg*scale]` и полная SIB-адресация - ❌ Инструкции для работы со стеком (PUSH, POP, CALL, RET) - ❌ Старшие 8-битные регистры (AH, BH, CH, DH) и расширенные младшие (SPL, BPL, SIL, DIL) - ❌ Регистры R8–R15 и их байтовые/словные версии - ❌ Поддержка плавающей запятой (FPU/SSE) - ❌ Многомодульная компиляция - ❌ Макросы ## 📈 План развития ### Реализовано (v2.0) - Лексер с токенами `[`, `]`, `NUMBER` - Парсер с поддержкой операндов в квадратных скобках - Первый проход с корректным расчётом размера инструкций с памятью - Второй проход с кодированием абсолютной адресации через RIP-relative - Поддержка меток в операндах памяти `[переменная]` - Поддержка числовых адресов `[0x402000]` - Поддержка косвенной адресации `[регистр]` - Секция `.бсс` для неинициализированных данных - Рефакторинг: выделение кодировщика в отдельный модуль ### В планах (v3.0) - Адресация со смещением `[reg + disp]` - Сложная адресация с индексом `[reg + reg*scale]` - Полная SIB-адресация `[reg + reg*scale + disp]` - Поддержка инструкций PUSH/POP/CALL/RET для стековых операций - Стандартная библиотека (`libkvs.квс`): malloc, free, strlen, strcmp, print ## 📄 Лицензия Только для образовательных целей. Используйте на свой страх и риск. --- *КВС Ассемблер | Экспериментальный проект | 2026* *Только для образовательных целей. Используйте на свой страх и риск.* ```