| доки | ||
| тесты | ||
| disassembler_skip_zero.py | ||
| elfreader.py | ||
| kvs_build.py | ||
| kvs_builder.py | ||
| kvs_data.py | ||
| kvs_lexer.py | ||
| kvs_parser.py | ||
| kvs_pass1.py | ||
| kvs_pass2.py | ||
| README.html | ||
| README.md | ||
| todo.txt | ||
Документация компилятора КВС
1. Общие сведения
КВС (язык программирования) — это низкоуровневый язык, транслируемый в 64-битный ELF-исполняемый файл для архитектуры x86-64. Компилятор написан на Python и состоит из нескольких модулей, выполняющих лексический анализ, синтаксический разбор, двухпроходную генерацию кода и сборку ELF-файла.
1.1. Состав компилятора
| Файл | Назначение |
|---|---|
kvs_8.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 |
Общие данные (регистры, инструкции, константы) |
1.2. Запуск компилятора
# Монолитная версия
python3 kvs_8.py <файл.квс>
# Декомпозированная версия
python3 kvs_build.py <файл.квс>
Входной файл должен иметь расширение .квс.
1.3. Результаты компиляции
| Файл | Содержимое |
|---|---|
<имя>.elf |
Исполняемый ELF-файл (64-bit) |
<имя>.log.csv |
Лог с адресами, байтами и соответствием командам |
<имя>.токены |
Промежуточный файл токенов (только для декомп. версии) |
<имя>.аст |
Промежуточный AST-файл (только для декомп. версии) |
<имя>.проход1 |
Данные первого прохода (только для декомп. версии) |
<имя>.csv |
CSV с машинным кодом (только для декомп. версии) |
2. Синтаксис языка КВС
2.1. Структура программы
Программа на КВС состоит из секций:
.текст ; секция кода (обязательна)
; ... инструкции ...
.данные ; секция данных (опциональна)
; ... данные ...
2.2. Метки
Метка — это имя, за которым следует двоеточие. Метки могут использоваться как цели переходов.
_start: ; метка _start
переместить_имм раикс, 1
переход _start ; переход на метку
2.3. Директивы
| Директива | Назначение | Пример |
|---|---|---|
.текст |
Начало секции кода | .текст |
.данные |
Начало секции данных | .данные |
.глобал |
Объявление глобальной метки (точки входа) | .глобал _start |
.строка |
Строка без завершающего нуля | .строка "Hello" |
.строка_нуль |
Строка с завершающим нулём | .строка_нуль "Hello" |
.байт |
Последовательность байтов | .байт 0x48, 0x65, 108 |
.константа |
Определение константы | .константа LEN = 10 |
2.4. Комментарии
Однострочные комментарии начинаются с ;:
; Это комментарий
переместить_имм раикс, 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. Инструкции
Загрузка констант
| Инструкция | Синтаксис | Описание |
|---|---|---|
переместить_имм |
переместить_имм рег, значение |
Загрузить константу в регистр |
переместить_имм раикс, 42 ; RAX = 42
переместить_имм еаикс, 0x7FFF ; EAX = 32767 (32-бит)
переместить_имм ал, 0xFF ; AL = 255 (8-бит)
Арифметика и логика
| Инструкция | Синтаксис | Описание |
|---|---|---|
прибавить |
прибавить рег1, рег2 |
рег1 += рег2 |
вычесть |
вычесть рег1, рег2 |
рег1 -= рег2 |
увеличить |
увеличить рег |
рег++ |
уменьшить |
уменьшить рег |
рег-- |
сравнить |
сравнить рег1, рег2 |
Сравнить два регистра (установка флагов) |
сравнить_с |
сравнить_с рег, значение |
Сравнить регистр с константой |
проверить |
проверить рег1, рег2 |
TEST — логическое AND (установка ZF) |
прибавить раикс, рбикс ; 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 |
переход_если_ноль |
переход_если_ноль метка |
ZF = 1 (синоним JE) |
переход_если_не_ноль |
переход_если_не_ноль метка |
ZF = 0 (синоним JNE) |
Короткие условные переходы (префикс короткий_):
короткий_переход_если_равно,короткий_переход_если_неравно, и т.д.- Генерируют 2-байтовые инструкции (смещение ±127 байт)
Системные вызовы
| Инструкция | Синтаксис | Описание |
|---|---|---|
вызов_системы |
вызов_системы |
Вызов ядра Linux (syscall) |
; Пример: вывод строки
переместить_имм раикс, 1 ; syscall 1 = write
переместить_имм рдиай, 1 ; stdout
переместить_имм рсиай, msg ; указатель на строку
переместить_имм рдикс, len ; длина строки
вызов_системы
; Пример: завершение программы
переместить_имм раикс, 60 ; syscall 60 = exit
переместить_имм рдиай, 0 ; код возврата 0
вызов_системы
Прочие инструкции
| Инструкция | Синтаксис | Описание |
|---|---|---|
нет_операции |
нет_операции |
NOP (0x90) |
4. Примеры программ
4.1. Hello World
.текст
.глобал _start
_start:
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, msg
переместить_имм рдикс, len_msg
вызов_системы
переместить_имм раикс, 60
переместить_имм рдиай, 0
вызов_системы
.данные
msg: .строка_нуль "Hello, World!\n"
.константа len_msg = 15
4.2. Цикл и условный переход
.текст
.глобал _start
_start:
переместить_имм рсикс, 10 ; счетчик = 10
loop:
; тело цикла
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, msg
переместить_имм рдикс, len_msg
вызов_системы
уменьшить рсикс ; счетчик--
сравнить_с рсикс, 0
переход_если_больше loop ; если > 0, продолжаем
переместить_имм раикс, 60
переместить_имм рдиай, 0
вызов_системы
.данные
msg: .строка_нуль "Iteration\n"
.константа len_msg = 10
5. Проверка исполняемого файла стандартными утилитами
5.1. Запуск программы
./<имя>.elf
5.2. Просмотр секций (objdump -h)
objdump -h программа.elf
Вывод показывает размер, виртуальный адрес и атрибуты каждой секции.
Разделы:
Idx Name Разм VMA LMA Фа смещ.
0 .text 00000232 0000000000401000 0000000000401000 00001000
1 .data 0000011c 0000000000402000 0000000000402000 00002000
5.3. Дизассемблирование (objdump -d)
objdump -d программа.elf
Показывает машинный код в виде ассемблерных инструкций x86-64.
# Ограничить вывод
objdump -d программа.elf | head -50
# Сохранить в файл
objdump -d программа.elf > код.asm
5.4. Просмотр заголовков программы (readelf -l)
readelf -l программа.elf
Показывает сегменты LOAD, их смещения, виртуальные адреса и права доступа.
Заголовки программы:
Тип Смещ. Вирт.адр Физ.адр Рзм.фйл Рзм.пм Флаги
LOAD 0x001000 0x401000 0x401000 0x232 0x1000 R E
LOAD 0x002000 0x402000 0x402000 0x11c 0x1000 RW
5.5. Проверка целостности ELF (readelf -h)
readelf -h программа.elf
Выводит заголовок ELF-файла (магия, тип, архитектура, точка входа).
5.6. Просмотр всех заголовков секций (readelf -S)
readelf -S программа.elf
5.7. Сравнение двух ELF-файлов
# Сравнить дизассемблированный код
diff <(objdump -d файл1.elf) <(objdump -d файл2.elf)
# Сравнить заголовки секций
diff <(objdump -h файл1.elf) <(objdump -h файл2.elf)
5.8. Просмотр строк из секции .data
# Извлечь строки из ELF
strings программа.elf
# Показать шестнадцатеричный дамп секции .data
objdump -s -j .data программа.elf
5.9. Трассировка системных вызовов
strace ./программа.elf
Показывает все системные вызовы, выполняемые программой.
5.10. Отладка с GDB
gdb ./программа.elf
В GDB:
(gdb) break _start ; установить точку останова
(gdb) run ; запустить
(gdb) info registers ; показать регистры
(gdb) x/10i $rip ; показать 10 инструкций
(gdb) stepi ; выполнить одну инструкцию
6. Особенности и ограничения
6.1. Поддерживаемые возможности
- ✅ 64-битные, 32-битные, 16-битные и 8-битные регистры
- ✅ Непосредственная загрузка констант (imm) в регистры
- ✅ Сравнение регистров и регистров с константами
- ✅ Условные и безусловные переходы (длинные и короткие)
- ✅ Арифметические операции (ADD, SUB, INC, DEC)
- ✅ Логическая операция TEST
- ✅ Системные вызовы Linux (syscall)
- ✅ Секции
.textи.data - ✅ Строковые литералы с escape-последовательностями (
\n,\t,\\,\") - ✅ Директива
.байтдля raw-данных - ✅ Директива
.константадля имён констант
6.2. Ограничения
- ❌ Отсутствует поддержка косвенной адресации памяти
[reg+disp] - ❌ Нет инструкций для работы со стеком (PUSH, POP, CALL, RET)
- ❌ Нет поддержки плавающей запятой (FPU/SSE)
- ❌ Нет многомодульной компиляции
- ❌ Нет макросов
6.3. Примечания
- Все переходы используют абсолютные целевые адреса (метки преобразуются в адреса)
- Для длинных переходов генерируется 5-байтовая инструкция JMP или 6-байтовая Jcc
- Секция
.dataвыравнивается на границу страницы (0x1000) после.text - Точка входа по умолчанию —
_start
7. Сообщения об ошибках
Компилятор выводит подробные сообщения об ошибках с указанием файла и строки:
Ошибка в файле test.квс, строка 42:
переместить_имм аикс, 100000
Неподдерживаемый размер регистра
Основные ошибки:
| Сообщение | Причина |
|---|---|
Неизвестная инструкция: '...' |
Неверное имя инструкции |
Недопустимый формат числа: '...' |
Неверный синтаксис числа |
Недопустимый регистр |
Регистр не найден в таблице |
Метка не найдена: '...' |
Использование неопределённой метки |
Цель слишком далеко для короткого перехода |
Смещение > 127 байт для условного перехода |
Незакрытая кавычка в строке |
Ошибка в синтаксисе строки |
8. Заключение
Компилятор КВС предоставляет возможность писать низкоуровневые программы на русскоязычном ассемблероподобном языке с последующей компиляцией в нативный 64-битный ELF-исполняемый файл. Декомпозированная архитектура компилятора облегчает понимание этапов трансляции и модификацию отдельных модулей.