упростить рассчет смещений
This commit is contained in:
parent
bb80efac8d
commit
84646f02c6
40
README.md
40
README.md
|
|
@ -23,14 +23,14 @@
|
||||||
|
|
||||||
- **Полностью русский синтаксис** — все инструкции, регистры и директивы на кириллице
|
- **Полностью русский синтаксис** — все инструкции, регистры и директивы на кириллице
|
||||||
- **Генерация исполняемых ELF-файлов** — 64-битные ELF для Linux, готовые к запуску
|
- **Генерация исполняемых ELF-файлов** — 64-битные ELF для Linux, готовые к запуску
|
||||||
- **Четырёхпроходная сборка** — традиционная схема с разрешением меток, констант и перекодированием
|
- **Четырёхпроходная сборка** — традиционная схема с разрешением меток, подстановкой констант и перекодированием
|
||||||
- **Поддержка секций** — разделение на `.текст` (код), `.данные` (данные) и `.бнд` (неинициализированные данные)
|
- **Поддержка секций** — разделение на `.текст` (код), `.данные` (данные) и `.бнд` (неинициализированные данные)
|
||||||
- **Гибкая адресация памяти**:
|
- **Гибкая адресация памяти**:
|
||||||
- абсолютная адресация по меткам `[переменная]`
|
- абсолютная адресация по меткам `[переменная]`
|
||||||
- абсолютная адресация по числовому адресу `[0x402000]`
|
- абсолютная адресация по числовому адресу `[0x402000]`
|
||||||
- косвенная адресация через регистр `[раикс]`
|
- косвенная адресация через регистр `[раикс]`
|
||||||
- всё с RIP-relative кодированием для 64-битных перемещений
|
- всё с RIP-relative кодированием для 64-битных перемещений
|
||||||
- **CSV-логирование** — детальный файл с соответствием адресов, байтов и исходных команд
|
- **CSV-логирование** — детальный файл с соответствием адресов, байтов, меток и исходных команд
|
||||||
- **Более 50 инструкций** — полный набор основных команд x86-64
|
- **Более 50 инструкций** — полный набор основных команд x86-64
|
||||||
- **Минимализм зависимостей** — только стандартная библиотека Python
|
- **Минимализм зависимостей** — только стандартная библиотека Python
|
||||||
|
|
||||||
|
|
@ -48,9 +48,9 @@
|
||||||
AST-представление (.аст)
|
AST-представление (.аст)
|
||||||
│
|
│
|
||||||
▼ (kvs_pass1.py) ← ПРОХОД 1: генерация CSV с заглушками (0xCC)
|
▼ (kvs_pass1.py) ← ПРОХОД 1: генерация CSV с заглушками (0xCC)
|
||||||
CSV-файл (.csv) ← содержит все байты программы, метки, заглушки
|
CSV-файл (.csv) ← содержит все байты программы, метки, виртуальные адреса
|
||||||
│
|
│
|
||||||
▼ (kvs_pass2.py) ← ПРОХОД 2: разрешение меток (замена заглушек)
|
▼ (kvs_pass2.py) ← ПРОХОД 2: разрешение меток
|
||||||
│
|
│
|
||||||
▼ (kvs_pass3.py) ← ПРОХОД 3: подстановка констант (.константа)
|
▼ (kvs_pass3.py) ← ПРОХОД 3: подстановка констант (.константа)
|
||||||
│
|
│
|
||||||
|
|
@ -68,24 +68,24 @@ ELF-файл (.elf)
|
||||||
| Файл | Назначение |
|
| Файл | Назначение |
|
||||||
|------|-------------|
|
|------|-------------|
|
||||||
| `kvs_build.py` | Главный сборочный скрипт (запускает все этапы по порядку) |
|
| `kvs_build.py` | Главный сборочный скрипт (запускает все этапы по порядку) |
|
||||||
| `kvs_lexer.py` | Лексический анализ, разбор на токены (с поддержкой `[]`, `+`, `-`, `*`) |
|
| `kvs_lexer.py` | Лексический анализ, разбор на токены (поддерживает `[]`, `+`, `-`, `*`) |
|
||||||
| `kvs_parser.py` | Синтаксический анализ, построение AST (директивы, метки, инструкции) |
|
| `kvs_parser.py` | Синтаксический анализ, построение AST (директивы, метки, инструкции) |
|
||||||
| `kvs_data.py` | Общие данные: регистры, таблица инструкций, вспомогательные функции |
|
| `kvs_data.py` | Общие данные: регистры, таблица инструкций, вспомогательные функции |
|
||||||
| `kvs_encoder.py` | Фасад кодировщика (реэкспорт из fixsize + mutsize) |
|
| `kvs_encoder.py` | Фасад кодировщика (объединяет fixsize и mutsize) |
|
||||||
| `kvs_encoder_fixsize.py` | Кодировщик инструкций фиксированного размера |
|
| `kvs_encoder_fixsize.py` | Кодировщик инструкций фиксированного размера |
|
||||||
| `kvs_encoder_mutsize.py` | Кодировщик инструкций переменного размера + диспетчер |
|
| `kvs_encoder_mutsize.py` | Кодировщик инструкций переменного размера + диспетчер |
|
||||||
| `kvs_pass1.py` | Первый проход — вычисление размеров секций, адресов меток, генерация CSV с заглушками |
|
| `kvs_pass1.py` | Первый проход — генерация CSV с заглушками для неизвестных меток |
|
||||||
| `kvs_pass2.py` | Второй проход — разрешение меток |
|
| `kvs_pass2.py` | Второй проход — разрешение меток (замена заглушек на реальные адреса) |
|
||||||
| `kvs_pass3.py` | Третий проход — подстановка констант |
|
| `kvs_pass3.py` | Третий проход — подстановка констант из директив `.константа` |
|
||||||
| `kvs_pass4.py` | Четвёртый проход — перекодирование инструкций |
|
| `kvs_pass4.py` | Четвёртый проход — перекодирование инструкций с подставленными значениями |
|
||||||
| `kvs_builder.py` | Сборка ELF: чтение CSV, заполнение байтов по адресам, установка прав на исполнение |
|
| `kvs_builder.py` | Сборка ELF: чтение CSV, заполнение байтов по адресам, установка прав на исполнение |
|
||||||
|
|
||||||
### Почему 4 прохода?
|
### Почему 4 прохода?
|
||||||
|
|
||||||
1. **Первый проход** — неизвестно, какие адреса будут у меток (метка может использоваться до определения). Вместо остановки ставим заглушки `0xCC` и продолжаем.
|
1. **Первый проход** — неизвестно, какие адреса будут у меток (метка может использоваться до определения). Вместо остановки ставим заглушки `0xCC` и продолжаем.
|
||||||
2. **Второй проход** — после того как все адреса меток известны, можно заменить заглушки на реальные значения.
|
2. **Второй проход** — после того как все адреса меток известны, заменяем заглушки на реальные значения.
|
||||||
3. **Третий проход** — константы могут ссылаться друг на друга и на метки, поэтому их подстановка делается отдельно.
|
3. **Третий проход** — константы могут ссылаться друг на друга и на метки, поэтому их подстановка делается отдельно.
|
||||||
4. **Четвёртый проход** — после подстановки чисел адреса/констант нужно перегенерировать машинный код (разные операнды могут менять длину инструкции).
|
4. **Четвёртый проход** — после подстановки чисел (адресов/констант) нужно перегенерировать машинный код, так как разные операнды могут менять длину инструкции.
|
||||||
|
|
||||||
### Структура CSV-файла
|
### Структура CSV-файла
|
||||||
|
|
||||||
|
|
@ -93,6 +93,7 @@ ELF-файл (.elf)
|
||||||
|---------|-------------|
|
|---------|-------------|
|
||||||
| `сегмент` | Имя секции (`.header`, `.text`, `.data`, `.bss`) |
|
| `сегмент` | Имя секции (`.header`, `.text`, `.data`, `.bss`) |
|
||||||
| `адрес` | Файловое смещение байта |
|
| `адрес` | Файловое смещение байта |
|
||||||
|
| `виртуальный_адрес` | Виртуальный адрес байта в памяти (для вычисления смещений) |
|
||||||
| `байт` | Исходное значение байта (из pass1) |
|
| `байт` | Исходное значение байта (из pass1) |
|
||||||
| `приводящая_метка` | Имена меток, находящихся на этом адресе (через запятую) |
|
| `приводящая_метка` | Имена меток, находящихся на этом адресе (через запятую) |
|
||||||
| `уводящий_адрес` | Строка `ЗАГЛУШКА имя` для неразрешённых меток |
|
| `уводящий_адрес` | Строка `ЗАГЛУШКА имя` для неразрешённых меток |
|
||||||
|
|
@ -475,12 +476,11 @@ strings программа.elf
|
||||||
|
|
||||||
После компиляции создаётся файл `программа.csv` со структурой:
|
После компиляции создаётся файл `программа.csv` со структурой:
|
||||||
|
|
||||||
| адрес | байт | целевой_адрес | исходная_команда |
|
| адрес | виртуальный_адрес | байт | приводящая_метка | исходная_команда |
|
||||||
|-------|------|---------------|------------------|
|
|-------|-------------------|------|------------------|------------------|
|
||||||
| 0x401000 | 48 | | переместить_имм раикс, 1 |
|
| 0x1000 | 0x401000 | 48 | _start | переместить_имм раикс, 10 |
|
||||||
| 0x401001 | B8 | | |
|
| 0x1001 | 0x401001 | B8 | | |
|
||||||
| 0x401002 | 01 | | |
|
| ... | ... | ... | ... | ... |
|
||||||
| ... | ... | ... | ... |
|
|
||||||
|
|
||||||
### Трассировка системных вызовов
|
### Трассировка системных вызовов
|
||||||
|
|
||||||
|
|
@ -524,7 +524,6 @@ gdb ./программа.elf
|
||||||
|
|
||||||
- Адресация со смещением `[reg + disp]`
|
- Адресация со смещением `[reg + disp]`
|
||||||
- Сложная адресация с индексом `[reg + reg*scale]` и полная SIB-адресация
|
- Сложная адресация с индексом `[reg + reg*scale]` и полная SIB-адресация
|
||||||
- Инструкции для работы со стеком (PUSH, POP, CALL, RET) — кроме базовых PUSH/POP reg
|
|
||||||
- Поддержка плавающей запятой (FPU/SSE)
|
- Поддержка плавающей запятой (FPU/SSE)
|
||||||
- Многомодульная компиляция
|
- Многомодульная компиляция
|
||||||
- Макросы
|
- Макросы
|
||||||
|
|
@ -544,7 +543,8 @@ gdb ./программа.elf
|
||||||
- Поддержка числовых адресов `[0x402000]`
|
- Поддержка числовых адресов `[0x402000]`
|
||||||
- Поддержка косвенной адресации `[регистр]`
|
- Поддержка косвенной адресации `[регистр]`
|
||||||
- Секция `.бнд` для неинициализированных данных
|
- Секция `.бнд` для неинициализированных данных
|
||||||
- Рефакторинг: выделение кодировщика в отдельный модуль
|
- Вынесение кодировщика в отдельный модуль
|
||||||
|
- Колонка `виртуальный_адрес` в CSV для точного вычисления смещений
|
||||||
|
|
||||||
### В планах (v3.0)
|
### В планах (v3.0)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,6 @@ if __name__ == "__main__":
|
||||||
("kvs_pass2.py", [csv_file], "2 проход"),
|
("kvs_pass2.py", [csv_file], "2 проход"),
|
||||||
("kvs_pass3.py", [ast_file, csv_file], "3 проход"),
|
("kvs_pass3.py", [ast_file, csv_file], "3 проход"),
|
||||||
("kvs_pass4.py", [csv_file], "4 проход"),
|
("kvs_pass4.py", [csv_file], "4 проход"),
|
||||||
#("kvs_pass2.py", [csv_file], "Второй проход: разрешение меток"),
|
|
||||||
("kvs_builder.py", [csv_file, elf_file], "Сборка ELF"),
|
("kvs_builder.py", [csv_file, elf_file], "Сборка ELF"),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
311
kvs_pass1.py
311
kvs_pass1.py
|
|
@ -6,8 +6,9 @@
|
||||||
Генерирует CSV-таблицу напрямую из AST
|
Генерирует CSV-таблицу напрямую из AST
|
||||||
- Неизвестные метки заменяются заглушками (0xCC) с пометкой в колонке 'уводящий_адрес'
|
- Неизвестные метки заменяются заглушками (0xCC) с пометкой в колонке 'уводящий_адрес'
|
||||||
- В колонке 'приводящая_метка' записываются имена меток, находящихся по данному адресу (через запятую)
|
- В колонке 'приводящая_метка' записываются имена меток, находящихся по данному адресу (через запятую)
|
||||||
- Колонка 'команда_со_значениями' оставлена пустой (для возможного расширения)
|
- Колонка 'команда_со_значениями' оставлена пустой (для второго прохода)
|
||||||
- Колонки 'рассчитанный_уводящий_адрес' и 'рассчитанный_байт' оставлены для второго прохода
|
- Колонки 'рассчитанный_уводящий_адрес' и 'рассчитанный_байт' оставлены для второго прохода
|
||||||
|
- Колонка 'виртуальный_адрес' содержит виртуальный адрес байта (для pass4)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
@ -18,7 +19,7 @@ from kvs_data import PAGE_SIZE, text_vaddr_base, align_up
|
||||||
from kvs_encoder import encode_instruction
|
from kvs_encoder import encode_instruction
|
||||||
|
|
||||||
# ========== ГЛОБАЛЬНОЕ СОСТОЯНИЕ ==========
|
# ========== ГЛОБАЛЬНОЕ СОСТОЯНИЕ ==========
|
||||||
entries = [] # (segment, address, byte, target, source, label, source_with_values, calc_target, calc_byte)
|
entries = [] # (segment, address, virt_addr, byte, target, source, label, cmd_with_values, calc_target, calc_byte)
|
||||||
current_address = 0
|
current_address = 0
|
||||||
current_segment = '.header'
|
current_segment = '.header'
|
||||||
last_segment = None
|
last_segment = None
|
||||||
|
|
@ -31,12 +32,11 @@ text_buffer = bytearray()
|
||||||
data_buffer = bytearray()
|
data_buffer = bytearray()
|
||||||
bnd_size = 0
|
bnd_size = 0
|
||||||
|
|
||||||
labels = {} # имя метки -> адрес
|
labels = {}
|
||||||
label_sections = {} # имя метки -> секция
|
label_sections = {}
|
||||||
symbols = {} # имя константы -> значение
|
symbols = {}
|
||||||
|
|
||||||
# Для сбора нескольких меток на один адрес
|
pending_labels = []
|
||||||
pending_labels = [] # список имён меток, ожидающих привязки к следующему байту
|
|
||||||
|
|
||||||
text_pos = 0
|
text_pos = 0
|
||||||
data_pos = 0
|
data_pos = 0
|
||||||
|
|
@ -44,6 +44,34 @@ data_pos = 0
|
||||||
entry_point = "_start"
|
entry_point = "_start"
|
||||||
relocations = []
|
relocations = []
|
||||||
|
|
||||||
|
# Список инструкций, которые всегда должны получать заглушки в первом проходе
|
||||||
|
ALWAYS_STUB_INSTRUCTIONS = {
|
||||||
|
"переход",
|
||||||
|
"короткий_переход",
|
||||||
|
"вызвать",
|
||||||
|
"цикл",
|
||||||
|
"переход_если_равно",
|
||||||
|
"переход_если_неравно",
|
||||||
|
"переход_если_меньше",
|
||||||
|
"переход_если_больше",
|
||||||
|
"переход_если_меньше_или_равно",
|
||||||
|
"переход_если_больше_или_равно",
|
||||||
|
"переход_если_перенос",
|
||||||
|
"переход_если_нет_переноса",
|
||||||
|
"переход_если_ноль",
|
||||||
|
"переход_если_не_ноль",
|
||||||
|
"короткий_переход_если_равно",
|
||||||
|
"короткий_переход_если_неравно",
|
||||||
|
"короткий_переход_если_меньше",
|
||||||
|
"короткий_переход_если_больше",
|
||||||
|
"короткий_переход_если_меньше_или_равно",
|
||||||
|
"короткий_переход_если_больше_или_равно",
|
||||||
|
"короткий_переход_если_перенос",
|
||||||
|
"короткий_переход_если_нет_переноса",
|
||||||
|
"короткий_переход_если_ноль",
|
||||||
|
"короткий_переход_если_не_ноль",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def reset_state():
|
def reset_state():
|
||||||
global entries, current_address, current_segment, last_segment
|
global entries, current_address, current_segment, last_segment
|
||||||
|
|
@ -75,11 +103,21 @@ def set_segment(segment: str):
|
||||||
current_segment = segment
|
current_segment = segment
|
||||||
|
|
||||||
|
|
||||||
|
def get_virtual_address():
|
||||||
|
"""Возвращает виртуальный адрес для текущей позиции"""
|
||||||
|
if current_segment == '.text':
|
||||||
|
return vaddr_text + (current_address - 0x1000)
|
||||||
|
elif current_segment == '.data':
|
||||||
|
if vaddr_data is None:
|
||||||
|
return current_address
|
||||||
|
return vaddr_data + (current_address - 0x2000)
|
||||||
|
else:
|
||||||
|
return current_address
|
||||||
|
|
||||||
|
|
||||||
def add_byte(value: int, source: str = "", target=None, labels_list=None):
|
def add_byte(value: int, source: str = "", target=None, labels_list=None):
|
||||||
"""Добавить один байт в текущую позицию"""
|
|
||||||
global current_address, last_segment, pending_labels
|
global current_address, last_segment, pending_labels
|
||||||
|
|
||||||
# Если есть отложенные метки, объединяем их через запятую
|
|
||||||
effective_labels = ""
|
effective_labels = ""
|
||||||
if labels_list is not None and labels_list:
|
if labels_list is not None and labels_list:
|
||||||
effective_labels = ','.join(labels_list)
|
effective_labels = ','.join(labels_list)
|
||||||
|
|
@ -90,20 +128,23 @@ def add_byte(value: int, source: str = "", target=None, labels_list=None):
|
||||||
if show_segment:
|
if show_segment:
|
||||||
last_segment = current_segment
|
last_segment = current_segment
|
||||||
|
|
||||||
|
virt_addr = get_virtual_address()
|
||||||
|
byte_val = value & 0xFF
|
||||||
|
|
||||||
entries.append((
|
entries.append((
|
||||||
show_segment if show_segment else "", # segment
|
show_segment if show_segment else "",
|
||||||
current_address, # address
|
current_address,
|
||||||
value & 0xFF, # byte
|
f"0x{virt_addr:08x}", # виртуальный_адрес
|
||||||
target if target else "", # target (уводящий_адрес)
|
f"0x{byte_val:02x}", # байт (в виде hex-строки)
|
||||||
source, # source (исходная_команда)
|
target if target else "",
|
||||||
effective_labels, # label (приводящая_метка) - несколько через запятую
|
source,
|
||||||
"", # source_with_values (команда_со_значениями) - всегда пусто
|
effective_labels,
|
||||||
"", # calc_target
|
"", # команда_со_значениями (заполняется во втором проходе)
|
||||||
"" # calc_byte
|
"", # рассчитанный_уводящий_адрес
|
||||||
|
f"0x{byte_val:02x}" # рассчитанный_байт (изначально = байт)
|
||||||
))
|
))
|
||||||
current_address += 1
|
current_address += 1
|
||||||
|
|
||||||
# После добавления байта сбрасываем отложенные метки
|
|
||||||
if pending_labels:
|
if pending_labels:
|
||||||
pending_labels = []
|
pending_labels = []
|
||||||
|
|
||||||
|
|
@ -114,7 +155,6 @@ def add_bytes(values, source: str = "", target=None):
|
||||||
|
|
||||||
|
|
||||||
def add_word16(value: int, source: str = "", target=None):
|
def add_word16(value: int, source: str = "", target=None):
|
||||||
"""Добавить 16-битное слово (little-endian)"""
|
|
||||||
add_bytes([
|
add_bytes([
|
||||||
(value >> 0) & 0xFF,
|
(value >> 0) & 0xFF,
|
||||||
(value >> 8) & 0xFF,
|
(value >> 8) & 0xFF,
|
||||||
|
|
@ -122,7 +162,6 @@ def add_word16(value: int, source: str = "", target=None):
|
||||||
|
|
||||||
|
|
||||||
def add_word32(value: int, source: str = "", target=None):
|
def add_word32(value: int, source: str = "", target=None):
|
||||||
"""Добавить 32-битное слово (little-endian)"""
|
|
||||||
add_bytes([
|
add_bytes([
|
||||||
(value >> 0) & 0xFF,
|
(value >> 0) & 0xFF,
|
||||||
(value >> 8) & 0xFF,
|
(value >> 8) & 0xFF,
|
||||||
|
|
@ -132,7 +171,6 @@ def add_word32(value: int, source: str = "", target=None):
|
||||||
|
|
||||||
|
|
||||||
def add_word64(value: int, source: str = "", target=None):
|
def add_word64(value: int, source: str = "", target=None):
|
||||||
"""Добавить 64-битное слово (little-endian)"""
|
|
||||||
add_bytes([
|
add_bytes([
|
||||||
(value >> 0) & 0xFF,
|
(value >> 0) & 0xFF,
|
||||||
(value >> 8) & 0xFF,
|
(value >> 8) & 0xFF,
|
||||||
|
|
@ -174,48 +212,29 @@ def unescape_string(s):
|
||||||
|
|
||||||
|
|
||||||
def generate_elf_header():
|
def generate_elf_header():
|
||||||
# EI_MAGIC
|
|
||||||
add_bytes([0x7F, 0x45, 0x4C, 0x46], "ELF magic")
|
add_bytes([0x7F, 0x45, 0x4C, 0x46], "ELF magic")
|
||||||
# EI_CLASS, EI_DATA, EI_VERSION
|
|
||||||
add_byte(2, "ELFCLASS64")
|
add_byte(2, "ELFCLASS64")
|
||||||
add_byte(1, "ELFDATA2LSB")
|
add_byte(1, "ELFDATA2LSB")
|
||||||
add_byte(1, "ELF version")
|
add_byte(1, "ELF version")
|
||||||
# EI_OSABI, EI_ABIVERSION
|
|
||||||
add_byte(0, "OS ABI")
|
add_byte(0, "OS ABI")
|
||||||
add_byte(0, "ABI version")
|
add_byte(0, "ABI version")
|
||||||
# EI_PAD
|
|
||||||
add_bytes([0] * 7, "Padding")
|
add_bytes([0] * 7, "Padding")
|
||||||
|
|
||||||
# e_type (2 байта)
|
|
||||||
add_word16(2, "e_type = ET_EXEC")
|
add_word16(2, "e_type = ET_EXEC")
|
||||||
# e_machine (2 байта)
|
|
||||||
add_word16(62, "e_machine = EM_X86_64")
|
add_word16(62, "e_machine = EM_X86_64")
|
||||||
# e_version (4 байта)
|
|
||||||
add_word32(1, "e_version")
|
add_word32(1, "e_version")
|
||||||
# e_entry (8 байт, заглушка)
|
|
||||||
add_word64(0, "e_entry (stub)")
|
add_word64(0, "e_entry (stub)")
|
||||||
# e_phoff (8 байт)
|
|
||||||
add_word64(64, "e_phoff")
|
add_word64(64, "e_phoff")
|
||||||
# e_shoff (8 байт)
|
|
||||||
add_word64(0, "e_shoff = 0")
|
add_word64(0, "e_shoff = 0")
|
||||||
# e_flags (4 байта)
|
|
||||||
add_word32(0, "e_flags")
|
add_word32(0, "e_flags")
|
||||||
# e_ehsize (2 байта)
|
|
||||||
add_word16(64, "e_ehsize")
|
add_word16(64, "e_ehsize")
|
||||||
# e_phentsize (2 байта)
|
|
||||||
add_word16(56, "e_phentsize")
|
add_word16(56, "e_phentsize")
|
||||||
# e_phnum (2 байта)
|
|
||||||
add_word16(2, "e_phnum = 2")
|
add_word16(2, "e_phnum = 2")
|
||||||
# e_shentsize (2 байта)
|
|
||||||
add_word16(0, "e_shentsize = 0")
|
add_word16(0, "e_shentsize = 0")
|
||||||
# e_shnum (2 байта)
|
|
||||||
add_word16(0, "e_shnum = 0")
|
add_word16(0, "e_shnum = 0")
|
||||||
# e_shstrndx (2 байта)
|
|
||||||
add_word16(0, "e_shstrndx")
|
add_word16(0, "e_shstrndx")
|
||||||
|
|
||||||
|
|
||||||
def generate_program_headers():
|
def generate_program_headers():
|
||||||
# Program Header 1: TEXT (RX)
|
|
||||||
add_word32(1, "p_type = PT_LOAD")
|
add_word32(1, "p_type = PT_LOAD")
|
||||||
add_word32(5, "p_flags = RX")
|
add_word32(5, "p_flags = RX")
|
||||||
add_word64(0, "p_offset (text stub)")
|
add_word64(0, "p_offset (text stub)")
|
||||||
|
|
@ -225,7 +244,6 @@ def generate_program_headers():
|
||||||
add_word64(0, "p_memsz (text stub)")
|
add_word64(0, "p_memsz (text stub)")
|
||||||
add_word64(PAGE_SIZE, "p_align")
|
add_word64(PAGE_SIZE, "p_align")
|
||||||
|
|
||||||
# Program Header 2: DATA (RW)
|
|
||||||
add_word32(1, "p_type = PT_LOAD")
|
add_word32(1, "p_type = PT_LOAD")
|
||||||
add_word32(6, "p_flags = RW")
|
add_word32(6, "p_flags = RW")
|
||||||
add_word64(0, "p_offset (data stub)")
|
add_word64(0, "p_offset (data stub)")
|
||||||
|
|
@ -258,7 +276,6 @@ def parse_ast_line(line):
|
||||||
mnemonic = line[first + 1:second]
|
mnemonic = line[first + 1:second]
|
||||||
section = line[second + 1:third]
|
section = line[second + 1:third]
|
||||||
operands_str = line[third + 1:]
|
operands_str = line[third + 1:]
|
||||||
|
|
||||||
operands = operands_str.split(',') if operands_str else []
|
operands = operands_str.split(',') if operands_str else []
|
||||||
|
|
||||||
return "INSTR", {
|
return "INSTR", {
|
||||||
|
|
@ -313,7 +330,17 @@ def parse_ast_line(line):
|
||||||
|
|
||||||
|
|
||||||
def get_stub_size(mnemonic, operands):
|
def get_stub_size(mnemonic, operands):
|
||||||
if mnemonic == "переместить_имм" and len(operands) >= 2:
|
if mnemonic in ("переход", "вызвать"):
|
||||||
|
return 5
|
||||||
|
elif mnemonic == "короткий_переход":
|
||||||
|
return 2
|
||||||
|
elif mnemonic.startswith("переход_если") and not mnemonic.startswith("короткий"):
|
||||||
|
return 6
|
||||||
|
elif mnemonic.startswith("короткий_переход_если"):
|
||||||
|
return 2
|
||||||
|
elif mnemonic == "цикл":
|
||||||
|
return 2
|
||||||
|
elif mnemonic == "переместить_имм" and len(operands) >= 2:
|
||||||
reg = operands[0]
|
reg = operands[0]
|
||||||
if reg in ('раикс', 'рбикс', 'рсикс', 'рдикс', 'рсипи', 'рбипи', 'рсиай', 'рдиай',
|
if reg in ('раикс', 'рбикс', 'рсикс', 'рдикс', 'рсипи', 'рбипи', 'рсиай', 'рдиай',
|
||||||
'р8', 'р9', 'р10', 'р11', 'р12', 'р13', 'р14', 'р15'):
|
'р8', 'р9', 'р10', 'р11', 'р12', 'р13', 'р14', 'р15'):
|
||||||
|
|
@ -322,46 +349,88 @@ def get_stub_size(mnemonic, operands):
|
||||||
return 7
|
return 7
|
||||||
else:
|
else:
|
||||||
return 2
|
return 2
|
||||||
elif mnemonic in ("переход", "вызвать"):
|
|
||||||
return 5
|
|
||||||
elif mnemonic.startswith("короткий_переход"):
|
|
||||||
return 2
|
|
||||||
elif mnemonic.startswith("переход_если"):
|
|
||||||
return 6
|
|
||||||
elif mnemonic.startswith("короткий_переход_если"):
|
|
||||||
return 2
|
|
||||||
elif mnemonic in ("загрузить", "сохранить", "загрузить_адрес"):
|
elif mnemonic in ("загрузить", "сохранить", "загрузить_адрес"):
|
||||||
return 7
|
return 7
|
||||||
|
elif mnemonic == "сравнить_с":
|
||||||
|
return 7
|
||||||
|
elif mnemonic in ("прибавить_непосредственно", "вычесть_непосредственно"):
|
||||||
|
return 7
|
||||||
|
elif mnemonic in ("переместить_с_нулями", "переместить_со_знаком"):
|
||||||
|
return 7
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
|
||||||
def has_unresolved_labels(operands):
|
def extract_label_from_operands(operands):
|
||||||
|
"""Извлекает первую метку из операндов инструкции"""
|
||||||
|
for op in operands:
|
||||||
|
if not op:
|
||||||
|
continue
|
||||||
|
# Пропускаем регистры
|
||||||
|
if op in ('раикс', 'рбикс', 'рсикс', 'рдикс', 'рсипи', 'рбипи', 'рсиай', 'рдиай',
|
||||||
|
'еаикс', 'ебикс', 'есикс', 'едикс',
|
||||||
|
'аикс', 'бикс', 'сикс', 'дикс',
|
||||||
|
'ал', 'бл', 'кл', 'дл',
|
||||||
|
'р8', 'р9', 'р10', 'р11', 'р12', 'р13', 'р14', 'р15'):
|
||||||
|
continue
|
||||||
|
# Пропускаем числа
|
||||||
|
if op.isdigit() or (op.startswith('0x') and len(op) > 2):
|
||||||
|
continue
|
||||||
|
# Пропускаем косвенную адресацию через регистр
|
||||||
|
if op.startswith('MEM:reg_indirect:'):
|
||||||
|
continue
|
||||||
|
# Извлекаем метку из [метка]
|
||||||
|
if op.startswith('[') and op.endswith(']'):
|
||||||
|
inner = op[1:-1]
|
||||||
|
if inner not in ('раикс', 'рбикс', 'рсикс', 'рдикс', 'рсипи', 'рбипи', 'рсиай', 'рдиай'):
|
||||||
|
if not inner.isdigit() and not inner.startswith('0x'):
|
||||||
|
return inner
|
||||||
|
# Обычная метка
|
||||||
|
elif op not in symbols:
|
||||||
|
return op
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def has_unresolved_labels(operands, mnemonic=""):
|
||||||
|
if mnemonic in ALWAYS_STUB_INSTRUCTIONS:
|
||||||
|
for op in operands:
|
||||||
|
if op and not op.isdigit() and not op.startswith('0x'):
|
||||||
|
if op not in ('раикс', 'рбикс', 'рсикс', 'рдикс', 'рсипи', 'рбипи', 'рсиай', 'рдиай',
|
||||||
|
'еаикс', 'ебикс', 'есикс', 'едикс',
|
||||||
|
'аикс', 'бикс', 'сикс', 'дикс',
|
||||||
|
'ал', 'бл', 'кл', 'дл'):
|
||||||
|
return True
|
||||||
|
|
||||||
for op in operands:
|
for op in operands:
|
||||||
if not op:
|
if not op:
|
||||||
continue
|
continue
|
||||||
if op in ('раикс', 'рбикс', 'рсикс', 'рдикс', 'рсипи', 'рбипи', 'рсиай', 'рдиай',
|
if op in ('раикс', 'рбикс', 'рсикс', 'рдикс', 'рсипи', 'рбипи', 'рсиай', 'рдиай',
|
||||||
'р8', 'р9', 'р10', 'р11', 'р12', 'р13', 'р14', 'р15',
|
|
||||||
'еаикс', 'ебикс', 'есикс', 'едикс',
|
'еаикс', 'ебикс', 'есикс', 'едикс',
|
||||||
'аикс', 'бикс', 'сикс', 'дикс',
|
'аикс', 'бикс', 'сикс', 'дикс',
|
||||||
'ал', 'бл', 'кл', 'дл'):
|
'ал', 'бл', 'кл', 'дл',
|
||||||
|
'р8', 'р9', 'р10', 'р11', 'р12', 'р13', 'р14', 'р15',
|
||||||
|
'р8д', 'р9д', 'р10д', 'р11д', 'р12д', 'р13д', 'р14д', 'р15д',
|
||||||
|
'р8в', 'р9в', 'р10в', 'р11в', 'р12в', 'р13в', 'р14в', 'р15в',
|
||||||
|
'р8б', 'р9б', 'р10б', 'р11б', 'р12б', 'р13б', 'р14б', 'р15б',
|
||||||
|
'спл', 'бпл', 'сил', 'дил'):
|
||||||
|
continue
|
||||||
|
if op.startswith('MEM:reg_indirect:'):
|
||||||
continue
|
continue
|
||||||
if op.startswith('[') and op.endswith(']'):
|
if op.startswith('[') and op.endswith(']'):
|
||||||
inner = op[1:-1]
|
inner = op[1:-1]
|
||||||
if inner in ('раикс', 'рбикс', 'рсикс', 'рдикс', 'рсипи', 'рбипи', 'рсиай', 'рдиай'):
|
if inner in ('раикс', 'рбикс', 'рсикс', 'рдикс', 'рсипи', 'рбипи', 'рсиай', 'рдиай'):
|
||||||
continue
|
continue
|
||||||
if inner in labels:
|
if inner.isdigit() or (inner.startswith('0x') and len(inner) > 2):
|
||||||
continue
|
|
||||||
if inner.isdigit() or (inner.startswith('0x')):
|
|
||||||
continue
|
continue
|
||||||
|
if inner not in labels:
|
||||||
return True
|
return True
|
||||||
elif op in labels:
|
|
||||||
continue
|
continue
|
||||||
elif op.isdigit() or (op.startswith('0x')):
|
if op.isdigit() or (op.startswith('0x') and len(op) > 2):
|
||||||
continue
|
continue
|
||||||
else:
|
|
||||||
if op in symbols:
|
if op in symbols:
|
||||||
continue
|
continue
|
||||||
|
if op not in labels:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -380,7 +449,8 @@ def get_unresolved_labels(operands):
|
||||||
if op not in ('раикс', 'рбикс', 'рсикс', 'рдикс', 'рсипи', 'рбипи', 'рсиай', 'рдиай',
|
if op not in ('раикс', 'рбикс', 'рсикс', 'рдикс', 'рсипи', 'рбипи', 'рсиай', 'рдиай',
|
||||||
'еаикс', 'ебикс', 'есикс', 'едикс',
|
'еаикс', 'ебикс', 'есикс', 'едикс',
|
||||||
'аикс', 'бикс', 'сикс', 'дикс',
|
'аикс', 'бикс', 'сикс', 'дикс',
|
||||||
'ал', 'бл', 'кл', 'дл'):
|
'ал', 'бл', 'кл', 'дл',
|
||||||
|
'р8', 'р9', 'р10', 'р11', 'р12', 'р13', 'р14', 'р15'):
|
||||||
if op not in symbols:
|
if op not in symbols:
|
||||||
unresolved.append(op)
|
unresolved.append(op)
|
||||||
return unresolved
|
return unresolved
|
||||||
|
|
@ -505,17 +575,25 @@ def process_ast_line(line):
|
||||||
|
|
||||||
source = f"{mnemonic} {', '.join(operands)}" if operands else mnemonic
|
source = f"{mnemonic} {', '.join(operands)}" if operands else mnemonic
|
||||||
|
|
||||||
source_with_values = ""
|
need_stub = has_unresolved_labels(operands, mnemonic)
|
||||||
|
|
||||||
if has_unresolved_labels(operands):
|
if need_stub:
|
||||||
stub_size = get_stub_size(mnemonic, operands)
|
stub_size = get_stub_size(mnemonic, operands)
|
||||||
unresolved = get_unresolved_labels(operands)
|
unresolved = get_unresolved_labels(operands)
|
||||||
|
|
||||||
|
if unresolved:
|
||||||
reloc_text = f"ЗАГЛУШКА {', '.join(unresolved)}"
|
reloc_text = f"ЗАГЛУШКА {', '.join(unresolved)}"
|
||||||
|
else:
|
||||||
|
label_from_op = extract_label_from_operands(operands)
|
||||||
|
if label_from_op:
|
||||||
|
reloc_text = f"ЗАГЛУШКА {label_from_op}"
|
||||||
|
else:
|
||||||
|
reloc_text = "ЗАГЛУШКА (неизвестная метка)"
|
||||||
|
|
||||||
relocations.append({
|
relocations.append({
|
||||||
'address': current_address,
|
'address': current_address,
|
||||||
'size': stub_size,
|
'size': stub_size,
|
||||||
'labels': unresolved,
|
'labels': unresolved if unresolved else [label_from_op] if label_from_op else [],
|
||||||
'source': source,
|
'source': source,
|
||||||
'mnemonic': mnemonic
|
'mnemonic': mnemonic
|
||||||
})
|
})
|
||||||
|
|
@ -560,9 +638,9 @@ def process_ast_line(line):
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Ошибка кодирования {source}: {e}", file=sys.stderr)
|
print(f"Ошибка кодирования {source}: {e}", file=sys.stderr)
|
||||||
labels_list = pending_labels
|
labels_to_attach = pending_labels.copy()
|
||||||
add_byte(0xCC, source, None, f"ОШИБКА: {e}", labels_list)
|
add_byte(0xCC, source, f"ОШИБКА: {e}", labels_to_attach)
|
||||||
pending_labels = []
|
pending_labels.clear()
|
||||||
|
|
||||||
if sec == '.text':
|
if sec == '.text':
|
||||||
text_buffer.append(0xCC)
|
text_buffer.append(0xCC)
|
||||||
|
|
@ -589,113 +667,113 @@ def finalize_headers():
|
||||||
|
|
||||||
i = 0
|
i = 0
|
||||||
while i < len(entries):
|
while i < len(entries):
|
||||||
segment, addr, byte, target, source, label, source_with_values, calc_target, calc_byte = entries[i]
|
segment, addr, virt_addr, byte_str, target, source, label, cmd_with_values, calc_target, calc_byte = entries[i]
|
||||||
|
|
||||||
# e_entry - 8 байт
|
|
||||||
if 'e_entry (stub)' in source:
|
if 'e_entry (stub)' in source:
|
||||||
new_bytes = [(entry_point_addr >> j*8) & 0xFF for j in range(8)]
|
new_bytes = [(entry_point_addr >> j*8) & 0xFF for j in range(8)]
|
||||||
for j, nb in enumerate(new_bytes):
|
for j, nb in enumerate(new_bytes):
|
||||||
entries[i + j] = (segment, addr + j, nb, target,
|
virt = f"0x{entry_point_addr + j:08x}"
|
||||||
|
byte_hex = f"0x{nb:02x}"
|
||||||
|
entries[i + j] = (segment, addr + j, virt, byte_hex, target,
|
||||||
f"e_entry = 0x{entry_point_addr:x}",
|
f"e_entry = 0x{entry_point_addr:x}",
|
||||||
label if j == 0 else "",
|
label if j == 0 else "",
|
||||||
"", "",
|
"", "", byte_hex)
|
||||||
f"0x{nb:02x}")
|
|
||||||
i += 8
|
i += 8
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# p_offset (text) - 8 байт
|
|
||||||
elif 'p_offset (text stub)' in source:
|
elif 'p_offset (text stub)' in source:
|
||||||
new_bytes = [(text_offset >> j*8) & 0xFF for j in range(8)]
|
new_bytes = [(text_offset >> j*8) & 0xFF for j in range(8)]
|
||||||
for j, nb in enumerate(new_bytes):
|
for j, nb in enumerate(new_bytes):
|
||||||
entries[i + j] = (segment, addr + j, nb, target,
|
virt = f"0x{addr + j:08x}"
|
||||||
|
byte_hex = f"0x{nb:02x}"
|
||||||
|
entries[i + j] = (segment, addr + j, virt, byte_hex, target,
|
||||||
f"p_offset (text) = 0x{text_offset:x}",
|
f"p_offset (text) = 0x{text_offset:x}",
|
||||||
label if j == 0 else "",
|
label if j == 0 else "",
|
||||||
"", "",
|
"", "", byte_hex)
|
||||||
f"0x{nb:02x}")
|
|
||||||
i += 8
|
i += 8
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# p_filesz (text) - 8 байт
|
|
||||||
elif 'p_filesz (text stub)' in source:
|
elif 'p_filesz (text stub)' in source:
|
||||||
new_bytes = [(text_filesz >> j*8) & 0xFF for j in range(8)]
|
new_bytes = [(text_filesz >> j*8) & 0xFF for j in range(8)]
|
||||||
for j, nb in enumerate(new_bytes):
|
for j, nb in enumerate(new_bytes):
|
||||||
entries[i + j] = (segment, addr + j, nb, target,
|
virt = f"0x{addr + j:08x}"
|
||||||
|
byte_hex = f"0x{nb:02x}"
|
||||||
|
entries[i + j] = (segment, addr + j, virt, byte_hex, target,
|
||||||
f"p_filesz (text) = {text_filesz}",
|
f"p_filesz (text) = {text_filesz}",
|
||||||
label if j == 0 else "",
|
label if j == 0 else "",
|
||||||
"", "",
|
"", "", byte_hex)
|
||||||
f"0x{nb:02x}")
|
|
||||||
i += 8
|
i += 8
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# p_memsz (text) - 8 байт
|
|
||||||
elif 'p_memsz (text stub)' in source:
|
elif 'p_memsz (text stub)' in source:
|
||||||
new_bytes = [(text_memsz >> j*8) & 0xFF for j in range(8)]
|
new_bytes = [(text_memsz >> j*8) & 0xFF for j in range(8)]
|
||||||
for j, nb in enumerate(new_bytes):
|
for j, nb in enumerate(new_bytes):
|
||||||
entries[i + j] = (segment, addr + j, nb, target,
|
virt = f"0x{addr + j:08x}"
|
||||||
|
byte_hex = f"0x{nb:02x}"
|
||||||
|
entries[i + j] = (segment, addr + j, virt, byte_hex, target,
|
||||||
f"p_memsz (text) = {text_memsz}",
|
f"p_memsz (text) = {text_memsz}",
|
||||||
label if j == 0 else "",
|
label if j == 0 else "",
|
||||||
"", "",
|
"", "", byte_hex)
|
||||||
f"0x{nb:02x}")
|
|
||||||
i += 8
|
i += 8
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# p_offset (data) - 8 байт
|
|
||||||
elif 'p_offset (data stub)' in source:
|
elif 'p_offset (data stub)' in source:
|
||||||
new_bytes = [(data_offset >> j*8) & 0xFF for j in range(8)]
|
new_bytes = [(data_offset >> j*8) & 0xFF for j in range(8)]
|
||||||
for j, nb in enumerate(new_bytes):
|
for j, nb in enumerate(new_bytes):
|
||||||
entries[i + j] = (segment, addr + j, nb, target,
|
virt = f"0x{addr + j:08x}"
|
||||||
|
byte_hex = f"0x{nb:02x}"
|
||||||
|
entries[i + j] = (segment, addr + j, virt, byte_hex, target,
|
||||||
f"p_offset (data) = 0x{data_offset:x}",
|
f"p_offset (data) = 0x{data_offset:x}",
|
||||||
label if j == 0 else "",
|
label if j == 0 else "",
|
||||||
"", "",
|
"", "", byte_hex)
|
||||||
f"0x{nb:02x}")
|
|
||||||
i += 8
|
i += 8
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# p_vaddr (data) - 8 байт
|
|
||||||
elif 'p_vaddr (data stub)' in source:
|
elif 'p_vaddr (data stub)' in source:
|
||||||
new_bytes = [(vaddr_data_final >> j*8) & 0xFF for j in range(8)]
|
new_bytes = [(vaddr_data_final >> j*8) & 0xFF for j in range(8)]
|
||||||
for j, nb in enumerate(new_bytes):
|
for j, nb in enumerate(new_bytes):
|
||||||
entries[i + j] = (segment, addr + j, nb, target,
|
virt = f"0x{vaddr_data_final + j:08x}"
|
||||||
|
byte_hex = f"0x{nb:02x}"
|
||||||
|
entries[i + j] = (segment, addr + j, virt, byte_hex, target,
|
||||||
f"p_vaddr (data) = 0x{vaddr_data_final:x}",
|
f"p_vaddr (data) = 0x{vaddr_data_final:x}",
|
||||||
label if j == 0 else "",
|
label if j == 0 else "",
|
||||||
"", "",
|
"", "", byte_hex)
|
||||||
f"0x{nb:02x}")
|
|
||||||
i += 8
|
i += 8
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# p_paddr (data) - 8 байт
|
|
||||||
elif 'p_paddr (data stub)' in source:
|
elif 'p_paddr (data stub)' in source:
|
||||||
new_bytes = [(vaddr_data_final >> j*8) & 0xFF for j in range(8)]
|
new_bytes = [(vaddr_data_final >> j*8) & 0xFF for j in range(8)]
|
||||||
for j, nb in enumerate(new_bytes):
|
for j, nb in enumerate(new_bytes):
|
||||||
entries[i + j] = (segment, addr + j, nb, target,
|
virt = f"0x{vaddr_data_final + j:08x}"
|
||||||
|
byte_hex = f"0x{nb:02x}"
|
||||||
|
entries[i + j] = (segment, addr + j, virt, byte_hex, target,
|
||||||
f"p_paddr (data) = 0x{vaddr_data_final:x}",
|
f"p_paddr (data) = 0x{vaddr_data_final:x}",
|
||||||
label if j == 0 else "",
|
label if j == 0 else "",
|
||||||
"", "",
|
"", "", byte_hex)
|
||||||
f"0x{nb:02x}")
|
|
||||||
i += 8
|
i += 8
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# p_filesz (data) - 8 байт
|
|
||||||
elif 'p_filesz (data stub)' in source:
|
elif 'p_filesz (data stub)' in source:
|
||||||
new_bytes = [(data_filesz >> j*8) & 0xFF for j in range(8)]
|
new_bytes = [(data_filesz >> j*8) & 0xFF for j in range(8)]
|
||||||
for j, nb in enumerate(new_bytes):
|
for j, nb in enumerate(new_bytes):
|
||||||
entries[i + j] = (segment, addr + j, nb, target,
|
virt = f"0x{addr + j:08x}"
|
||||||
|
byte_hex = f"0x{nb:02x}"
|
||||||
|
entries[i + j] = (segment, addr + j, virt, byte_hex, target,
|
||||||
f"p_filesz (data) = {data_filesz}",
|
f"p_filesz (data) = {data_filesz}",
|
||||||
label if j == 0 else "",
|
label if j == 0 else "",
|
||||||
"", "",
|
"", "", byte_hex)
|
||||||
f"0x{nb:02x}")
|
|
||||||
i += 8
|
i += 8
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# p_memsz (data) - 8 байт
|
|
||||||
elif 'p_memsz (data stub)' in source:
|
elif 'p_memsz (data stub)' in source:
|
||||||
new_bytes = [(data_memsz >> j*8) & 0xFF for j in range(8)]
|
new_bytes = [(data_memsz >> j*8) & 0xFF for j in range(8)]
|
||||||
for j, nb in enumerate(new_bytes):
|
for j, nb in enumerate(new_bytes):
|
||||||
entries[i + j] = (segment, addr + j, nb, target,
|
virt = f"0x{addr + j:08x}"
|
||||||
|
byte_hex = f"0x{nb:02x}"
|
||||||
|
entries[i + j] = (segment, addr + j, virt, byte_hex, target,
|
||||||
f"p_memsz (data) = {data_memsz}",
|
f"p_memsz (data) = {data_memsz}",
|
||||||
label if j == 0 else "",
|
label if j == 0 else "",
|
||||||
"", "",
|
"", "", byte_hex)
|
||||||
f"0x{nb:02x}")
|
|
||||||
i += 8
|
i += 8
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|
@ -705,19 +783,20 @@ def finalize_headers():
|
||||||
def save_to_csv(filename: str):
|
def save_to_csv(filename: str):
|
||||||
with open(filename, 'w', newline='', encoding='utf-8') as f:
|
with open(filename, 'w', newline='', encoding='utf-8') as f:
|
||||||
writer = csv.writer(f, delimiter=';')
|
writer = csv.writer(f, delimiter=';')
|
||||||
writer.writerow(['сегмент', 'адрес', 'байт', 'приводящая_метка', 'уводящий_адрес',
|
writer.writerow(['сегмент', 'адрес', 'виртуальный_адрес', 'байт', 'приводящая_метка',
|
||||||
'исходная_команда', 'команда_со_значениями',
|
'уводящий_адрес', 'исходная_команда', 'команда_со_значениями',
|
||||||
'рассчитанный_уводящий_адрес', 'рассчитанный_байт'])
|
'рассчитанный_уводящий_адрес', 'рассчитанный_байт'])
|
||||||
|
|
||||||
for segment, addr, byte, target, source, label, source_with_values, calc_target, calc_byte in entries:
|
for segment, addr, virt_addr, byte_str, target, source, label, cmd_with_values, calc_target, calc_byte in entries:
|
||||||
writer.writerow([
|
writer.writerow([
|
||||||
segment,
|
segment,
|
||||||
f"0x{addr:08x}",
|
f"0x{addr:08x}",
|
||||||
f"0x{byte:02x}",
|
virt_addr,
|
||||||
|
byte_str,
|
||||||
label,
|
label,
|
||||||
target,
|
target,
|
||||||
source,
|
source,
|
||||||
source_with_values,
|
cmd_with_values,
|
||||||
calc_target,
|
calc_target,
|
||||||
calc_byte
|
calc_byte
|
||||||
])
|
])
|
||||||
|
|
@ -748,16 +827,16 @@ def main():
|
||||||
vaddr_data_final = align_up(vaddr_text + len(text_buffer), PAGE_SIZE)
|
vaddr_data_final = align_up(vaddr_text + len(text_buffer), PAGE_SIZE)
|
||||||
vaddr_bnd_final = align_up(vaddr_data_final + len(data_buffer), PAGE_SIZE)
|
vaddr_bnd_final = align_up(vaddr_data_final + len(data_buffer), PAGE_SIZE)
|
||||||
|
|
||||||
print(f"\n=== Первый проход (однопроходная генерация с заглушками) ===")
|
print(f"\n=== Первый проход ===")
|
||||||
print(f" .text: {len(text_buffer)} байт, виртуальный адрес=0x{vaddr_text:x}")
|
print(f" .text: {len(text_buffer)} байт, vaddr=0x{vaddr_text:x}")
|
||||||
print(f" .data: {len(data_buffer)} байт, виртуальный адрес=0x{vaddr_data_final:x}")
|
print(f" .data: {len(data_buffer)} байт, vaddr=0x{vaddr_data_final:x}")
|
||||||
print(f" .bnd: {bnd_size} байт, виртуальный адрес=0x{vaddr_bnd_final:x}")
|
print(f" .bnd: {bnd_size} байт, vaddr=0x{vaddr_bnd_final:x}")
|
||||||
print(f" точка входа: {entry_point} = 0x{labels.get(entry_point, vaddr_text):x}")
|
print(f" точка входа: {entry_point} = 0x{labels.get(entry_point, vaddr_text):x}")
|
||||||
print(f" меток: {len(labels)}")
|
print(f" меток: {len(labels)}")
|
||||||
print(f" констант: {len(symbols)}")
|
print(f" констант: {len(symbols)}")
|
||||||
print(f" релокаций: {len(relocations)}")
|
print(f" релокаций: {len(relocations)}")
|
||||||
print(f" записей в CSV: {len(entries)}")
|
print(f" записей: {len(entries)}")
|
||||||
print(f" CSV сохранен: {csv_file}")
|
print(f" CSV: {csv_file}")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
|
||||||
216
kvs_pass2.py
216
kvs_pass2.py
|
|
@ -2,13 +2,11 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Второй проход КВС
|
Второй проход КВС (упрощённый)
|
||||||
- Собирает адреса всех приводящих меток (поддерживает несколько меток через запятую)
|
- Собирает адреса всех приводящих меток из колонки 'виртуальный_адрес'
|
||||||
- Заменяет заглушки в уводящих адресах на реальные адреса
|
- Заменяет заглушки в уводящих адресах на реальные адреса
|
||||||
- Записывает рассчитанные значения в колонку 'рассчитанный_уводящий_адрес' (файловое смещение)
|
- Записывает рассчитанные значения в колонку 'рассчитанный_уводящий_адрес' (файловое смещение)
|
||||||
- Формирует команду с подставленными адресами в колонку 'команда_со_значениями' (виртуальный адрес)
|
- Формирует команду с подставленными виртуальными адресами в колонку 'команда_со_значениями'
|
||||||
- Пропускает заглушки, которые не найдены (возможно это константы)
|
|
||||||
- Выводит статистику по неразрешённым заглушкам
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
@ -30,55 +28,17 @@ def read_csv(csv_file):
|
||||||
return headers, entries
|
return headers, entries
|
||||||
|
|
||||||
|
|
||||||
def get_virtual_addresses(entries, headers):
|
def collect_labels(entries, headers):
|
||||||
"""
|
|
||||||
Извлекает виртуальные адреса секций из заголовка CSV
|
|
||||||
Возвращает (vaddr_text, vaddr_data)
|
|
||||||
"""
|
|
||||||
vaddr_text = 0x401000
|
|
||||||
vaddr_data = 0x402000
|
|
||||||
|
|
||||||
try:
|
|
||||||
source_idx = headers.index('исходная_команда')
|
|
||||||
calc_target_idx = headers.index('рассчитанный_уводящий_адрес')
|
|
||||||
except ValueError:
|
|
||||||
return vaddr_text, vaddr_data
|
|
||||||
|
|
||||||
for row in entries:
|
|
||||||
source = row[source_idx].strip()
|
|
||||||
calc_target = row[calc_target_idx].strip()
|
|
||||||
|
|
||||||
if 'p_vaddr (text)' in source and calc_target:
|
|
||||||
parts = calc_target.split('=')
|
|
||||||
if len(parts) >= 2:
|
|
||||||
addr_str = parts[1].strip()
|
|
||||||
if addr_str.startswith('0x'):
|
|
||||||
vaddr_text = int(addr_str, 16)
|
|
||||||
|
|
||||||
elif 'p_vaddr (data)' in source and calc_target:
|
|
||||||
parts = calc_target.split('=')
|
|
||||||
if len(parts) >= 2:
|
|
||||||
addr_str = parts[1].strip()
|
|
||||||
if addr_str.startswith('0x'):
|
|
||||||
vaddr_data = int(addr_str, 16)
|
|
||||||
|
|
||||||
return vaddr_text, vaddr_data
|
|
||||||
|
|
||||||
|
|
||||||
def collect_labels(entries, headers, vaddr_text, vaddr_data):
|
|
||||||
"""
|
"""
|
||||||
Собирает адреса всех приводящих меток.
|
Собирает адреса всех приводящих меток.
|
||||||
Возвращает два словаря:
|
Использует колонку 'виртуальный_адрес' для получения адреса метки.
|
||||||
- labels_file: имя метки -> файловое смещение
|
Возвращает словарь: имя метки -> виртуальный адрес
|
||||||
- labels_virt: имя метки -> виртуальный адрес
|
|
||||||
"""
|
"""
|
||||||
labels_file = {} # имя метки -> файловое смещение
|
labels = {}
|
||||||
labels_virt = {} # имя метки -> виртуальный адрес
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
label_idx = headers.index('приводящая_метка')
|
label_idx = headers.index('приводящая_метка')
|
||||||
addr_idx = headers.index('адрес')
|
virt_addr_idx = headers.index('виртуальный_адрес')
|
||||||
segment_idx = headers.index('сегмент')
|
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
print(f"Ошибка: не найдена нужная колонка в CSV: {e}")
|
print(f"Ошибка: не найдена нужная колонка в CSV: {e}")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
@ -86,33 +46,33 @@ def collect_labels(entries, headers, vaddr_text, vaddr_data):
|
||||||
for row in entries:
|
for row in entries:
|
||||||
label_str = row[label_idx].strip()
|
label_str = row[label_idx].strip()
|
||||||
if label_str:
|
if label_str:
|
||||||
addr_str = row[addr_idx].strip()
|
virt_addr_str = row[virt_addr_idx].strip()
|
||||||
if addr_str.startswith('0x'):
|
if virt_addr_str.startswith('0x'):
|
||||||
file_addr = int(addr_str, 16)
|
virt_addr = int(virt_addr_str, 16)
|
||||||
segment = row[segment_idx].strip()
|
|
||||||
|
|
||||||
# Вычисляем виртуальный адрес
|
|
||||||
if segment == '.text':
|
|
||||||
virt_addr = vaddr_text + (file_addr - 0x1000)
|
|
||||||
elif segment == '.data':
|
|
||||||
virt_addr = vaddr_data + (file_addr - 0x2000)
|
|
||||||
else:
|
|
||||||
virt_addr = file_addr
|
|
||||||
|
|
||||||
# Разделяем несколько меток через запятую
|
|
||||||
for label_name in label_str.split(','):
|
for label_name in label_str.split(','):
|
||||||
label_name = label_name.strip()
|
label_name = label_name.strip()
|
||||||
if label_name:
|
if label_name:
|
||||||
labels_file[label_name] = file_addr
|
labels[label_name] = virt_addr
|
||||||
labels_virt[label_name] = virt_addr
|
|
||||||
|
|
||||||
return labels_file, labels_virt
|
# Выводим статистику собранных меток
|
||||||
|
print(f"\n{'='*80}")
|
||||||
|
print(f"СОБРАННЫЕ ПРИВОДЯЩИЕ МЕТКИ (всего: {len(labels)})")
|
||||||
|
print(f"{'='*80}")
|
||||||
|
print(f"\n{'Имя метки':<35} {'Виртуальный адрес':<22}")
|
||||||
|
print(f"{'-'*57}")
|
||||||
|
|
||||||
|
for name in sorted(labels.keys()):
|
||||||
|
virt_addr = labels[name]
|
||||||
|
print(f"{name:<35} 0x{virt_addr:08x} ({virt_addr})")
|
||||||
|
|
||||||
|
return labels
|
||||||
|
|
||||||
|
|
||||||
def resolve_targets(entries, headers, labels_file, labels_virt):
|
def resolve_targets(entries, headers, labels):
|
||||||
"""
|
"""
|
||||||
Заменяет уводящие адреса-заглушки на реальные адреса
|
Заменяет уводящие адреса-заглушки на реальные адреса
|
||||||
- рассчитанный_уводящий_адрес: файловое смещение
|
- рассчитанный_уводящий_адрес: файловое смещение (берём из колонки 'адрес')
|
||||||
- команда_со_значениями: виртуальный адрес
|
- команда_со_значениями: виртуальный адрес
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
|
|
@ -120,12 +80,13 @@ def resolve_targets(entries, headers, labels_file, labels_virt):
|
||||||
calc_target_idx = headers.index('рассчитанный_уводящий_адрес')
|
calc_target_idx = headers.index('рассчитанный_уводящий_адрес')
|
||||||
source_idx = headers.index('исходная_команда')
|
source_idx = headers.index('исходная_команда')
|
||||||
source_with_values_idx = headers.index('команда_со_значениями')
|
source_with_values_idx = headers.index('команда_со_значениями')
|
||||||
|
addr_idx = headers.index('адрес')
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
print(f"Ошибка: не найдена нужная колонка в CSV: {e}")
|
print(f"Ошибка: не найдена нужная колонка в CSV: {e}")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
resolved = [] # (имя_метки, файловый_адрес, виртуальный_адрес)
|
resolved = []
|
||||||
unresolved = [] # имя_метки
|
unresolved = []
|
||||||
|
|
||||||
for row in entries:
|
for row in entries:
|
||||||
target = row[target_idx].strip()
|
target = row[target_idx].strip()
|
||||||
|
|
@ -133,17 +94,22 @@ def resolve_targets(entries, headers, labels_file, labels_virt):
|
||||||
if target and target.startswith('ЗАГЛУШКА '):
|
if target and target.startswith('ЗАГЛУШКА '):
|
||||||
label_name = target.replace('ЗАГЛУШКА ', '').strip()
|
label_name = target.replace('ЗАГЛУШКА ', '').strip()
|
||||||
|
|
||||||
if label_name in labels_file:
|
if label_name in labels:
|
||||||
file_addr = labels_file[label_name]
|
virt_addr = labels[label_name]
|
||||||
virt_addr = labels_virt[label_name]
|
|
||||||
file_hex = f"0x{file_addr:08x}"
|
|
||||||
virt_hex = f"0x{virt_addr:08x}"
|
virt_hex = f"0x{virt_addr:08x}"
|
||||||
|
|
||||||
# Файловое смещение в рассчитанный_уводящий_адрес
|
# Файловое смещение берём из колонки 'адрес' текущей строки
|
||||||
|
addr_str = row[addr_idx].strip()
|
||||||
|
if addr_str.startswith('0x'):
|
||||||
|
file_addr = int(addr_str, 16)
|
||||||
|
file_hex = f"0x{file_addr:08x}"
|
||||||
row[calc_target_idx] = file_hex
|
row[calc_target_idx] = file_hex
|
||||||
resolved.append((label_name, file_addr, virt_addr))
|
resolved.append((label_name, file_addr, virt_addr))
|
||||||
|
else:
|
||||||
|
row[calc_target_idx] = ""
|
||||||
|
resolved.append((label_name, 0, virt_addr))
|
||||||
|
|
||||||
# Виртуальный адрес в команда_со_значениями
|
# Подставляем виртуальный адрес в команду
|
||||||
source_cmd = row[source_idx].strip()
|
source_cmd = row[source_idx].strip()
|
||||||
if source_cmd:
|
if source_cmd:
|
||||||
cmd_with_addr = source_cmd.replace(label_name, virt_hex)
|
cmd_with_addr = source_cmd.replace(label_name, virt_hex)
|
||||||
|
|
@ -152,6 +118,46 @@ def resolve_targets(entries, headers, labels_file, labels_virt):
|
||||||
unresolved.append(label_name)
|
unresolved.append(label_name)
|
||||||
row[calc_target_idx] = ""
|
row[calc_target_idx] = ""
|
||||||
|
|
||||||
|
# Выводим статистику разрешённых заглушек
|
||||||
|
print(f"\n{'='*80}")
|
||||||
|
print(f"РАЗРЕШЁННЫЕ ЗАГЛУШКИ (всего: {len(resolved)})")
|
||||||
|
print(f"{'='*80}")
|
||||||
|
|
||||||
|
if resolved:
|
||||||
|
unique_resolved = {}
|
||||||
|
for name, file_addr, virt_addr in resolved:
|
||||||
|
if name not in unique_resolved:
|
||||||
|
unique_resolved[name] = (file_addr, virt_addr)
|
||||||
|
|
||||||
|
print(f"\nУникальных меток: {len(unique_resolved)}")
|
||||||
|
print(f"\n{'Имя метки':<35} {'Файловое смещение':<22} {'Виртуальный адрес':<22}")
|
||||||
|
print(f"{'-'*79}")
|
||||||
|
|
||||||
|
for name in sorted(unique_resolved.keys()):
|
||||||
|
file_addr, virt_addr = unique_resolved[name]
|
||||||
|
if file_addr:
|
||||||
|
print(f"{name:<35} 0x{file_addr:08x} ({file_addr:<10}) 0x{virt_addr:08x} ({virt_addr})")
|
||||||
|
else:
|
||||||
|
print(f"{name:<35} {'(не известно)':<22} 0x{virt_addr:08x} ({virt_addr})")
|
||||||
|
else:
|
||||||
|
print("\n--- НЕТ РАЗРЕШЁННЫХ ЗАГЛУШЕК ---")
|
||||||
|
|
||||||
|
# Выводим статистику неразрешённых заглушек
|
||||||
|
print(f"\n{'='*80}")
|
||||||
|
print(f"НЕРАЗРЕШЁННЫЕ ЗАГЛУШКИ (всего: {len(unresolved)})")
|
||||||
|
print(f"{'='*80}")
|
||||||
|
|
||||||
|
if unresolved:
|
||||||
|
unresolved_counts = Counter(unresolved)
|
||||||
|
print(f"\nУникальных неразрешённых имён: {len(unresolved_counts)}")
|
||||||
|
print(f"\n{'Имя метки':<35} {'Количество вхождений':<20}")
|
||||||
|
print(f"{'-'*55}")
|
||||||
|
|
||||||
|
for name, count in sorted(unresolved_counts.items(), key=lambda x: x[1], reverse=True):
|
||||||
|
print(f"{name:<35} {count}")
|
||||||
|
else:
|
||||||
|
print("\n--- НЕТ НЕРАЗРЕШЁННЫХ ЗАГЛУШЕК ---")
|
||||||
|
|
||||||
return resolved, unresolved
|
return resolved, unresolved
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -163,36 +169,6 @@ def save_csv(csv_file, headers, entries):
|
||||||
writer.writerows(entries)
|
writer.writerows(entries)
|
||||||
|
|
||||||
|
|
||||||
def print_statistics(labels_count, resolved, unresolved, vaddr_text, vaddr_data):
|
|
||||||
"""Выводит статистику по разрешению меток"""
|
|
||||||
print(f"\n--- Статистика разрешения меток ---")
|
|
||||||
print(f" Виртуальный адрес .text: 0x{vaddr_text:x}")
|
|
||||||
print(f" Виртуальный адрес .data: 0x{vaddr_data:x}")
|
|
||||||
print(f" Всего приводящих меток: {labels_count}")
|
|
||||||
print(f" Разрешено заглушек: {len(resolved)}")
|
|
||||||
print(f" Не разрешено заглушек (возможно константы): {len(unresolved)}")
|
|
||||||
|
|
||||||
if resolved:
|
|
||||||
unique_resolved = {}
|
|
||||||
for name, file_addr, virt_addr in resolved:
|
|
||||||
if name not in unique_resolved:
|
|
||||||
unique_resolved[name] = (file_addr, virt_addr)
|
|
||||||
|
|
||||||
print(f"\n--- Разрешённые заглушки (первые 20) ---")
|
|
||||||
for i, (name, (file_addr, virt_addr)) in enumerate(list(unique_resolved.items())[:20]):
|
|
||||||
print(f" {name} -> файл:0x{file_addr:08x}, вирт:0x{virt_addr:08x}")
|
|
||||||
if len(unique_resolved) > 20:
|
|
||||||
print(f" ... и ещё {len(unique_resolved) - 20}")
|
|
||||||
|
|
||||||
if unresolved:
|
|
||||||
unresolved_counts = Counter(unresolved)
|
|
||||||
print(f"\n--- Неразрешённые заглушки (возможно константы) ---")
|
|
||||||
for name, count in sorted(unresolved_counts.items(), key=lambda x: x[1], reverse=True)[:20]:
|
|
||||||
print(f" {name}: {count} раз(а)")
|
|
||||||
if len(unresolved_counts) > 20:
|
|
||||||
print(f" ... и ещё {len(unresolved_counts) - 20} различных имён")
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
if len(sys.argv) != 2:
|
if len(sys.argv) != 2:
|
||||||
print("Использование: python kvs_pass2.py <входной.csv>")
|
print("Использование: python kvs_pass2.py <входной.csv>")
|
||||||
|
|
@ -200,33 +176,27 @@ def main():
|
||||||
|
|
||||||
csv_file = sys.argv[1]
|
csv_file = sys.argv[1]
|
||||||
|
|
||||||
print(f"\n=== Второй проход КВС ===")
|
print(f"\n=== ВТОРОЙ ПРОХОД КВС (упрощённый) ===")
|
||||||
print(f"Чтение CSV: {csv_file}")
|
print(f"Чтение CSV: {csv_file}")
|
||||||
|
|
||||||
headers, entries = read_csv(csv_file)
|
headers, entries = read_csv(csv_file)
|
||||||
|
|
||||||
vaddr_text, vaddr_data = get_virtual_addresses(entries, headers)
|
print(f"\n--- СБОР ПРИВОДЯЩИХ МЕТОК ---")
|
||||||
print(f"Виртуальный адрес .text: 0x{vaddr_text:x}")
|
labels = collect_labels(entries, headers)
|
||||||
print(f"Виртуальный адрес .data: 0x{vaddr_data:x}")
|
|
||||||
|
|
||||||
print(f"\n--- Сбор приводящих меток ---")
|
print(f"\n--- РАЗРЕШЕНИЕ УВОДЯЩИХ АДРЕСОВ ---")
|
||||||
labels_file, labels_virt = collect_labels(entries, headers, vaddr_text, vaddr_data)
|
resolved, unresolved = resolve_targets(entries, headers, labels)
|
||||||
print(f"Найдено приводящих меток: {len(labels_file)}")
|
|
||||||
|
|
||||||
if labels_file:
|
print(f"\n{'='*80}")
|
||||||
print(f"\n--- Примеры приводящих меток (первые 20) ---")
|
print(f"ОБЩАЯ СТАТИСТИКА")
|
||||||
for i, name in enumerate(list(labels_file.keys())[:20]):
|
print(f"{'='*80}")
|
||||||
print(f" {name} -> файл:0x{labels_file[name]:08x}, вирт:0x{labels_virt[name]:08x}")
|
print(f" Приводящих меток в CSV: {len(labels)}")
|
||||||
if len(labels_file) > 20:
|
print(f" Разрешено заглушек: {len(resolved)}")
|
||||||
print(f" ... и ещё {len(labels_file) - 20}")
|
print(f" Не разрешено заглушек: {len(unresolved)}")
|
||||||
|
print(f"{'='*80}")
|
||||||
print(f"\n--- Разрешение уводящих адресов и формирование команд ---")
|
|
||||||
resolved, unresolved = resolve_targets(entries, headers, labels_file, labels_virt)
|
|
||||||
|
|
||||||
print_statistics(len(labels_file), resolved, unresolved, vaddr_text, vaddr_data)
|
|
||||||
|
|
||||||
save_csv(csv_file, headers, entries)
|
save_csv(csv_file, headers, entries)
|
||||||
print(f"\nCSV сохранен: {csv_file}")
|
print(f"\nCSV сохранён: {csv_file}")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
|
||||||
190
kvs_pass4.py
190
kvs_pass4.py
|
|
@ -4,13 +4,13 @@
|
||||||
"""
|
"""
|
||||||
Четвёртый проход КВС
|
Четвёртый проход КВС
|
||||||
- Перекодирует инструкции, используя подставленные значения
|
- Перекодирует инструкции, используя подставленные значения
|
||||||
- Смотрит колонки 'команда_со_значениями' и 'рассчитанный_уводящий_адрес'
|
- Смотрит колонку 'команда_со_значениями'
|
||||||
- Записывает перекодированные байты в колонку 'рассчитанный_байт'
|
- Записывает перекодированные байты в колонку 'рассчитанный_байт'
|
||||||
|
- Использует виртуальные адреса из CSV для вычисления смещений
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import csv
|
import csv
|
||||||
import struct
|
|
||||||
|
|
||||||
sys.path.insert(0, '.')
|
sys.path.insert(0, '.')
|
||||||
from kvs_data import PAGE_SIZE, text_vaddr_base, align_up
|
from kvs_data import PAGE_SIZE, text_vaddr_base, align_up
|
||||||
|
|
@ -18,16 +18,15 @@ from kvs_encoder import encode_instruction
|
||||||
|
|
||||||
# ========== ГЛОБАЛЬНОЕ СОСТОЯНИЕ ==========
|
# ========== ГЛОБАЛЬНОЕ СОСТОЯНИЕ ==========
|
||||||
vaddr_text = text_vaddr_base
|
vaddr_text = text_vaddr_base
|
||||||
vaddr_data = None
|
vaddr_data = 0x402000
|
||||||
vaddr_bnd = None
|
vaddr_bnd = None
|
||||||
|
|
||||||
labels = {} # имя метки -> адрес
|
labels = {}
|
||||||
label_sections = {} # имя метки -> секция
|
label_sections = {}
|
||||||
symbols = {} # имя константы -> значение
|
symbols = {}
|
||||||
|
|
||||||
|
|
||||||
def read_csv(csv_file):
|
def read_csv(csv_file):
|
||||||
"""Читает CSV файл и возвращает список записей и заголовки"""
|
|
||||||
entries = []
|
entries = []
|
||||||
headers = []
|
headers = []
|
||||||
|
|
||||||
|
|
@ -41,7 +40,6 @@ def read_csv(csv_file):
|
||||||
|
|
||||||
|
|
||||||
def parse_command(cmd_str):
|
def parse_command(cmd_str):
|
||||||
"""Разбирает команду вида 'мнемоника операнд1, операнд2, ...'"""
|
|
||||||
if not cmd_str:
|
if not cmd_str:
|
||||||
return None, []
|
return None, []
|
||||||
|
|
||||||
|
|
@ -50,75 +48,44 @@ def parse_command(cmd_str):
|
||||||
|
|
||||||
operands = []
|
operands = []
|
||||||
if len(parts) > 1 and parts[1]:
|
if len(parts) > 1 and parts[1]:
|
||||||
# Разбираем операнды, разделённые запятыми
|
|
||||||
operands = [op.strip() for op in parts[1].split(',')]
|
operands = [op.strip() for op in parts[1].split(',')]
|
||||||
|
|
||||||
return mnemonic, operands
|
return mnemonic, operands
|
||||||
|
|
||||||
|
|
||||||
def collect_labels_from_csv(entries, headers):
|
def collect_labels_from_csv(entries, headers):
|
||||||
"""Собирает метки из CSV для перекодирования"""
|
"""
|
||||||
global labels, label_sections, vaddr_data, vaddr_bnd
|
Собирает метки из CSV, используя колонку 'виртуальный_адрес'
|
||||||
|
"""
|
||||||
|
global labels, label_sections
|
||||||
|
|
||||||
try:
|
try:
|
||||||
label_idx = headers.index('приводящая_метка')
|
label_idx = headers.index('приводящая_метка')
|
||||||
addr_idx = headers.index('адрес')
|
virt_addr_idx = headers.index('виртуальный_адрес')
|
||||||
segment_idx = headers.index('сегмент')
|
|
||||||
byte_idx = headers.index('байт')
|
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
print(f"Ошибка: не найдена нужная колонка в CSV: {e}")
|
print(f"Ошибка: не найдена нужная колонка в CSV: {e}")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
# Сначала нужно определить виртуальные адреса секций
|
|
||||||
max_addr = 0
|
|
||||||
for row in entries:
|
|
||||||
addr_str = row[addr_idx].strip()
|
|
||||||
if addr_str.startswith('0x'):
|
|
||||||
addr = int(addr_str, 16)
|
|
||||||
if addr > max_addr:
|
|
||||||
max_addr = addr
|
|
||||||
segment = row[segment_idx].strip()
|
|
||||||
|
|
||||||
# Определяем vaddr_data по первому адресу в .data
|
|
||||||
if segment == '.data' and vaddr_data is None:
|
|
||||||
vaddr_data = addr
|
|
||||||
# Определяем vaddr_bnd по первому адресу в .bss
|
|
||||||
elif segment == '.bss' and vaddr_bnd is None:
|
|
||||||
vaddr_bnd = addr
|
|
||||||
|
|
||||||
if vaddr_data is None:
|
|
||||||
vaddr_data = align_up(vaddr_text + max_addr, PAGE_SIZE)
|
|
||||||
if vaddr_bnd is None:
|
|
||||||
vaddr_bnd = align_up(vaddr_data + max_addr, PAGE_SIZE)
|
|
||||||
|
|
||||||
# Собираем метки
|
|
||||||
for row in entries:
|
for row in entries:
|
||||||
label_str = row[label_idx].strip()
|
label_str = row[label_idx].strip()
|
||||||
if label_str:
|
if label_str:
|
||||||
addr_str = row[addr_idx].strip()
|
virt_addr_str = row[virt_addr_idx].strip()
|
||||||
if addr_str.startswith('0x'):
|
if virt_addr_str.startswith('0x'):
|
||||||
addr = int(addr_str, 16)
|
virt_addr = int(virt_addr_str, 16)
|
||||||
|
|
||||||
for label_name in label_str.split(','):
|
for label_name in label_str.split(','):
|
||||||
label_name = label_name.strip()
|
label_name = label_name.strip()
|
||||||
if label_name:
|
if label_name:
|
||||||
labels[label_name] = addr
|
labels[label_name] = virt_addr
|
||||||
# Определяем секцию по адресу
|
label_sections[label_name] = ''
|
||||||
if addr >= vaddr_text and addr < vaddr_text + PAGE_SIZE:
|
|
||||||
label_sections[label_name] = '.text'
|
|
||||||
elif vaddr_data and addr >= vaddr_data and addr < vaddr_data + PAGE_SIZE:
|
|
||||||
label_sections[label_name] = '.data'
|
|
||||||
elif vaddr_bnd and addr >= vaddr_bnd:
|
|
||||||
label_sections[label_name] = '.bss'
|
|
||||||
|
|
||||||
|
|
||||||
def reencode_instructions(entries, headers):
|
def reencode_instructions(entries, headers):
|
||||||
"""Перекодирует инструкции, используя подставленные значения"""
|
|
||||||
try:
|
try:
|
||||||
source_with_values_idx = headers.index('команда_со_значениями')
|
source_with_values_idx = headers.index('команда_со_значениями')
|
||||||
calc_target_idx = headers.index('рассчитанный_уводящий_адрес')
|
|
||||||
calc_byte_idx = headers.index('рассчитанный_байт')
|
calc_byte_idx = headers.index('рассчитанный_байт')
|
||||||
addr_idx = headers.index('адрес')
|
addr_idx = headers.index('адрес')
|
||||||
segment_idx = headers.index('сегмент')
|
virt_addr_idx = headers.index('виртуальный_адрес')
|
||||||
byte_idx = headers.index('байт')
|
byte_idx = headers.index('байт')
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
print(f"Ошибка: не найдена нужная колонка в CSV: {e}")
|
print(f"Ошибка: не найдена нужная колонка в CSV: {e}")
|
||||||
|
|
@ -127,7 +94,6 @@ def reencode_instructions(entries, headers):
|
||||||
reencoded_count = 0
|
reencoded_count = 0
|
||||||
error_count = 0
|
error_count = 0
|
||||||
|
|
||||||
# Проходим по всем строкам
|
|
||||||
i = 0
|
i = 0
|
||||||
while i < len(entries):
|
while i < len(entries):
|
||||||
row = entries[i]
|
row = entries[i]
|
||||||
|
|
@ -136,76 +102,86 @@ def reencode_instructions(entries, headers):
|
||||||
i += 1
|
i += 1
|
||||||
continue
|
continue
|
||||||
|
|
||||||
addr = int(addr_str, 16)
|
file_addr = int(addr_str, 16)
|
||||||
segment = row[segment_idx].strip()
|
|
||||||
|
# Берём виртуальный адрес инструкции из CSV
|
||||||
|
virt_addr_str = row[virt_addr_idx].strip()
|
||||||
|
if virt_addr_str.startswith('0x'):
|
||||||
|
instr_virt_addr = int(virt_addr_str, 16)
|
||||||
|
else:
|
||||||
|
instr_virt_addr = file_addr
|
||||||
|
|
||||||
# Проверяем, есть ли команда для перекодирования
|
|
||||||
cmd = row[source_with_values_idx].strip()
|
cmd = row[source_with_values_idx].strip()
|
||||||
calc_target = row[calc_target_idx].strip()
|
|
||||||
|
|
||||||
# Определяем, нужно ли перекодировать
|
|
||||||
need_reencode = False
|
|
||||||
|
|
||||||
if cmd:
|
if cmd:
|
||||||
# Есть команда с подставленными константами
|
|
||||||
need_reencode = True
|
|
||||||
elif calc_target and calc_target.startswith('0x'):
|
|
||||||
# Есть рассчитанный адрес для заглушки
|
|
||||||
# Нужно взять исходную команду и подставить адрес
|
|
||||||
source_idx = headers.index('исходная_команда')
|
|
||||||
source = row[source_idx].strip()
|
|
||||||
if source:
|
|
||||||
# Заменяем ЗАГЛУШКА имя на реальный адрес
|
|
||||||
target_addr = int(calc_target, 16)
|
|
||||||
cmd = source.replace('ЗАГЛУШКА', '').strip()
|
|
||||||
# Добавляем адрес как операнд
|
|
||||||
cmd = f"{cmd} 0x{target_addr:08x}"
|
|
||||||
need_reencode = True
|
|
||||||
|
|
||||||
if need_reencode and cmd:
|
|
||||||
try:
|
try:
|
||||||
mnemonic, operands = parse_command(cmd)
|
mnemonic, operands = parse_command(cmd)
|
||||||
if mnemonic:
|
if mnemonic:
|
||||||
# Вычисляем текущую позицию в секции
|
# ОТЛАДОЧНЫЙ ВЫВОД (только для переходов)
|
||||||
if segment == '.text':
|
if mnemonic.startswith('короткий_переход') or mnemonic.startswith('переход'):
|
||||||
current_pos = addr - vaddr_text
|
print(f"\n=== ОТЛАДКА ===")
|
||||||
elif segment == '.data' and vaddr_data:
|
print(f" Адрес в CSV: 0x{file_addr:08x}")
|
||||||
current_pos = addr - vaddr_data
|
print(f" Виртуальный адрес инструкции: 0x{instr_virt_addr:08x}")
|
||||||
else:
|
print(f" Команда: {cmd}")
|
||||||
current_pos = 0
|
print(f" Мнемоника: {mnemonic}")
|
||||||
|
print(f" Операнды: {operands}")
|
||||||
|
|
||||||
# Кодируем инструкцию
|
if operands and len(operands) > 0:
|
||||||
|
target_str = operands[0]
|
||||||
|
if target_str.startswith('0x'):
|
||||||
|
target_addr = int(target_str, 16)
|
||||||
|
# Определяем размер инструкции
|
||||||
|
if mnemonic.startswith('короткий'):
|
||||||
|
instr_size = 2
|
||||||
|
else:
|
||||||
|
instr_size = 5
|
||||||
|
offset = target_addr - (instr_virt_addr + instr_size)
|
||||||
|
print(f" Целевой адрес: 0x{target_addr:08x}")
|
||||||
|
print(f" Размер инструкции: {instr_size}")
|
||||||
|
print(f" RIP = 0x{instr_virt_addr + instr_size:08x}")
|
||||||
|
print(f" Смещение = {offset} (0x{offset & 0xFFFFFFFF:08x})")
|
||||||
|
print(f" В диапазоне [-128..127]: {-128 <= offset <= 127}")
|
||||||
|
|
||||||
|
# Вычисляем current_pos как смещение в секции
|
||||||
|
# Определяем секцию по виртуальному адресу
|
||||||
|
if 0x401000 <= instr_virt_addr < 0x402000:
|
||||||
|
current_pos = instr_virt_addr - vaddr_text
|
||||||
|
elif 0x402000 <= instr_virt_addr < 0x403000:
|
||||||
|
current_pos = instr_virt_addr - vaddr_data
|
||||||
|
else:
|
||||||
|
current_pos = instr_virt_addr
|
||||||
|
|
||||||
|
# Преобразуем операнды: если строка с 0x, оставляем как есть
|
||||||
|
# Кодировщик сам разберётся с isdigit()
|
||||||
encoded = encode_instruction(
|
encoded = encode_instruction(
|
||||||
mnemonic, operands, labels, label_sections, symbols,
|
mnemonic, operands, labels, label_sections, symbols,
|
||||||
vaddr_text, vaddr_data if vaddr_data else 0,
|
vaddr_text, vaddr_data, current_pos, vaddr_bnd
|
||||||
current_pos, vaddr_bnd if vaddr_bnd else 0
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Записываем байты в колонку рассчитанный_байт
|
if mnemonic.startswith('короткий_переход') or mnemonic.startswith('переход'):
|
||||||
# Для много-байтовых инструкций записываем в последовательные строки
|
print(f" Закодировано: {[f'0x{b:02x}' for b in encoded]}")
|
||||||
|
print(f" РЕЗУЛЬТАТ: УСПЕШНО")
|
||||||
|
|
||||||
for j, byte in enumerate(encoded):
|
for j, byte in enumerate(encoded):
|
||||||
if i + j < len(entries):
|
if i + j < len(entries):
|
||||||
entries[i + j][calc_byte_idx] = f"0x{byte:02x}"
|
entries[i + j][calc_byte_idx] = f"0x{byte:02x}"
|
||||||
else:
|
|
||||||
# Не хватает строк, создаём новую
|
|
||||||
# (в нормальной ситуации не должно происходить)
|
|
||||||
pass
|
|
||||||
|
|
||||||
reencoded_count += 1
|
reencoded_count += 1
|
||||||
|
|
||||||
# Пропускаем следующие строки, принадлежащие этой инструкции
|
|
||||||
# (обычно в CSV одна строка = один байт)
|
|
||||||
i += len(encoded)
|
i += len(encoded)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Ошибка перекодирования '{cmd}': {e}")
|
print(f"\n=== ОТЛАДКА (ОШИБКА) ===")
|
||||||
|
print(f" Команда: {cmd}")
|
||||||
|
print(f" Мнемоника: {mnemonic if 'mnemonic' in locals() else '?'}")
|
||||||
|
print(f" Операнды: {operands if 'operands' in locals() else '?'}")
|
||||||
|
print(f" Виртуальный адрес инструкции: 0x{instr_virt_addr:08x}")
|
||||||
|
print(f" ОШИБКА: {e}")
|
||||||
error_count += 1
|
error_count += 1
|
||||||
# Записываем INT3 как заглушку
|
|
||||||
row[calc_byte_idx] = "0xcc"
|
row[calc_byte_idx] = "0xcc"
|
||||||
i += 1
|
i += 1
|
||||||
else:
|
else:
|
||||||
# Если нет команды для перекодирования, просто копируем исходный байт
|
# Если нет команды, копируем исходный байт
|
||||||
byte_str = row[byte_idx].strip()
|
byte_str = row[byte_idx].strip()
|
||||||
if byte_str.startswith('0x'):
|
if byte_str.startswith('0x'):
|
||||||
row[calc_byte_idx] = byte_str
|
row[calc_byte_idx] = byte_str
|
||||||
|
|
@ -215,19 +191,20 @@ def reencode_instructions(entries, headers):
|
||||||
|
|
||||||
|
|
||||||
def save_csv(csv_file, headers, entries):
|
def save_csv(csv_file, headers, entries):
|
||||||
"""Сохраняет обновлённый CSV файл"""
|
|
||||||
with open(csv_file, 'w', newline='', encoding='utf-8') as f:
|
with open(csv_file, 'w', newline='', encoding='utf-8') as f:
|
||||||
writer = csv.writer(f, delimiter=';')
|
writer = csv.writer(f, delimiter=';')
|
||||||
writer.writerow(headers)
|
writer.writerow(headers)
|
||||||
writer.writerows(entries)
|
writer.writerows(entries)
|
||||||
|
|
||||||
|
|
||||||
def print_statistics(reencoded_count, error_count):
|
def print_statistics(reencoded_count, error_count, labels_count):
|
||||||
"""Выводит статистику перекодирования"""
|
|
||||||
print(f"\n--- Статистика перекодирования ---")
|
print(f"\n--- Статистика перекодирования ---")
|
||||||
|
print(f" Меток в словаре: {labels_count}")
|
||||||
print(f" Перекодировано инструкций: {reencoded_count}")
|
print(f" Перекодировано инструкций: {reencoded_count}")
|
||||||
if error_count:
|
if error_count:
|
||||||
print(f" Ошибок: {error_count}")
|
print(f" Ошибок: {error_count}")
|
||||||
|
else:
|
||||||
|
print(f" Ошибок: нет")
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|
@ -240,21 +217,26 @@ def main():
|
||||||
print(f"\n=== Четвёртый проход КВС ===")
|
print(f"\n=== Четвёртый проход КВС ===")
|
||||||
print(f"Чтение CSV: {csv_file}")
|
print(f"Чтение CSV: {csv_file}")
|
||||||
|
|
||||||
# Читаем CSV
|
|
||||||
headers, entries = read_csv(csv_file)
|
headers, entries = read_csv(csv_file)
|
||||||
|
|
||||||
print(f"\n--- Сбор меток из CSV ---")
|
print(f"\n--- Сбор меток из CSV ---")
|
||||||
collect_labels_from_csv(entries, headers)
|
collect_labels_from_csv(entries, headers)
|
||||||
print(f"Найдено меток: {len(labels)}")
|
print(f"Найдено меток: {len(labels)}")
|
||||||
|
|
||||||
|
if labels:
|
||||||
|
print(f"\n--- Примеры меток (виртуальные адреса) ---")
|
||||||
|
for i, name in enumerate(sorted(labels.keys())[:10]):
|
||||||
|
print(f" {name} -> 0x{labels[name]:08x}")
|
||||||
|
if len(labels) > 10:
|
||||||
|
print(f" ... и ещё {len(labels) - 10}")
|
||||||
|
|
||||||
print(f"\n--- Перекодирование инструкций ---")
|
print(f"\n--- Перекодирование инструкций ---")
|
||||||
reencoded_count, error_count = reencode_instructions(entries, headers)
|
reencoded_count, error_count = reencode_instructions(entries, headers)
|
||||||
|
|
||||||
print_statistics(reencoded_count, error_count)
|
print_statistics(reencoded_count, error_count, len(labels))
|
||||||
|
|
||||||
# Сохраняем результат
|
|
||||||
save_csv(csv_file, headers, entries)
|
save_csv(csv_file, headers, entries)
|
||||||
print(f"\nCSV сохранен: {csv_file}")
|
print(f"\nCSV сохранён: {csv_file}")
|
||||||
print(f"Колонка 'рассчитанный_байт' обновлена")
|
print(f"Колонка 'рассчитанный_байт' обновлена")
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
204
тесты/сложный_тест.квс
Normal file
204
тесты/сложный_тест.квс
Normal file
|
|
@ -0,0 +1,204 @@
|
||||||
|
; сложный_тест9.квс
|
||||||
|
; Тест: запутанные переходы, крякмис
|
||||||
|
|
||||||
|
.текст
|
||||||
|
.глобал _start
|
||||||
|
|
||||||
|
_start:
|
||||||
|
; Инициализация регистров
|
||||||
|
переместить_имм раикс, 10 ; rax = 10
|
||||||
|
переместить_имм рбикс, 5 ; rbx = 5
|
||||||
|
переместить_имм рсикс, 10 ; rcx = 10 (для проверки ZF в jz)
|
||||||
|
|
||||||
|
; ПЕРВЫЙ ПЕРЕХОД: короткий_переход_если_не_ноль
|
||||||
|
; ZF=0 (так как rax=10), значит jnz сработает
|
||||||
|
; Прыгаем к метке 'проверка_2', пропуская мертвый_код_1
|
||||||
|
короткий_переход_если_не_ноль проверка_2
|
||||||
|
|
||||||
|
; --- МЕРТВЫЙ КОД 1 ---
|
||||||
|
; Этот код НЕ должен выполниться
|
||||||
|
переместить_имм раикс, 1
|
||||||
|
переместить_имм рдиай, 1
|
||||||
|
переместить_имм рсиай, msg_dead_1
|
||||||
|
переместить_имм рдикс, len_msg_dead_1
|
||||||
|
вызов_системы
|
||||||
|
; ---------------------
|
||||||
|
|
||||||
|
проверка_2:
|
||||||
|
; ДОПОЛНИТЕЛЬНЫЙ ПЕРЕХОД 1: "Два шага вперед" - короткий_переход через мертвый_код_2 и мертвый_код_3
|
||||||
|
; Прыгаем к проверка_4, минуя мертвый_код_2 и мертвый_код_3
|
||||||
|
короткий_переход проверка_4
|
||||||
|
|
||||||
|
; --- МЕРТВЫЙ КОД 2 ---
|
||||||
|
; Этот код НЕ должен выполниться из-за прыжка выше
|
||||||
|
переместить_имм раикс, 1
|
||||||
|
переместить_имм рдиай, 1
|
||||||
|
переместить_имм рсиай, msg_dead_2
|
||||||
|
переместить_имм рдикс, len_msg_dead_2
|
||||||
|
вызов_системы
|
||||||
|
; ---------------------
|
||||||
|
|
||||||
|
мертвый_код_3:
|
||||||
|
; ЖИВОЙ КОД 3: Этот код выполнится благодаря прыжку "назад"
|
||||||
|
; Выведем сообщение, чтобы убедиться, что он выполнился
|
||||||
|
переместить_имм раикс, 1
|
||||||
|
переместить_имм рдиай, 1
|
||||||
|
переместить_имм рсиай, msg_live_from_3
|
||||||
|
переместить_имм рдикс, len_msg_live_from_3
|
||||||
|
вызов_системы
|
||||||
|
; ДОПОЛНИТЕЛЬНЫЙ ПЕРЕХОД 3: "Четыре вперед" - переход через мертвый_код_4, 5, 6, 7
|
||||||
|
; Цель слишком далеко для короткого перехода. Используем длинный.
|
||||||
|
; Прыгаем к проверка_8
|
||||||
|
переход проверка_8
|
||||||
|
; ---------------------
|
||||||
|
|
||||||
|
проверка_4:
|
||||||
|
; ЧЕТВЁРТЫЙ ПЕРЕХОД: короткий_переход_если_больше
|
||||||
|
; Сравниваем rax (10) и rbx (5) -> rax > rbx, ZF=0, SF=0, OF=0
|
||||||
|
сравнить раикс, рбикс
|
||||||
|
; Условие jg: ZF=0 (истина) И SF=OF (0=0, истина). jg СРАБОТАЕТ.
|
||||||
|
; Мы хотим прыгнуть МИМО мертвого кода 4, если jg сработает (т.е. если rax > rbx).
|
||||||
|
короткий_переход_если_больше мимо_мертвого_кода_4
|
||||||
|
; --- МЕРТВЫЙ КОД 4 ---
|
||||||
|
; Этот код НЕ должен выполниться (так как jg сработал)
|
||||||
|
переместить_имм раикс, 1
|
||||||
|
переместить_имм рдиай, 1
|
||||||
|
переместить_имм рсиай, msg_dead_4
|
||||||
|
переместить_имм рдикс, len_msg_dead_4
|
||||||
|
вызов_системы
|
||||||
|
; ---------------------
|
||||||
|
мимо_мертвого_кода_4:
|
||||||
|
|
||||||
|
; ДОПОЛНИТЕЛЬНЫЙ ПЕРЕХОД 2: "Один назад" - короткий_переход к мертвому_коду_3 (делая его живым)
|
||||||
|
короткий_переход мертвый_код_3
|
||||||
|
|
||||||
|
; --- МЕРТВЫЙ КОД 5 ---
|
||||||
|
; Этот код НЕ должен выполниться
|
||||||
|
переместить_имм раикс, 1
|
||||||
|
переместить_имм рдиай, 1
|
||||||
|
переместить_имм рсиай, msg_dead_5
|
||||||
|
переместить_имм рдикс, len_msg_dead_5
|
||||||
|
вызов_системы
|
||||||
|
; ---------------------
|
||||||
|
|
||||||
|
; --- МЕРТВЫЙ КОД 6 ---
|
||||||
|
; Этот код НЕ должен выполниться
|
||||||
|
переместить_имм раикс, 1
|
||||||
|
переместить_имм рдиай, 1
|
||||||
|
переместить_имм рсиай, msg_dead_6
|
||||||
|
переместить_имм рдикс, len_msg_dead_6
|
||||||
|
вызов_системы
|
||||||
|
; ---------------------
|
||||||
|
|
||||||
|
; --- МЕРТВЫЙ КОД 7 ---
|
||||||
|
; Этот код НЕ должен выполниться
|
||||||
|
переместить_имм раикс, 1
|
||||||
|
переместить_имм рдиай, 1
|
||||||
|
переместить_имм рсиай, msg_dead_7
|
||||||
|
переместить_имм рдикс, len_msg_dead_7
|
||||||
|
вызов_системы
|
||||||
|
; ---------------------
|
||||||
|
|
||||||
|
проверка_8:
|
||||||
|
; СЕДЬМОЙ ПЕРЕХОД: короткий_переход_если_перенос
|
||||||
|
; Выполним вычитание, которое вызовет перенос: rbx - rax = 5 - 10
|
||||||
|
переместить_имм рбикс, 5 ; rbx = 5
|
||||||
|
переместить_имм раикс, 10 ; rax = 10
|
||||||
|
; rbx - rax = 5 - 10 -> CF=1
|
||||||
|
вычесть рбикс, раикс ; rbx = rbx - rax = 5 - 10. Это вызовет перенос (CF=1).
|
||||||
|
; Условие jc: CF=1. CF=1. jc СРАБОТАЕТ.
|
||||||
|
; Мы хотим прыгнуть МИМО мертвого кода 8, если jc сработает (т.е. если был перенос).
|
||||||
|
короткий_переход_если_перенос мимо_мертвого_кода_8
|
||||||
|
; --- МЕРТВЫЙ КОД 8 ---
|
||||||
|
; Этот код НЕ должен выполниться (так как jc сработал)
|
||||||
|
переместить_имм раикс, 1
|
||||||
|
переместить_имм рдиай, 1
|
||||||
|
переместить_имм рсиай, msg_dead_8
|
||||||
|
переместить_имм рдикс, len_msg_dead_8
|
||||||
|
вызов_системы
|
||||||
|
; ---------------------
|
||||||
|
|
||||||
|
мимо_мертвого_кода_8:
|
||||||
|
|
||||||
|
; ВОСЬМОЙ ПЕРЕХОД: короткий_переход_если_нет_переноса
|
||||||
|
; Убедимся, что CF=0. Выполним операцию, которая сбросит CF.
|
||||||
|
сравнить раикс, раикс ; CF = 0 (так как rax - rax = 0, без переноса)
|
||||||
|
; Условие jnc: CF=0. CF=0. jnc СРАБОТАЕТ.
|
||||||
|
; Мы хотим прыгнуть МИМО мертвого кода 9, если jnc сработает (т.е. если НЕ было переноса).
|
||||||
|
короткий_переход_если_нет_переноса мимо_мертвого_кода_9
|
||||||
|
; --- МЕРТВЫЙ КОД 9 ---
|
||||||
|
; Этот код НЕ должен выполниться (так как jnc сработал)
|
||||||
|
переместить_имм раикс, 1
|
||||||
|
переместить_имм рдиай, 1
|
||||||
|
переместить_имм рсиай, msg_dead_9
|
||||||
|
переместить_имм рдикс, len_msg_dead_9
|
||||||
|
вызов_системы
|
||||||
|
; ---------------------
|
||||||
|
|
||||||
|
мимо_мертвого_кода_9:
|
||||||
|
|
||||||
|
; ДЕВЯТЫЙ ПЕРЕХОД: короткий_переход (безусловный)
|
||||||
|
; Просто прыгаем мимо мертвого кода 10.
|
||||||
|
короткий_переход мимо_мертвого_кода_10
|
||||||
|
; --- МЕРТВЫЙ КОД 10 ---
|
||||||
|
; Этот код НЕ должен выполниться (так как jmp сработал)
|
||||||
|
переместить_имм раикс, 1
|
||||||
|
переместить_имм рдиай, 1
|
||||||
|
переместить_имм рсиай, msg_dead_10
|
||||||
|
переместить_имм рдикс, len_msg_dead_10
|
||||||
|
вызов_системы
|
||||||
|
; ---------------------
|
||||||
|
|
||||||
|
мимо_мертвого_кода_10:
|
||||||
|
|
||||||
|
; --- ВЫВОД ЦЕЛЕВОГО СООБЩЕНИЯ ---
|
||||||
|
вывести_сообщение:
|
||||||
|
переместить_имм раикс, 1
|
||||||
|
переместить_имм рдиай, 1
|
||||||
|
переместить_имм рсиай, msg_success
|
||||||
|
переместить_имм рдикс, len_msg_success
|
||||||
|
вызов_системы
|
||||||
|
|
||||||
|
; --- ЗАВЕРШЕНИЕ ---
|
||||||
|
переместить_имм раикс, 60
|
||||||
|
переместить_имм рдиай, 0
|
||||||
|
вызов_системы
|
||||||
|
|
||||||
|
.данные
|
||||||
|
; Перемешиваем строки и константы
|
||||||
|
; "Живой из 3!\n" = 8 букв * 2 + 1 (!) + 2 (\n) = 16 + 3 = 19 байт на содержимое. len = 19
|
||||||
|
msg_live_from_3: .строка_нуль "Живой из 3!\n"
|
||||||
|
.константа len_msg_live_from_3 = 19
|
||||||
|
; "Успех!\n" = 5 букв * 2 + 1 (!) + 2 (\n) = 13 байт на содержимое. len = 13
|
||||||
|
msg_success: .строка_нуль "Успех!\n"
|
||||||
|
.константа len_msg_success = 13
|
||||||
|
; "Мертвый код 10!" = 7 букв * 2 + 4 символа * 1 = 14 + 4 = 18 байт на содержимое. len = 18
|
||||||
|
msg_dead_10: .строка_нуль "Мертвый код 10!"
|
||||||
|
.константа len_msg_dead_10 = 18
|
||||||
|
; "Мертвый код 9!" = 7 букв * 2 + 4 символа * 1 = 14 + 4 = 18 байт на содержимое. len = 18
|
||||||
|
msg_dead_9: .строка_нуль "Мертвый код 9!"
|
||||||
|
.константа len_msg_dead_9 = 18
|
||||||
|
; "Мертвый код 8!" = 7 букв * 2 + 4 символа * 1 = 14 + 4 = 18 байт на содержимое. len = 18
|
||||||
|
msg_dead_8: .строка_нуль "Мертвый код 8!"
|
||||||
|
.константа len_msg_dead_8 = 18
|
||||||
|
; "Мертвый код 7!" = 7 букв * 2 + 4 символа * 1 = 14 + 4 = 18 байт на содержимое. len = 18
|
||||||
|
msg_dead_7: .строка_нуль "Мертвый код 7!"
|
||||||
|
.константа len_msg_dead_7 = 18
|
||||||
|
; "Мертвый код 6!" = 7 букв * 2 + 4 символа * 1 = 14 + 4 = 18 байт на содержимое. len = 18
|
||||||
|
msg_dead_6: .строка_нуль "Мертвый код 6!"
|
||||||
|
.константа len_msg_dead_6 = 18
|
||||||
|
; "Мертвый код 5!" = 7 букв * 2 + 4 символа * 1 = 14 + 4 = 18 байт на содержимое. len = 18
|
||||||
|
msg_dead_5: .строка_нуль "Мертвый код 5!"
|
||||||
|
.константа len_msg_dead_5 = 18
|
||||||
|
; "Мертвый код 4!" = 7 букв * 2 + 4 символа * 1 = 14 + 4 = 18 байт на содержимое. len = 18
|
||||||
|
msg_dead_4: .строка_нуль "Мертвый код 4!"
|
||||||
|
.константа len_msg_dead_4 = 18
|
||||||
|
; "Мертвый код 3!" = 7 букв * 2 + 4 символа * 1 = 14 + 4 = 18 байт на содержимое. len = 18
|
||||||
|
msg_dead_3: .строка_нуль "Мертвый код 3!"
|
||||||
|
.константа len_msg_dead_3 = 18
|
||||||
|
; "Мертвый код 2!" = 7 букв * 2 + 4 символа * 1 = 14 + 4 = 18 байт на содержимое. len = 18
|
||||||
|
msg_dead_2: .строка_нуль "Мертвый код 2!"
|
||||||
|
.константа len_msg_dead_2 = 18
|
||||||
|
; "Мертвый код 1!" = 7 букв * 2 + 4 символа * 1 = 14 + 4 = 18 байт на содержимое. len = 18
|
||||||
|
msg_dead_1: .строка_нуль "Мертвый код 1!"
|
||||||
|
.константа len_msg_dead_1 = 18
|
||||||
Loading…
Reference in a new issue