From e54fb6a479cb2c267e608a55e071d95742a701f8 Mon Sep 17 00:00:00 2001 From: mzhoot Date: Sun, 17 May 2026 16:15:27 +0300 Subject: [PATCH] =?UTF-8?q?=D0=B8=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=81=D0=BC=D0=B5=D1=89=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D1=8F=20.bss?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kvs_builder.py | 6 ++--- kvs_pass1.py | 23 +++++++++++++--- kvs_pass2.py | 18 +++++++++---- kvs_pass2_encoder_mutsize.py | 9 +++---- тесты/bss_bug.txt | 47 ++++++++++++++++++++++++++++++++- тесты/test_bss_only.квс | 45 +++++++++++++++++++++++++++++++ 6 files changed, 130 insertions(+), 18 deletions(-) create mode 100644 тесты/test_bss_only.квс diff --git a/kvs_builder.py b/kvs_builder.py index ae0b95c..13e9163 100644 --- a/kvs_builder.py +++ b/kvs_builder.py @@ -125,10 +125,10 @@ def create_elf(text_bytes, data_bytes, pass1_data, labels, output_file): ph1 = phdr(1, 5, offset_text, vaddr_text, len(text_bytes), align_up(len(text_bytes), PAGE_SIZE)) if bnd_size > 0: - # Сегмент данных включает .data + .bss - # p_filesz — только данные в файле, p_memsz — данные + BSS в памяти data_segment_filesz = len(data_bytes) - data_segment_memsz = align_up(len(data_bytes) + bnd_size, PAGE_SIZE) + # memsz должно покрывать от vaddr_data до конца .bss + bss_end = vaddr_bnd + bnd_size + data_segment_memsz = align_up(bss_end - vaddr_data, PAGE_SIZE) ph2 = phdr(1, 6, offset_data, vaddr_data, data_segment_filesz, data_segment_memsz) else: ph2 = phdr(1, 6, offset_data, vaddr_data, len(data_bytes), align_up(len(data_bytes), PAGE_SIZE)) diff --git a/kvs_pass1.py b/kvs_pass1.py index 72733b9..255cea4 100644 --- a/kvs_pass1.py +++ b/kvs_pass1.py @@ -316,8 +316,8 @@ class Pass1: offset_data = align_up(offset_text + text_size, PAGE_SIZE) vaddr_text = text_vaddr_base vaddr_data = align_up(vaddr_text + text_size, PAGE_SIZE) - #vaddr_bnd = align_up(vaddr_data + data_size, PAGE_SIZE) - vaddr_bnd = align_up(vaddr_data + max(data_size, 1), PAGE_SIZE) + # .бнд всегда на следующей странице после .data + vaddr_bnd = vaddr_data + PAGE_SIZE comment_size = len("Сборщик КВС".encode('utf-8')) + 1 offset_comment = align_up(offset_data + data_size, 1) @@ -370,4 +370,21 @@ if __name__ == "__main__": layout = pass1.calculate_layout() write_pass1(layout, pass1.labels, pass1.label_sections, pass1.symbols, sys.argv[2]) - print(f"Проход 1: text_size={layout['text_size']}, data_size={layout['data_size']}, bnd_size={layout['bnd_size']}") \ No newline at end of file + + print(f"Проход 1:") + print(f" .text: размер={layout['text_size']} байт, смещение_в_файле=0x{layout['offset_text']:x}, виртуальный_адрес=0x{layout['vaddr_text']:x}") + print(f" .data: размер={layout['data_size']} байт, смещение_в_файле=0x{layout['offset_data']:x}, виртуальный_адрес=0x{layout['vaddr_data']:x}") + print(f" .бнд: размер={layout['bnd_size']} байт, виртуальный_адрес=0x{layout['vaddr_bnd']:x}") + print(f" entry_point: {layout['entry_point']}") + print(f" метки:") + for label, pos in pass1.labels.items(): + sec = pass1.label_sections.get(label, ".text") + if sec == ".text": + addr = layout['vaddr_text'] + pos + elif sec == ".data": + addr = layout['vaddr_data'] + pos + elif sec == ".бнд": + addr = layout['vaddr_bnd'] + pos + else: + addr = pos + print(f" {label}: секция={sec}, смещение={pos}, адрес=0x{addr:x}") \ No newline at end of file diff --git a/kvs_pass2.py b/kvs_pass2.py index 1fb8457..9071b44 100644 --- a/kvs_pass2.py +++ b/kvs_pass2.py @@ -65,7 +65,7 @@ def read_pass1(input_file): if parts[0] == "PARAM": key = parts[1] value = parts[2] - if value.isdigit(): + if value.isdigit() or (value.startswith('-') and value[1:].isdigit()): value = int(value) data[key] = value elif parts[0] == "LABEL": @@ -182,8 +182,8 @@ class Pass2: self.label_sections = label_sections self.symbols = symbols self.vaddr_text = pass1_data["vaddr_text"] - text_size = pass1_data["text_size"] - self.vaddr_data = align_up(self.vaddr_text + text_size, PAGE_SIZE) + self.vaddr_data = pass1_data.get("vaddr_data", align_up(self.vaddr_text + pass1_data["text_size"], PAGE_SIZE)) + self.vaddr_bnd = pass1_data.get("vaddr_bnd", self.vaddr_data + PAGE_SIZE) self.position = {".text": 0, ".data": 0} self.current_section = ".text" self.csv_lines = [] @@ -211,7 +211,14 @@ class Pass2: op_str = operands[1] if op_str in self.labels: sec = self.label_sections[op_str] - addr = self.labels[op_str] + (self.vaddr_text if sec == ".text" else self.vaddr_data) + if sec == ".text": + addr = self.labels[op_str] + self.vaddr_text + elif sec == ".data": + addr = self.labels[op_str] + self.vaddr_data + elif sec == ".бнд": + addr = self.labels[op_str] + self.vaddr_bnd + else: + addr = self.labels[op_str] + self.vaddr_text return hex(addr) elif op_str in self.symbols: return hex(self.symbols[op_str]) @@ -291,7 +298,8 @@ class Pass2: current_pos = self.position[sec] code = encode_instruction(mnemonic, operands, self.labels, self.label_sections, - self.symbols, self.vaddr_text, self.vaddr_data, current_pos) + self.symbols, self.vaddr_text, self.vaddr_data, current_pos, + self.vaddr_bnd) target_addr = self.get_target_addr(mnemonic, operands) diff --git a/kvs_pass2_encoder_mutsize.py b/kvs_pass2_encoder_mutsize.py index 0d3b873..91ebf79 100644 --- a/kvs_pass2_encoder_mutsize.py +++ b/kvs_pass2_encoder_mutsize.py @@ -55,10 +55,7 @@ def parse_operand(operand, labels, label_sections, symbols, vaddr_text, vaddr_da elif section == '.data': return labels[operand] + vaddr_data elif section == '.бнд': - if vaddr_bnd is not None: - return labels[operand] + vaddr_bnd - else: - return labels[operand] + vaddr_data + return labels[operand] + vaddr_bnd else: return labels[operand] + vaddr_text if operand in symbols: @@ -111,7 +108,7 @@ def parse_memory_operand(operand_str, labels, label_sections, vaddr_text, vaddr_ elif section == '.data': base = vaddr_data elif section == '.бнд': - base = vaddr_bnd if vaddr_bnd is not None else vaddr_data + base = vaddr_bnd else: base = vaddr_text addr = labels[value] + base @@ -140,7 +137,7 @@ def parse_memory_operand(operand_str, labels, label_sections, vaddr_text, vaddr_ elif section == '.data': base = vaddr_data elif section == '.бнд': - base = vaddr_bnd if vaddr_bnd is not None else vaddr_data + base = vaddr_bnd else: base = vaddr_text addr = labels[content] + base diff --git a/тесты/bss_bug.txt b/тесты/bss_bug.txt index 8cb9439..0a39a2b 100644 --- a/тесты/bss_bug.txt +++ b/тесты/bss_bug.txt @@ -88,4 +88,49 @@ _start: ## Как проверить -Если закомментировать Тест 3 (строки с `рсикс` и `неиниц_бнд`), код возврата станет `66` — баг исчезает, потому что `0x402000` не перезаписывается. \ No newline at end of file +Если закомментировать Тест 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` для меток `.бнд`. \ No newline at end of file diff --git a/тесты/test_bss_only.квс b/тесты/test_bss_only.квс new file mode 100644 index 0000000..5737c6d --- /dev/null +++ b/тесты/test_bss_only.квс @@ -0,0 +1,45 @@ +.текст +.глобал _start + +_start: + ; ============================================= + ; ТЕСТ 1: Абсолютная адресация в .бнд + ; ============================================= + переместить_имм раикс, 0x42 + сохранить [абс_перем], раикс + + ; ============================================= + ; ТЕСТ 2: Косвенная адресация в .бнд + ; ============================================= + переместить_имм рбикс, косв_перем + переместить_имм раикс, 0x99 + сохранить [рбикс], раикс + + ; ============================================= + ; ТЕСТ 3: Ещё одна косвенная адресация в .бнд + ; ============================================= + переместить_имм рсикс, ещё_перем + переместить_имм раикс, 0x77 + сохранить [рсикс], раикс + + ; ============================================= + ; Читаем всё обратно + ; ============================================= + загрузить р8, [абс_перем] + загрузить р9, [рбикс] + загрузить р10, [рсикс] + + ; ============================================= + ; ЗАВЕРШЕНИЕ: возвращаем из абс_перем + ; ============================================= + загрузить рдиай, [абс_перем] + переместить_имм раикс, 60 + вызов_системы + +.бнд +абс_перем: + .резб 1 +косв_перем: + .резб 1 +ещё_перем: + .резб 8 \ No newline at end of file