kvs/тесты/bss_bug.txt

136 lines
6.4 KiB
Plaintext
Raw Normal View History

2026-05-17 15:18:35 +03:00
## Исходник
```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` для меток `.бнд`.