╔══════════════════════════════════╗ ║ ██╗ ██╗ ██╗ ██╗ ███████╗ ║ ║ ██║ ██╔╝ ██╗ ██╗ ██╔════╝ ║ ║ █████╔╝ ██╗ ██╗ ███████╗ ║ ║ ██║╚██╗ ╚██╗ ██╔╝ ╚════██║ ║ ║ ██║ ╚██╗ ╚██╔╝ ███████║ ║ ║ ╚═╝ ╚═╝ ╚═╝ ╚══════╝ ║ ╚══════════════════════════════════╝
Версия 2.0 | Экспериментальный проект | 2025
✓ Абсолютная адресация реализована | ⟳ Косвенная адресация в разработке
КВС — это ассемблер для архитектуры x86-64, полностью использующий русскую лексику для мнемоник инструкций, имён регистров и директив. Проект носит образовательный и экспериментальный характер и демонстрирует принципы работы ассемблера, построения ELF-файлов и трансляции высокоуровневых концепций в машинный код.
переместить, прибавить, вызвать, регистры раикс, есипи, ал, директивы .текст, .данные.текст (код) и .данные (данные)[переменная] и абсолютным адресам [0x402000] с RIP-relative кодированием.csv с соответствием адресов, байтов и исходных командkvs_pass2_encoder.py| Файл | Назначение |
|---|---|
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 | Общие данные (регистры, инструкции) |
# Клонирование репозитория git clone https://github.com/username/kvs.git cd kvs # Установка прав на выполнение (при необходимости) chmod +x kvs_build.py # Компиляция программы python3 kvs_build.py программа.квс # Запуск скомпилированной программы ./программа.elf
; Комментарий начинается с точки с запятой
.данные ; Начало секции данных
переменная: .байт 0 ; Переменная в памяти
message: .строка_нуль "Привет, мир!"
.текст ; Начало секции кода
.глобал _start ; Точка входа
_start:
; Работа с памятью
переместить_имм раикс, 42
сохранить [переменная], раикс ; запись в память
загрузить рбикс, [переменная] ; чтение из памяти
; Системный вызов write
переместить_имм раикс, 1
загрузить_адрес рсиай, message
переместить_имм рдикс, 13
вызов_системы
; Выход с кодом из переменной
переместить_имм раикс, 60
загрузить рдиай, [переменная]
вызов_системы
| Категория | Примеры инструкций | Соответствие NASM |
|---|---|---|
| Перемещение данных | переместить, переместить_имм | mov, mov reg, imm |
| Работа с памятью | загрузить, сохранить, загрузить_адрес | mov reg, mem, mov mem, reg, lea |
| Арифметика | прибавить, вычесть, умножить, разделить, увеличить, уменьшить | add, sub, mul, div, inc, dec |
| Логические | и, или, исключающее_или, инвертировать, отрицать | and, or, xor, not, neg |
| Сравнение | сравнить, сравнить_с, проверить | cmp, test |
| Условные переходы | переход_если_равно, переход_если_больше, короткий_переход_если_равно | je, jg, je short |
| Безусловные переходы | переход, короткий_переход, вызвать, вернуться | jmp, jmp short, call, ret |
| Системные | вызов_системы, остановить | syscall, hlt |
| Синтаксис | Описание | Пример |
|---|---|---|
[метка] | Адрес метки (из .данные) | загрузить раикс, [переменная] |
[число] | Абсолютный адрес | сохранить [0x402000], раикс |
.данные
переменная: .байт 0
результат: .байт 0
.текст
_start:
; Запись значения
переместить_имм раикс, 42
сохранить [переменная], раикс
; Чтение значения
загрузить рбикс, [переменная]
; Завершение с кодом 42
переместить_имм раикс, 60
загрузить рдиай, [переменная]
вызов_системы
.данные имеет значение! Переменные, объявленные перед строковыми константами, могут затереть первые байты строк. Рекомендуется объявлять строки первыми, а изменяемые переменные — после.
| 64-битные | 32-битные | 16-битные | 8-битные (мл.) | 8-битные (ст.) |
|---|---|---|---|---|
раикс | еаикс | аикс | ал | аш |
рбикс | ебикс | бикс | бл | бш |
рсикс | есикс | сикс | кл | чш |
рдикс | едикс | дикс | дл | дш |
рсипи | есипи | эсп | спл | — |
рбипи | ебипи | бипи | бпл | — |
рсиай | есиай | эс | сил | — |
рдиай | едиай | ди | дил | — |
р8…р15 | р8д…р15д | р8в…р15в | р8б…р15б | — |
| Директива | Назначение | Пример |
|---|---|---|
.текст | Начало секции кода | .текст |
.данные | Начало секции данных | .данные |
.глобал | Объявление глобальной метки | .глобал _start |
.строка | Строка без нулевого терминатора | .строка "Hello" |
.строка_нуль | Строка с нулевым терминатором | .строка_нуль "Hello" |
.байт | Резервирование байтов | .байт 0x0A, 255, 0b0001 |
.константа | Определение константы | .константа SIZE = 100 |
.глобал _start
.текст
_start:
; write(1, msg, 13)
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, msg
переместить_имм рдикс, 13
вызов_системы
; exit(0)
переместить_имм раикс, 60
переместить_имм рдиай, 0
вызов_системы
.данные
msg: .строка_нуль "Hello, World!"
.глобал _start
.текст
_start:
; Запись 42 в переменную
переместить_имм раикс, 42
сохранить [переменная], раикс
; Завершение с кодом 42
переместить_имм раикс, 60
загрузить рдиай, [переменная]
вызов_системы
.данные
переменная: .байт 0
.глобал _start
.текст
_start:
переместить_имм р8, 0 ; сумма
переместить_имм р9, 10 ; счётчик
loop:
прибавить р8, р9
уменьшить р9
сравнить_с р9, 0
переход_если_больше loop
; exit(сумма в r8)
переместить_имм раикс, 60
переместить рдикс, р8
вызов_системы
Запуск ассемблера:
python3 kvs_build.py программа.квс
В результате создаются файлы:
программа.токены — результат лексического анализапрограмма.аст — AST-представлениепрограмма.проход1 — результаты первого прохода (размеры, метки)программа.csv — детальный лог с адресами, байтами и командамипрограмма.elf — исполняемый ELF-файл[, ], NUMBER[переменная]kvs_pass2_encoder.pyзагрузить_адрес (LEA) — только для чисел, не для меток[reg][reg + disp][reg + reg*scale][reg + reg*scale + disp].bss для неинициализированных данныхзагрузить_адрес reg, [метка])[, ], NUMBER[метка] и [число][reg] — косвенная адресация через регистр[reg + disp] — со смещением (disp8/disp32)[reg + reg*scale] — с индексным регистром[reg + reg*scale + disp] — полная SIB-адресация.bss — секция неинициализированных данныхmalloc, freestrlen, strcmp, memcpyputchar, getcharprintf (упрощённый вариант)[метка]; адресация через регистры [reg] в разработке[reg+disp], [reg+reg*scale], [reg+reg*scale+disp] не реализованызагрузить_адрес reg, [метка] не работает, используйте переместить_имм reg, метка.data (занимают место в файле)