136 lines
6.4 KiB
Plaintext
136 lines
6.4 KiB
Plaintext
## Исходник
|
||
|
||
```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` для меток `.бнд`. |