255 lines
12 KiB
Plaintext
255 lines
12 KiB
Plaintext
```markdown
|
||
===========================
|
||
ПЛАН РЕАЛИЗАЦИИ СЛОЖНОЙ АДРЕСАЦИИ (ПОЛНАЯ ВЕРСИЯ)
|
||
===========================
|
||
|
||
## СТАТУС: ЧАСТИЧНО РЕАЛИЗОВАНО (v2.0)
|
||
|
||
### Уже реализовано:
|
||
- ✅ Лексер: токены `[`, `]`, `NUMBER`
|
||
- ✅ Парсер: распознавание `[метка]` и `[число]`
|
||
- ✅ Pass1: корректный расчёт размера (7 байт для MOV с памятью)
|
||
- ✅ Pass2: RIP-relative кодирование для абсолютной адресации
|
||
- ✅ Поддержка меток в операндах памяти `[переменная]`
|
||
- ✅ Рефакторинг: `kvs_pass2_encoder.py` отдельно
|
||
|
||
---
|
||
|
||
## 1. Общая схема изменений по модулям
|
||
|
||
| Модуль | Что меняется | Сложность | Статус |
|
||
|--------|--------------|-----------|--------|
|
||
| `kvs_lexer.py` | новые токены: `[`, `]`, `+`, `-`, `*`, `NUMBER` | низкая | ✅ ГОТОВ |
|
||
| `kvs_parser.py` | новая логика операндов: `parse_operand()`, `parse_memory_operand()` | высокая | ✅ ГОТОВ (базово) |
|
||
| `kvs_data.py` | активация и уточнение форматов инструкций | средняя | ⚠️ ТРЕБУЕТ ДОРАБОТКИ |
|
||
| `kvs_pass1.py` | динамический рассчёт размера инструкций с памятью | высокая | ✅ ГОТОВ (для абсолютной) |
|
||
| `kvs_pass2_encoder.py` | разбор адресации → ModR/M + SIB + disp, генерация кода | очень высокая | ⚠️ ЧАСТИЧНО (только абсолютная) |
|
||
|
||
---
|
||
|
||
## 2. Детальный план по шагам (в порядке реализации)
|
||
|
||
### Шаг 1 — Лексер (`kvs_lexer.py`) ✅ РЕАЛИЗОВАН
|
||
|
||
**Что сделано:**
|
||
- Добавлены токены: `LBRACKET` (`[`), `RBRACKET` (`]`), `PLUS` (`+`), `MINUS` (`-`), `STAR` (`*`), `NUMBER`
|
||
- Числа отделены от слов (поддержка десятичных, шестнадцатеричных, отрицательных)
|
||
|
||
**Результат:** новые типы токенов на выходе лексера.
|
||
|
||
---
|
||
|
||
### Шаг 2 — Парсер (`kvs_parser.py`) ✅ РЕАЛИЗОВАН (базово)
|
||
|
||
**Что сделано:**
|
||
|
||
2.1. Реализован `parse_operand()`:
|
||
- Если токен `LBRACKET` → вызывает `parse_memory_operand()`
|
||
- Иначе → возвращает значение токена (регистр/число/метка/строка)
|
||
|
||
2.2. Реализован `parse_memory_operand()`:
|
||
- Разбирает содержимое между `[` и `]`
|
||
- Поддерживает: `регистр`, `число`, `метка`
|
||
- Возвращает строку вида `[раикс + рсикс*8 + 16]` (структура сохраняется)
|
||
|
||
2.3. **Ограничения текущей реализации:**
|
||
- Поддерживается только простая форма `[метка]` и `[число]`
|
||
- Сложные выражения `[reg + reg*scale + disp]` парсятся, но не кодируются
|
||
|
||
**Результат:** AST содержит операнды памяти в каноническом строковом виде.
|
||
|
||
---
|
||
|
||
### Шаг 3 — Данные инструкций (`kvs_data.py`) ⚠️ ТРЕБУЕТ ДОРАБОТКИ
|
||
|
||
**Что нужно сделать:**
|
||
|
||
3.1. Активировать (или добавить) записи для:
|
||
|
||
| Мнемоника | Opcode | Тип (формат) |
|
||
|-----------|--------|--------------|
|
||
| `загрузить` | `48 8B` | `mov_reg_mem` |
|
||
| `сохранить` | `48 89` | `mov_mem_reg` |
|
||
| `загрузить_байт_из_памяти` | `8A` | `mov_reg8_mem` |
|
||
| `сохранить_байт` | `88` | `mov_mem8_reg8` |
|
||
| `загрузить_адрес` | `48 8D` | `lea` |
|
||
| `переместить_с_нулями` | `48 0F B6` | `movzx` |
|
||
| `переместить_со_знаком` | `48 0F BE` | `movsx` |
|
||
| `втолкнуть_из_памяти` | `FF /6` | `push_mem` |
|
||
| `вытолкнуть_в_память` | `8F /0` | `pop_mem` |
|
||
| `обменять_с_памятью` | `48 87` | `xchg_mem` |
|
||
|
||
3.2. **Статус:** записи присутствуют в `kvs_data.py`, но используются не все.
|
||
|
||
---
|
||
|
||
### Шаг 4 — Первый проход (`kvs_pass1.py`) ✅ РЕАЛИЗОВАН (для абсолютной)
|
||
|
||
**Что сделано:**
|
||
|
||
4.1. Написана функция `estimate_memory_operand_size(operand_str)`:
|
||
- Парсит строку `[раикс + рсикс*8 + 16]`
|
||
- Определяет наличие SIB, размер смещения
|
||
|
||
4.2. Модифицирована `estimate_size()`:
|
||
- Для инструкций `загрузить`, `сохранить`, `загрузить_адрес` возвращает `7` (REX + opcode + ModRM + disp32)
|
||
|
||
**Ограничения:**
|
||
- Для сложных форм адресации размер не рассчитывается динамически
|
||
|
||
---
|
||
|
||
### Шаг 5 — Второй проход (`kvs_pass2_encoder.py`) ⚠️ ЧАСТИЧНО РЕАЛИЗОВАН
|
||
|
||
#### 5.1. Структура данных для режима адресации ⚠️ НЕ РЕАЛИЗОВАНА
|
||
|
||
Нужно создать класс/словарь `AddressingMode`:
|
||
- `has_base` (bool)
|
||
- `base_reg` (int 0–15 или None)
|
||
- `has_index` (bool)
|
||
- `index_reg` (int 0–15)
|
||
- `scale` (1,2,4,8)
|
||
- `has_disp` (bool)
|
||
- `disp_value` (int)
|
||
- `disp_size` (1 или 4)
|
||
|
||
#### 5.2. Парсер адресации ⚠️ ЧАСТИЧНО РЕАЛИЗОВАН
|
||
|
||
Реализована `parse_memory_operand()` в `kvs_pass2_encoder.py`:
|
||
- Поддерживает `[число]` и `[метка]`
|
||
- **Нет поддержки:** `[reg]`, `[reg+disp]`, `[reg+reg*scale]`
|
||
|
||
#### 5.3. Кодирование ModR/M ⚠️ ЧАСТИЧНО РЕАЛИЗОВАНО
|
||
|
||
Функция `encode_modrm_reg_mem_absolute()`:
|
||
- Использует `mod=00, r/m=101` для RIP-relative
|
||
- **Нет поддержки:** других режимов адресации
|
||
|
||
#### 5.4. Кодирование SIB ❌ НЕ РЕАЛИЗОВАНО
|
||
|
||
Функция `encode_sib()` отсутствует.
|
||
|
||
#### 5.5. Кодирование смещения ⚠️ ЧАСТИЧНО РЕАЛИЗОВАНО
|
||
|
||
`encode_displacement()` использует `struct.pack('<i', offset)` для disp32.
|
||
|
||
#### 5.6. Генераторы инструкций ⚠️ ЧАСТИЧНО РЕАЛИЗОВАНЫ
|
||
|
||
| Функция | Статус |
|
||
|---------|--------|
|
||
| `encode_mov_reg_mem` | ✅ Реализована (только абсолютная адресация) |
|
||
| `encode_mov_mem_reg` | ✅ Реализована (только абсолютная адресация) |
|
||
| `encode_lea` | ⚠️ Есть старая версия, требует доработки |
|
||
| `encode_mov_reg8_mem` | ❌ Не реализована |
|
||
| `encode_mov_mem8_reg8` | ❌ Не реализована |
|
||
| `encode_movzx` | ❌ Не реализована |
|
||
| `encode_movsx` | ❌ Не реализована |
|
||
| `encode_push_mem` | ❌ Не реализована |
|
||
| `encode_pop_mem` | ❌ Не реализована |
|
||
| `encode_xchg_mem` | ❌ Не реализована |
|
||
|
||
#### 5.7. Диспетчер ✅ РЕАЛИЗОВАН
|
||
|
||
`encode_instruction()` содержит ветки для всех инструкций, включая:
|
||
- `загрузить`, `сохранить`, `загрузить_адрес` (с памятью)
|
||
- `переместить_имм`, `переместить` (без памяти)
|
||
|
||
---
|
||
|
||
### Шаг 6 — Тестирование
|
||
|
||
Тесты для проверки (поэтапно):
|
||
|
||
| Тест | Что проверяет | Статус |
|
||
|------|---------------|--------|
|
||
| `загрузить раикс, [число]` | Абсолютная адресация | ✅ ПРОЙДЕН |
|
||
| `сохранить [число], раикс` | Абсолютная адресация (запись) | ✅ ПРОЙДЕН |
|
||
| `загрузить раикс, [метка]` | Адресация по метке | ✅ ПРОЙДЕН |
|
||
| `сохранить [метка], раикс` | Адресация по метке (запись) | ✅ ПРОЙДЕН |
|
||
| `загрузить раикс, [рбикс]` | Косвенная адресация | ❌ НЕ РЕАЛИЗОВАНО |
|
||
| `загрузить раикс, [рбикс + 8]` | Со смещением | ❌ НЕ РЕАЛИЗОВАНО |
|
||
| `загрузить раикс, [рбикс + рсикс*8]` | С индексом | ❌ НЕ РЕАЛИЗОВАНО |
|
||
| `загрузить раикс, [рбикс + рсикс*8 + 16]` | Полная SIB | ❌ НЕ РЕАЛИЗОВАНО |
|
||
| `загрузить_адрес р11, [переменная]` | LEA с меткой | ❌ НЕ РЕАЛИЗОВАНО |
|
||
|
||
---
|
||
|
||
### Шаг 7 — Стандартная библиотека (отложено)
|
||
|
||
После полной реализации адресации:
|
||
|
||
| Файл | Содержание |
|
||
|------|------------|
|
||
| `libkvs.квс` | `malloc`, `free`, `strlen`, `strcmp`, `memcpy`, `putchar`, `getchar`, `printf` |
|
||
| `libkvs_data.квс` | статические данные для библиотеки |
|
||
|
||
---
|
||
|
||
## 3. Следующие шаги (приоритеты)
|
||
|
||
### 🔴 Приоритет 1 (критично):
|
||
1. **Косвенная адресация `[reg]`** — основа для всех остальных форм
|
||
- Нужно: `mod=00, r/m=reg` (без SIB, без disp)
|
||
|
||
### 🟡 Приоритет 2 (важно):
|
||
2. **Адресация со смещением `[reg + disp]`**
|
||
- disp8 для малых смещений (`mod=01`)
|
||
- disp32 для больших (`mod=10`)
|
||
|
||
### 🟢 Приоритет 3 (расширение):
|
||
3. **Сложная адресация с индексом `[reg + reg*scale]`**
|
||
- Требует SIB байта
|
||
4. **Полная SIB-адресация `[reg + reg*scale + disp]`**
|
||
5. **LEA для меток** `загрузить_адрес reg, [метка]`
|
||
6. **`.bss` секция** для неинициализированных данных
|
||
|
||
---
|
||
|
||
## 4. Итог: что получим на выходе
|
||
|
||
- ✅ **Лексер** выдаёт `LBRACKET`, `RBRACKET`, `PLUS`, `MINUS`, `STAR`, `NUMBER`
|
||
- ✅ **Парсер** понимает `[раикс + рсикс*8 - 16]`
|
||
- ✅ **Pass1** правильно считает размер инструкций с памятью (для абсолютной)
|
||
- ⚠️ **Pass2** генерирует код только для абсолютной адресации
|
||
- ⚠️ **ELF** содержит корректные инструкции x86-64 с RIP-relative
|
||
- ❌ **Библиотека** требует полной адресации
|
||
|
||
---
|
||
|
||
## 5. Зависимости между подзадачами
|
||
|
||
```
|
||
Лексер (шаг 1) ✅
|
||
↓
|
||
Парсер (шаг 2) ✅
|
||
↓
|
||
Данные инструкций (шаг 3) ⚠️
|
||
↓
|
||
Pass1 (шаг 4) ✅
|
||
↓
|
||
Pass2 (шаг 5):
|
||
5.1 → 5.2 → 5.3 → 5.4 → 5.5 ⚠️ ЧАСТИЧНО
|
||
↓
|
||
5.6 (для каждой мнемоники) ⚠️ ЧАСТИЧНО
|
||
↓
|
||
5.7 (диспетчер) ✅
|
||
↓
|
||
Тестирование (шаг 6) ⚠️ ЧАСТИЧНО
|
||
↓
|
||
Библиотека (шаг 7) ❌ ОТЛОЖЕНО
|
||
```
|
||
|
||
---
|
||
|
||
**Статус: v2.0 — абсолютная адресация реализована полностью.**
|
||
**Следующая цель: v3.0 — косвенная адресация `[reg]`.**
|
||
```
|
||
|
||
|
||
тестировать все директивы бнд
|
||
изучить работу с кучей
|
||
|
||
|
||
сохранить_байт и загрузить_байт_из_памяти есть в INSTRUCTIONS, но не реализованы в диспетчере encode_instruction
|
||
|