diff --git a/README.md b/README.md index 6d3b859..77fd31d 100644 --- a/README.md +++ b/README.md @@ -1,52 +1,133 @@ -# Документация компилятора КВС +```markdown +# КВС (Компилятор B Семейства) — Ассемблер с русским синтаксисом для x86-64 -## 1. Общие сведения +[![Version](https://img.shields.io/badge/version-2.0-green.svg)](https://github.com/username/kvs) +[![Python](https://img.shields.io/badge/python-3.6+-blue.svg)](https://python.org) +[![License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE) -**КВС** (язык программирования) — это низкоуровневый язык, транслируемый в 64-битный ELF-исполняемый файл для архитектуры x86-64. Компилятор написан на Python и состоит из нескольких модулей, выполняющих лексический анализ, синтаксический разбор, двухпроходную генерацию кода и сборку ELF-файла. +**КВС** — это экспериментальный ассемблер для архитектуры x86-64, полностью использующий **русскую лексику** для мнемоник инструкций, имён регистров и директив. Проект носит образовательный характер и демонстрирует принципы работы ассемблера, построения ELF-файлов и трансляции высокоуровневых концепций в машинный код. -### 1.1. Состав компилятора +## 📋 Оглавление + +- [Особенности](#-особенности) +- [Архитектура](#-архитектура) +- [Установка](#-установка) +- [Быстрый старт](#-быстрый-старт) +- [Синтаксис](#-синтаксис) +- [Система команд](#-система-команд) +- [Регистры](#-регистры-процессора) +- [Директивы](#-директивы-ассемблера) +- [Примеры программ](#-примеры-программ) +- [Отладка](#-отладка-и-проверка) +- [Ограничения](#-ограничения) +- [Лицензия](#-лицензия) + +## ✨ Особенности + +- **Полностью русский синтаксис** — все инструкции, регистры и директивы на кириллице +- **Генерация исполняемых ELF-файлов** — 64-битные ELF для Linux, готовые к запуску +- **Двухпроходная сборка** — традиционная схема с разрешением меток +- **Поддержка секций** — разделение на `.текст` (код) и `.данные` (данные) +- **CSV-логирование** — детальный файл с соответствием адресов, байтов и исходных команд +- **Более 50 инструкций** — полный набор основных команд x86-64 +- **Минимализм зависимостей** — только стандартная библиотека Python + +## 🏗 Архитектура + +Процесс трансляции исходного кода `.квс` в исполняемый файл `.elf` проходит через несколько этапов: + +``` +Исходный файл (.квс) + │ + ▼ (kvs_lexer.py) +Файл токенов (.токены) + │ + ▼ (kvs_parser.py) +AST-представление (.аст) + │ + ▼ (kvs_pass1.py) +Первый проход: размеры, метки (.проход1) + │ + ▼ (kvs_pass2.py) +Второй проход: генерация кода (.csv) + │ + ▼ (kvs_builder.py) +ELF-компоновщик (.elf) + +Исполняемый файл! +``` + +### Модули компилятора | Файл | Назначение | |------|------------| -| `kvs_8.py` | Монолитный ассемблер (оригинальная версия) | -| `kvs_build.py` | Главный сборочный скрипт, запускающий все этапы | +| `kvs_build.py` | Главный сборочный скрипт | | `kvs_lexer.py` | Лексический анализ, разбор на токены | | `kvs_parser.py` | Синтаксический анализ, построение AST | | `kvs_pass1.py` | Первый проход: вычисление размеров и адресов меток | | `kvs_pass2.py` | Второй проход: генерация машинного кода | -| `kvs_builder.py` | Сборка ELF-файла из CSV-данных | -| `kvs_data.py` | Общие данные (регистры, инструкции, константы) | +| `kvs_builder.py` | Сборка ELF-файла из CSV | +| `kvs_data.py` | Общие данные (регистры, инструкции) | -### 1.2. Запуск компилятора +## 🔧 Установка ```bash -# Монолитная версия -python3 kvs_8.py <файл.квс> +# Клонирование репозитория +git clone https://github.com/username/kvs.git +cd kvs -# Декомпозированная версия -python3 kvs_build.py <файл.квс> +# Установка прав на выполнение (при необходимости) +chmod +x kvs_build.py + +# Проверка работы +python3 kvs_build.py --help ``` -Входной файл должен иметь расширение **`.квс`**. +## 🚀 Быстрый старт -### 1.3. Результаты компиляции +### 1. Создайте файл `hello.квс`: -| Файл | Содержимое | -|------|------------| -| `<имя>.elf` | Исполняемый ELF-файл (64-bit) | -| `<имя>.log.csv` | Лог с адресами, байтами и соответствием командам | -| `<имя>.токены` | Промежуточный файл токенов (только для декомп. версии) | -| `<имя>.аст` | Промежуточный AST-файл (только для декомп. версии) | -| `<имя>.проход1` | Данные первого прохода (только для декомп. версии) | -| `<имя>.csv` | CSV с машинным кодом (только для декомп. версии) | +```asm +.текст +.глобал _start ---- +_start: + ; write(1, msg, 13) + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, msg + переместить_имм рдикс, 13 + вызов_системы -## 2. Синтаксис языка КВС + ; exit(0) + переместить_имм раикс, 60 + переместить_имм рдиай, 0 + вызов_системы -### 2.1. Структура программы +.данные +msg: .строка_нуль "Hello, World!" +``` -Программа на КВС состоит из секций: +### 2. Скомпилируйте: + +```bash +python3 kvs_build.py hello.квс +``` + +### 3. Запустите: + +```bash +./hello.elf +``` + +**Вывод:** +``` +Hello, World! +``` + +## 📝 Синтаксис + +### Структура программы ``` .текст ; секция кода (обязательна) @@ -56,60 +137,28 @@ python3 kvs_build.py <файл.квс> ; ... данные ... ``` -### 2.2. Метки +### Метки -Метка — это имя, за которым следует двоеточие. Метки могут использоваться как цели переходов. +Метка — это имя, за которым следует двоеточие: -``` +```asm _start: ; метка _start переместить_имм раикс, 1 переход _start ; переход на метку ``` -### 2.3. Директивы - -| Директива | Назначение | Пример | -|-----------|------------|--------| -| `.текст` | Начало секции кода | `.текст` | -| `.данные` | Начало секции данных | `.данные` | -| `.глобал` | Объявление глобальной метки (точки входа) | `.глобал _start` | -| `.строка` | Строка без завершающего нуля | `.строка "Hello"` | -| `.строка_нуль` | Строка с завершающим нулём | `.строка_нуль "Hello"` | -| `.байт` | Последовательность байтов | `.байт 0x48, 0x65, 108` | -| `.константа` | Определение константы | `.константа LEN = 10` | - -### 2.4. Комментарии +### Комментарии Однострочные комментарии начинаются с `;`: -``` +```asm ; Это комментарий переместить_имм раикс, 42 ; комментарий после инструкции ``` ---- +## 📖 Система команд -## 3. Система команд - -### 3.1. Регистры - -КВС поддерживает все основные 64-битные регистры x86-64 в различных размерностях: - -| Размер | 64-бит | 32-бит | 16-бит | 8-бит (мл.) | 8-бит (ст.) | -|--------|--------|--------|--------|-------------|-------------| -| RAX | `раикс` | `еаикс` | `аикс` | `ал` | `аш` | -| RCX | `рсикс` | `есикс` | `сикс` | `кл` | `чш` | -| RDX | `рдикс` | `едикс` | `дикс` | `дл` | `дш` | -| RBX | `рбикс` | `ебикс` | `бикс` | `бл` | `бш` | -| RSP | `рсипи` | `есипи` | `эсп` | `спл` | — | -| RBP | `рбипи` | `ебипи` | `бипи` | `бпл` | — | -| RSI | `рсиай` | `есиай` | `эс` | `сил` | — | -| RDI | `рдиай` | `едиай` | `ди` | `дил` | — | -| R8-R15 | `р8`…`р15` | `р8д`…`р15д` | `р8в`…`р15в` | `р8б`…`р15б` | — | - -### 3.2. Инструкции - -#### Загрузка констант +### Загрузка констант | Инструкция | Синтаксис | Описание | |------------|-----------|----------| @@ -117,11 +166,11 @@ _start: ; метка _start ```asm переместить_имм раикс, 42 ; RAX = 42 -переместить_имм еаикс, 0x7FFF ; EAX = 32767 (32-бит) -переместить_имм ал, 0xFF ; AL = 255 (8-бит) +переместить_имм еаикс, 0x7FFF ; EAX = 32767 +переместить_имм ал, 0xFF ; AL = 255 ``` -#### Арифметика и логика +### Арифметика и логика | Инструкция | Синтаксис | Описание | |------------|-----------|----------| @@ -129,9 +178,9 @@ _start: ; метка _start | `вычесть` | `вычесть рег1, рег2` | рег1 -= рег2 | | `увеличить` | `увеличить рег` | рег++ | | `уменьшить` | `уменьшить рег` | рег-- | -| `сравнить` | `сравнить рег1, рег2` | Сравнить два регистра (установка флагов) | -| `сравнить_с` | `сравнить_с рег, значение` | Сравнить регистр с константой | -| `проверить` | `проверить рег1, рег2` | TEST — логическое AND (установка ZF) | +| `сравнить` | `сравнить рег1, рег2` | Сравнить регистры | +| `сравнить_с` | `сравнить_с рег, значение` | Сравнить с константой | +| `проверить` | `проверить рег1, рег2` | TEST (логическое AND) | ```asm прибавить раикс, рбикс ; RAX += RBX @@ -139,80 +188,69 @@ _start: ; метка _start сравнить раикс, 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 | -| `переход_если_ноль` | `переход_если_ноль метка` | ZF = 1 (синоним JE) | -| `переход_если_не_ноль` | `переход_если_не_ноль метка` | ZF = 0 (синоним JNE) | +| Инструкция | Условие | +|------------|---------| +| `переход` | Безусловный | +| `короткий_переход` | Безусловный (смещение ±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) | +| Инструкция | Описание | +|------------|----------| +| `вызов_системы` | Вызов ядра Linux (syscall) | ```asm -; Пример: вывод строки -переместить_имм раикс, 1 ; syscall 1 = write -переместить_имм рдиай, 1 ; stdout -переместить_имм рсиай, msg ; указатель на строку -переместить_имм рдикс, len ; длина строки -вызов_системы - ; Пример: завершение программы переместить_имм раикс, 60 ; syscall 60 = exit переместить_имм рдиай, 0 ; код возврата 0 вызов_системы ``` -#### Прочие инструкции +## 💾 Регистры процессора -| Инструкция | Синтаксис | Описание | -|------------|-----------|----------| -| `нет_операции` | `нет_операции` | NOP (0x90) | +КВС поддерживает все основные 64-битные регистры x86-64: ---- +| 64-бит | 32-бит | 16-бит | 8-бит (мл.) | 8-бит (ст.) | +|--------|--------|--------|-------------|-------------| +| `раикс` | `еаикс` | `аикс` | `ал` | `аш` | +| `рбикс` | `ебикс` | `бикс` | `бл` | `бш` | +| `рсикс` | `есикс` | `сикс` | `кл` | `чш` | +| `рдикс` | `едикс` | `дикс` | `дл` | `дш` | +| `рсипи` | `есипи` | `эсп` | `спл` | — | +| `рбипи` | `ебипи` | `бипи` | `бпл` | — | +| `рсиай` | `есиай` | `эс` | `сил` | — | +| `рдиай` | `едиай` | `ди` | `дил` | — | +| `р8`…`р15` | `р8д`…`р15д` | `р8в`…`р15в` | `р8б`…`р15б` | — | -## 4. Примеры программ +## 🔧 Директивы ассемблера -### 4.1. Hello World +| Директива | Назначение | Пример | +|-----------|------------|--------| +| `.текст` | Начало секции кода | `.текст` | +| `.данные` | Начало секции данных | `.данные` | +| `.глобал` | Объявление глобальной метки | `.глобал _start` | +| `.строка` | Строка без завершающего нуля | `.строка "Hello"` | +| `.строка_нуль` | Строка с завершающим нулём | `.строка_нуль "Hello"` | +| `.байт` | Последовательность байтов | `.байт 0x48, 0x65, 108` | +| `.константа` | Определение константы | `.константа LEN = 10` | -```asm -.текст -.глобал _start +## 📝 Примеры программ -_start: - переместить_имм раикс, 1 - переместить_имм рдиай, 1 - переместить_имм рсиай, msg - переместить_имм рдикс, len_msg - вызов_системы - - переместить_имм раикс, 60 - переместить_имм рдиай, 0 - вызов_системы - -.данные - msg: .строка_нуль "Hello, World!\n" - .константа len_msg = 15 -``` - -### 4.2. Цикл и условный переход +### Цикл и условный переход ```asm .текст @@ -222,7 +260,6 @@ _start: переместить_имм рсикс, 10 ; счетчик = 10 loop: - ; тело цикла переместить_имм раикс, 1 переместить_имм рдиай, 1 переместить_имм рсиай, msg @@ -238,116 +275,74 @@ loop: вызов_системы .данные - msg: .строка_нуль "Iteration\n" +msg: .строка_нуль "Iteration\n" .константа len_msg = 10 ``` ---- +### Вычисление суммы чисел от 1 до 10 -## 5. Проверка исполняемого файла стандартными утилитами +```asm +.текст +.глобал _start -### 5.1. Запуск программы - -```bash -./<имя>.elf -``` - -### 5.2. Просмотр секций (`objdump -h`) - -```bash -objdump -h программа.elf -``` - -Вывод показывает размер, виртуальный адрес и атрибуты каждой секции. - -``` -Разделы: -Idx Name Разм VMA LMA Фа смещ. - 0 .text 00000232 0000000000401000 0000000000401000 00001000 - 1 .data 0000011c 0000000000402000 0000000000402000 00002000 -``` - -### 5.3. Дизассемблирование (`objdump -d`) +_start: + переместить_имм р8, 0 ; сумма + переместить_имм р9, 10 ; счётчик + +loop: + прибавить р8, р9 + уменьшить р9 + сравнить_с р9, 0 + переход_если_больше loop + + ; exit(сумма в r8) + переместить_имм раикс, 60 + переместить рдикс, р8 + вызов_системы +``` + +## 🐛 Отладка и проверка + +### Просмотр сгенерированного кода ```bash +# Дизассемблирование objdump -d программа.elf -``` -Показывает машинный код в виде ассемблерных инструкций x86-64. +# Просмотр секций +objdump -h программа.elf -```bash -# Ограничить вывод -objdump -d программа.elf | head -50 - -# Сохранить в файл -objdump -d программа.elf > код.asm -``` - -### 5.4. Просмотр заголовков программы (`readelf -l`) - -```bash +# Просмотр заголовков программы readelf -l программа.elf -``` -Показывает сегменты LOAD, их смещения, виртуальные адреса и права доступа. - -``` -Заголовки программы: - Тип Смещ. Вирт.адр Физ.адр Рзм.фйл Рзм.пм Флаги - LOAD 0x001000 0x401000 0x401000 0x232 0x1000 R E - LOAD 0x002000 0x402000 0x402000 0x11c 0x1000 RW -``` - -### 5.5. Проверка целостности ELF (`readelf -h`) - -```bash -readelf -h программа.elf -``` - -Выводит заголовок ELF-файла (магия, тип, архитектура, точка входа). - -### 5.6. Просмотр всех заголовков секций (`readelf -S`) - -```bash -readelf -S программа.elf -``` - -### 5.7. Сравнение двух ELF-файлов - -```bash -# Сравнить дизассемблированный код -diff <(objdump -d файл1.elf) <(objdump -d файл2.elf) - -# Сравнить заголовки секций -diff <(objdump -h файл1.elf) <(objdump -h файл2.elf) -``` - -### 5.8. Просмотр строк из секции `.data` - -```bash -# Извлечь строки из ELF +# Извлечение строк из ELF strings программа.elf - -# Показать шестнадцатеричный дамп секции .data -objdump -s -j .data программа.elf ``` -### 5.9. Трассировка системных вызовов +### CSV-лог + +После компиляции создаётся файл `программа.csv` со структурой: + +| адрес | байт | целевой_адрес | исходная_команда | +|-------|------|---------------|------------------| +| 0x401000 | 48 | | переместить_имм раикс, 1 | +| 0x401001 | B8 | | | +| 0x401002 | 01 | | | +| ... | ... | ... | ... | + +### Трассировка системных вызовов ```bash strace ./программа.elf ``` -Показывает все системные вызовы, выполняемые программой. - -### 5.10. Отладка с GDB +### Отладка с GDB ```bash gdb ./программа.elf ``` -В GDB: -``` +```gdb (gdb) break _start ; установить точку останова (gdb) run ; запустить (gdb) info registers ; показать регистры @@ -355,11 +350,9 @@ gdb ./программа.elf (gdb) stepi ; выполнить одну инструкцию ``` ---- +## ⚠️ Ограничения -## 6. Особенности и ограничения - -### 6.1. Поддерживаемые возможности +### Поддерживается - ✅ 64-битные, 32-битные, 16-битные и 8-битные регистры - ✅ Непосредственная загрузка констант (imm) в регистры @@ -368,51 +361,26 @@ gdb ./программа.elf - ✅ Арифметические операции (ADD, SUB, INC, DEC) - ✅ Логическая операция TEST - ✅ Системные вызовы Linux (syscall) -- ✅ Секции `.text` и `.data` +- ✅ Секции `.текст` и `.данные` - ✅ Строковые литералы с escape-последовательностями (`\n`, `\t`, `\\`, `\"`) - ✅ Директива `.байт` для raw-данных - ✅ Директива `.константа` для имён констант -### 6.2. Ограничения +### Не поддерживается -- ❌ Отсутствует поддержка косвенной адресации памяти `[reg+disp]` -- ❌ Нет инструкций для работы со стеком (PUSH, POP, CALL, RET) -- ❌ Нет поддержки плавающей запятой (FPU/SSE) -- ❌ Нет многомодульной компиляции -- ❌ Нет макросов +- ❌ Косвенная адресация памяти `[reg+disp]` (в разработке) +- ❌ Инструкции для работы со стеком (PUSH, POP, CALL, RET) +- ❌ Поддержка плавающей запятой (FPU/SSE) +- ❌ Многомодульная компиляция +- ❌ Макросы -### 6.3. Примечания +## 📄 Лицензия -- Все переходы используют абсолютные целевые адреса (метки преобразуются в адреса) -- Для длинных переходов генерируется 5-байтовая инструкция JMP или 6-байтовая Jcc -- Секция `.data` выравнивается на границу страницы (0x1000) после `.text` -- Точка входа по умолчанию — `_start` - ---- - -## 7. Сообщения об ошибках - -Компилятор выводит подробные сообщения об ошибках с указанием файла и строки: +Только для образовательных целей. Используйте на свой страх и риск. ``` -Ошибка в файле test.квс, строка 42: - переместить_имм аикс, 100000 -Неподдерживаемый размер регистра +КВС Ассемблер | Экспериментальный проект | 2025 +Только для образовательных целей. Используйте на свой страх и риск. ``` -Основные ошибки: - -| Сообщение | Причина | -|-----------|---------| -| `Неизвестная инструкция: '...'` | Неверное имя инструкции | -| `Недопустимый формат числа: '...'` | Неверный синтаксис числа | -| `Недопустимый регистр` | Регистр не найден в таблице | -| `Метка не найдена: '...'` | Использование неопределённой метки | -| `Цель слишком далеко для короткого перехода` | Смещение > 127 байт для условного перехода | -| `Незакрытая кавычка в строке` | Ошибка в синтаксисе строки | - ---- - -## 8. Заключение - -Компилятор КВС предоставляет возможность писать низкоуровневые программы на русскоязычном ассемблероподобном языке с последующей компиляцией в нативный 64-битный ELF-исполняемый файл. Декомпозированная архитектура компилятора облегчает понимание этапов трансляции и модификацию отдельных модулей. \ No newline at end of file +``` \ No newline at end of file