## Исходник ```asm .текст .глобал _start _start: ; ТЕСТ 1: Абсолютная адресация в .data переместить_имм раикс, 0x42 сохранить [абс_данные], раикс ; запись 0x42 по адресу абс_данные (0x402000) ; ТЕСТ 2: Косвенная адресация в .data переместить_имм рбикс, косв_данные ; рбикс = адрес косв_данные (0x402001) переместить_имм раикс, 0x99 сохранить [рбикс], раикс ; запись 0x99 по адресу 0x402001 ; ТЕСТ 3: Косвенная адресация в .бнд переместить_имм рсикс, неиниц_бнд ; рсикс = адрес неиниц_бнд переместить_имм раикс, 0x77 сохранить [рсикс], раикс ; запись 0x77 по адресу неиниц_бнд ; Читаем всё обратно загрузить р8, [абс_данные] ; чтение из 0x402000 загрузить р9, [рбикс] ; чтение из 0x402001 загрузить р10, [рсикс] ; чтение из неиниц_бнд ; ЗАВЕРШЕНИЕ: возвращаем значение из абс_данные загрузить рдиай, [абс_данные] ; рдиай = значение из 0x402000 переместить_имм раикс, 60 ; номер системного вызова exit вызов_системы .данные абс_данные: .байт 0 косв_данные: .байт 0 .бнд неиниц_бнд: .резб 8 ``` ## Размещение секций в памяти ``` 0x401000 ─ .text (код) 0x402000 ─ .data ├── абс_данные (смещение 0): байт 0 └── косв_данные (смещение 1): байт 0 0x403000 ─ .бнд └── неиниц_бнд (смещение 0): 8 байт, ноль ``` ## Что подразумевается 1. **Тест 1** пишет `0x42` в `абс_данные` по адресу `0x402000`. 2. **Тест 2** пишет `0x99` в `косв_данные` по адресу `0x402001`. 3. **Тест 3** пишет `0x77` в `неиниц_бнд` по адресу **`0x403000`**. После этого: - `[0x402000]` содержит `0x42` - `[0x402001]` содержит `0x99` - `[0x403000]` содержит `0x77` Финал читает `[абс_данные]` = `[0x402000]` = `0x42` в `рдиай` и завершается. **Ожидаемый код возврата:** `66` (это `0x42`). ## Что происходит на самом деле **Фактический код возврата:** `119` (это `0x77`). ## Причина Инструкция `переместить_имм рсикс, неиниц_бнд` загружает в `рсикс` **неправильный адрес**. Вместо `0x403000` (адрес `.бнд`) регистр получает `0x402002` (адрес внутри `.data`). Это происходит потому, что при вычислении адреса метки `неиниц_бнд` компилятор ошибочно использует базовый адрес секции `.data` (`0x402000`) вместо базового адреса секции `.бнд` (`0x403000`). Смещение метки `неиниц_бнд` внутри `.бнд` равно `0`. Правильный расчёт должен быть: `0x403000 + 0 = 0x403000`. Но компилятор считает: `0x402000 + 0 = 0x402000`. ## Цепочка последствий 1. `рсикс` получает `0x402000` вместо `0x403000`. 2. `сохранить [рсикс], раикс` пишет `0x77` по адресу `0x402000` — **это ячейка `абс_данные`**. 3. Значение `0x42`, записанное в Тесте 1, **затирается** значением `0x77`. 4. Финал читает `[абс_данные]` и получает `0x77` вместо `0x42`. 5. Код возврата становится `119` вместо `66`. ## Как проверить Если закомментировать Тест 3 (строки с `рсикс` и `неиниц_бнд`), код возврата станет `66` — баг исчезает, потому что `0x402000` не перезаписывается. `vaddr_data` считается в **двух** местах: ### 1. `kvs_pass1.py` — метод `calculate_layout` ```python vaddr_text = text_vaddr_base # 0x401000 vaddr_data = align_up(vaddr_text + text_size, PAGE_SIZE) # 0x402000 vaddr_bnd = align_up(vaddr_data + data_size, PAGE_SIZE) # 0x402000 или 0x403000 ``` Эти значения записываются в pass1-файл как `PARAM:vaddr_text:...`, `PARAM:vaddr_data:...`, `PARAM:vaddr_bnd:...`. ### 2. `kvs_pass2.py` — конструктор `Pass2.__init__` ```python self.vaddr_text = pass1_data["vaddr_text"] # читает из pass1 self.vaddr_data = align_up(self.vaddr_text + text_size, PAGE_SIZE) # вычисляет заново ``` **Pass2 не читает `vaddr_data` из pass1, а вычисляет сам.** А `vaddr_bnd` не читает и не вычисляет вообще. ### 3. `kvs_builder.py` — функция `create_elf` ```python vaddr_data = align_up(vaddr_text + text_size, PAGE_SIZE) # вычисляет заново vaddr_bnd = pass1_data.get("vaddr_bnd", ...) # читает из pass1 ``` **Builder читает `vaddr_bnd` из pass1**, но энкодер (pass2) его не получает. --- ## Корень бага | Модуль | `vaddr_data` | `vaddr_bnd` | |--------|:-----------:|:----------:| | pass1 | вычисляет ✅ | вычисляет ✅ | | pass2 | вычисляет ✅ | **не читает** ❌ | | builder | вычисляет ✅ | читает из pass1 ✅ | | encoder (mutsize) | получает от pass2 ✅ | **не получает** ❌ | Pass2 не передаёт `vaddr_bnd` в энкодер, поэтому `parse_operand` получает `vaddr_bnd=None` и подставляет `vaddr_data` для меток `.бнд`.