добавление .bss

This commit is contained in:
mzhoot 2026-05-17 11:22:39 +03:00
parent ead2caead8
commit 5f7d212dbf
11 changed files with 328 additions and 72 deletions

View file

@ -9,11 +9,11 @@ import sys
import struct
import os
sys.path.insert(0, '.')
from kvs_data import PAGE_SIZE, align_up
from kvs_data import PAGE_SIZE, align_up, SHT_NOBITS, SHF_WRITE, SHF_ALLOC
def read_csv(input_file, vaddr_text, vaddr_data, text_size, data_size):
"""Загружает байты из CSV используя точные виртуальные адреса"""
text_bytes = bytearray(text_size) # точный размер из pass1
text_bytes = bytearray(text_size)
data_bytes = bytearray(data_size)
with open(input_file, 'r', encoding='utf-8') as f:
@ -72,8 +72,12 @@ def read_pass1(input_file):
def create_elf(text_bytes, data_bytes, pass1_data, labels, output_file):
vaddr_text = pass1_data.get("vaddr_text", 0x401000)
text_size = pass1_data.get("text_size", len(text_bytes))
# Вычисляем vaddr_data динамически, как в kvs_8
data_size = pass1_data.get("data_size", len(data_bytes))
bnd_size = pass1_data.get("bnd_size", 0)
# Вычисляем виртуальные адреса
vaddr_data = align_up(vaddr_text + text_size, PAGE_SIZE)
vaddr_bnd = pass1_data.get("vaddr_bnd", align_up(vaddr_data + data_size, PAGE_SIZE))
offset_text = pass1_data.get("offset_text", 0x1000)
offset_data = align_up(offset_text + len(text_bytes), PAGE_SIZE)
@ -85,13 +89,18 @@ def create_elf(text_bytes, data_bytes, pass1_data, labels, output_file):
entry_addr = vaddr_text + labels.get(entry_point_name, 0)
comment_content = "Сборщик КВС".encode('utf-8') + b'\x00'
shstrtab_content = b"\x00.text\x00.data\x00.comment\x00.shstrtab\x00"
# shstrtab с учётом .bss
if bnd_size > 0:
shstrtab_content = b"\x00.text\x00.data\x00.bss\x00.comment\x00.shstrtab\x00"
else:
shstrtab_content = b"\x00.text\x00.data\x00.comment\x00.shstrtab\x00"
elf_header_size = 64
ph_size = 56
ph_num = 3
shdr_size = 64
shdr_num = 5
shdr_num = 5 + (1 if bnd_size > 0 else 0) # 5 базовых + .bss если есть
file_size = shdr_offset + shdr_num * shdr_size
elf_data = bytearray(file_size)
@ -111,13 +120,23 @@ def create_elf(text_bytes, data_bytes, pass1_data, labels, output_file):
p_filesz, p_memsz, PAGE_SIZE
)
# Program headers
ph0 = phdr(1, 4, 0, 0x400000, elf_header_size + ph_num * ph_size, PAGE_SIZE)
ph1 = phdr(1, 5, offset_text, vaddr_text, len(text_bytes), align_up(len(text_bytes), PAGE_SIZE))
ph2 = phdr(1, 6, offset_data, vaddr_data, len(data_bytes), align_up(len(data_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)
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))
phdrs = ph0 + ph1 + ph2
elf_data[elf_header_size : elf_header_size + len(phdrs)] = phdrs
# Данные секций
elf_data[offset_text : offset_text + len(text_bytes)] = text_bytes
elf_data[offset_data : offset_data + len(data_bytes)] = data_bytes
elf_data[offset_comment : offset_comment + len(comment_content)] = comment_content
@ -129,13 +148,34 @@ def create_elf(text_bytes, data_bytes, pass1_data, labels, output_file):
0, 0, addralign, 0
)
sh0 = shdr(0, 0, 0, 0, 0, 0)
sh1 = shdr(1, 1, 6, vaddr_text, offset_text, len(text_bytes), 16)
sh2 = shdr(7, 1, 3, vaddr_data, offset_data, len(data_bytes), 8)
sh3 = shdr(13, 1, 0, 0, offset_comment, len(comment_content), 1)
sh4 = shdr(22, 3, 0, 0, shstrtab_offset, len(shstrtab_content), 1)
# Индексы имён в shstrtab зависят от наличия .bss
if bnd_size > 0:
name_text = 1 # ".text"
name_data = 7 # ".data"
name_bss = 13 # ".bss"
name_comment = 18 # ".comment"
name_shstrtab = 27 # ".shstrtab"
else:
name_text = 1
name_data = 7
name_comment = 13
name_shstrtab = 22
# Section headers
sh0 = shdr(0, 0, 0, 0, 0, 0) # NULL
sh1 = shdr(name_text, 1, 6, vaddr_text, offset_text, len(text_bytes), 16) # .text
sh2 = shdr(name_data, 1, 3, vaddr_data, offset_data, len(data_bytes), 8) # .data
if bnd_size > 0:
sh3 = shdr(name_bss, SHT_NOBITS, SHF_WRITE | SHF_ALLOC, vaddr_bnd, 0, bnd_size, 16) # .bss
sh4 = shdr(name_comment, 1, 0, 0, offset_comment, len(comment_content), 1) # .comment
sh5 = shdr(name_shstrtab, 3, 0, 0, shstrtab_offset, len(shstrtab_content), 1) # .shstrtab
shdrs = sh0 + sh1 + sh2 + sh3 + sh4 + sh5
else:
sh3 = shdr(name_comment, 1, 0, 0, offset_comment, len(comment_content), 1)
sh4 = shdr(name_shstrtab, 3, 0, 0, shstrtab_offset, len(shstrtab_content), 1)
shdrs = sh0 + sh1 + sh2 + sh3 + sh4
shdrs = sh0 + sh1 + sh2 + sh3 + sh4
elf_data[shdr_offset : shdr_offset + len(shdrs)] = shdrs
with open(output_file, "wb") as f:
@ -146,7 +186,8 @@ def create_elf(text_bytes, data_bytes, pass1_data, labels, output_file):
print(f"Сборщик: ELF-файл создан: {output_file}")
print(f" .text: {len(text_bytes)} байт, адрес: 0x{vaddr_text:x}")
print(f" .data: {len(data_bytes)} байт, адрес: 0x{vaddr_data:x}")
print(f" Расстояние между секциями: 0x{vaddr_data - vaddr_text:x} байт")
if bnd_size > 0:
print(f" .bss: {bnd_size} байт, адрес: 0x{vaddr_bnd:x}")
if __name__ == "__main__":
if len(sys.argv) != 4:
@ -158,7 +199,7 @@ if __name__ == "__main__":
text_size = pass1_data["text_size"]
data_size = pass1_data["data_size"]
# Вычисляем vaddr_data как в kvs_8
# Вычисляем vaddr_data
vaddr_data = align_up(vaddr_text + text_size, PAGE_SIZE)
text_bytes, data_bytes = read_csv(sys.argv[1], vaddr_text, vaddr_data, text_size, data_size)

View file

@ -11,6 +11,16 @@ import struct
# === ГЛОБАЛЬНЫЕ КОНСТАНТЫ ===
# Константы для секции .бнд (аналог .bss)
SECTION_BND = '.бнд'
SECTION_BND_ELF = '.bss' # Имя секции в ELF-файле (стандарт Linux)
# ELF-константы для секции типа SHT_NOBITS
SHT_NOBITS = 8
SHF_WRITE = 0x1
SHF_ALLOC = 0x2
# ELF константы
PAGE_SIZE = 0x1000 # Размер страницы памяти (4096 байт)
elf_base_vaddr = 0x400000 # Базовый виртуальный адрес ELF

View file

@ -104,19 +104,45 @@ class Parser:
return True
def parse_directive(self, word):
"""
Разбор директив ассемблера.
Вызывает ошибку при некорректном синтаксисе или контексте.
"""
# === Секции ===
if word == '.текст':
self.current_section = ".text"
self.parsed_lines.append(f"DIRECTIVE:{word}")
elif word == '.данные':
self.current_section = ".data"
self.parsed_lines.append(f"DIRECTIVE:{word}")
elif word == '.бнд':
self.current_section = ".бнд"
self.parsed_lines.append(f"DIRECTIVE:{word}")
# === Глобальные метки ===
elif word == '.глобал':
label = self.expect('WORD')[1]
self.parsed_lines.append(f"DIRECTIVE:{word}:{label}")
# === Строковые директивы (запрещены в .бнд) ===
elif word in ('.строкауль', '.строка'):
if self.current_section == ".бнд":
raise ValueError(
"Ошибка: секция .бнд не поддерживает инициализированные данные "
"(используйте .резб, .резс, .рездс, .резкс)"
)
string_tok = self.expect('STRING')
self.parsed_lines.append(f"DIRECTIVE:{word}:{self.current_section}:{string_tok[1]}")
# === Константы (запрещены в .бнд) ===
elif word == '.константа':
if self.current_section == ".бнд":
raise ValueError(
"Ошибка: секция .бнд не поддерживает инициализированные данные "
"(используйте .резб, .резс, .рездс, .резкс)"
)
name = self.expect('WORD')[1]
# Пропускаем '=', если есть
eq_tok = self.peek()
@ -125,7 +151,14 @@ class Parser:
# Значение может быть WORD или NUMBER
value_tok = self.expect_one_of(['WORD', 'NUMBER'])
self.parsed_lines.append(f"DIRECTIVE:{word}:{name}:{value_tok[1]}")
# === Байты (запрещены в .бнд) ===
elif word == '.байт':
if self.current_section == ".бнд":
raise ValueError(
"Ошибка: секция .бнд не поддерживает инициализированные данные "
"(используйте .резб, .резс, .рездс, .резкс)"
)
bytes_list = []
while True:
tok = self.peek()
@ -139,6 +172,23 @@ class Parser:
val_tok = self.expect_one_of(['WORD', 'NUMBER', 'STRING'])
bytes_list.append(val_tok[1])
self.parsed_lines.append(f"DIRECTIVE:{word}:{self.current_section}:" + ",".join(bytes_list))
# === Директивы резервирования (только в .бнд) ===
elif word in ('.резб', '.резс', '.рездс', '.резкс'):
if self.current_section != ".бнд":
raise ValueError(
f"Ошибка: директива {word} допустима только внутри секции .бнд"
)
count_tok = self.expect('NUMBER')
count = int(count_tok[1])
if count <= 0:
raise ValueError(
f"Ошибка: размер резервирования должен быть положительным целым числом"
)
self.parsed_lines.append(
f"DIRECTIVE:{word}:{self.current_section}:{count}"
)
else:
raise ValueError(f"Неизвестная директива: {word}")

View file

@ -151,7 +151,7 @@ class Pass1:
self.labels = {}
self.label_sections = {}
self.symbols = {}
self.position = {".text": 0, ".data": 0}
self.position = {".text": 0, ".data": 0, ".бнд": 0}
self.current_section = ".text"
self.entry_point = "_start"
@ -165,6 +165,8 @@ class Pass1:
self.current_section = ".text"
elif directive == '.данные':
self.current_section = ".data"
elif directive == '.бнд':
self.current_section = ".бнд"
elif directive == '.глобал':
self.entry_point = parts[2]
elif directive in ('.строкауль', '.строка'):
@ -188,6 +190,23 @@ class Pass1:
if len(parts) > 3 and parts[3]:
num_bytes = len(parts[3].split(','))
self.position[sec] += num_bytes
# Директивы резервирования в .бнд
elif directive == '.резб':
count = int(parts[3])
self.position['.бнд'] += count * 1
elif directive == '.резс':
count = int(parts[3])
self.position['.бнд'] += count * 2
elif directive == '.рездс':
count = int(parts[3])
self.position['.бнд'] += count * 4
elif directive == '.резкс':
count = int(parts[3])
self.position['.бнд'] += count * 8
elif line_type == "LABEL":
label_name = parts[1]
@ -292,6 +311,7 @@ class Pass1:
def calculate_layout(self):
text_size = self.position[".text"]
data_size = self.position[".data"]
bnd_size = self.position[".бнд"]
elf_header_size = 64
ph_size = 56
@ -302,21 +322,29 @@ 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)
comment_size = len("Сборщик КВС".encode('utf-8')) + 1
offset_comment = align_up(offset_data + data_size, 1)
shstrtab_size = len(b"\x00.text\x00.data\x00.comment\x00.shstrtab\x00")
# shstrtab теперь включает ".bss"
if bnd_size > 0:
shstrtab_content = b"\x00.text\x00.data\x00.bss\x00.comment\x00.shstrtab\x00"
else:
shstrtab_content = b"\x00.text\x00.data\x00.comment\x00.shstrtab\x00"
shstrtab_size = len(shstrtab_content)
shstrtab_offset = align_up(offset_comment + comment_size, 8)
shdr_offset = align_up(shstrtab_offset + shstrtab_size, 16)
return {
"text_size": text_size,
"data_size": data_size,
"bnd_size": bnd_size,
"offset_text": offset_text,
"offset_data": offset_data,
"vaddr_text": vaddr_text,
"vaddr_data": vaddr_data,
"vaddr_bnd": vaddr_bnd,
"offset_comment": offset_comment,
"comment_size": comment_size,
"shstrtab_offset": shstrtab_offset,
@ -347,4 +375,4 @@ 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']}")
print(f"Проход 1: text_size={layout['text_size']}, data_size={layout['data_size']}, bnd_size={layout['bnd_size']}")

View file

@ -91,8 +91,11 @@ class Pass2:
self.symbols = symbols
self.vaddr_text = pass1_data["vaddr_text"]
text_size = pass1_data["text_size"]
data_size = pass1_data["data_size"]
self.vaddr_data = align_up(self.vaddr_text + text_size, PAGE_SIZE)
self.position = {".text": 0, ".data": 0}
self.vaddr_bnd = pass1_data.get("vaddr_bnd", align_up(self.vaddr_data + data_size, PAGE_SIZE))
self.bnd_size = pass1_data.get("bnd_size", 0)
self.position = {".text": 0, ".data": 0, ".бнд": 0}
self.current_section = ".text"
self.csv_lines = []
self.data_bytes = {".text": bytearray(), ".data": bytearray()}
@ -119,7 +122,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])
@ -139,6 +149,8 @@ class Pass2:
self.current_section = ".text"
elif directive == '.данные':
self.current_section = ".data"
elif directive == '.бнд':
self.current_section = ".бнд"
elif directive in ('.строкауль', '.строка'):
s = parts[3] if len(parts) > 3 else ""
real_s = unescape_string(s)
@ -180,6 +192,23 @@ class Pass2:
self.data_bytes[".data"].append(val & 0xFF)
self.position[".data"] += len(byte_values)
# Директивы резервирования в .бнд — не генерируют байты
elif directive == '.резб':
count = int(parts[3])
self.position['.бнд'] += count * 1
elif directive == '.резс':
count = int(parts[3])
self.position['.бнд'] += count * 2
elif directive == '.рездс':
count = int(parts[3])
self.position['.бнд'] += count * 4
elif directive == '.резкс':
count = int(parts[3])
self.position['.бнд'] += count * 8
elif line_type == "LABEL":
label_name = parts[1]
@ -249,4 +278,6 @@ if __name__ == "__main__":
print(f"Проход 2: {len(csv_lines)} строк CSV записано в {sys.argv[3]}")
print(f" .text: {pass2.position['.text']} байт, виртуальный адрес: 0x{pass2.vaddr_text:x}")
print(f" .data: {pass2.position['.data']} байт, виртуальный адрес: 0x{pass2.vaddr_data:x}")
print(f" .data: {pass2.position['.data']} байт, виртуальный адрес: 0x{pass2.vaddr_data:x}")
if pass2.bnd_size > 0:
print(f" .бнд: {pass2.bnd_size} байт, виртуальный адрес: 0x{pass2.vaddr_bnd:x}")

View file

@ -11,13 +11,13 @@ import sys
from kvs_data import INSTRUCTIONS, REGISTERS, get_reg_info
def parse_operand(operand, labels, label_sections, symbols, vaddr_text, vaddr_data):
def parse_operand(operand, labels, label_sections, symbols, vaddr_text, vaddr_data, vaddr_bnd=None):
"""
Вычисляет значение операнда.
Поддерживает:
- десятичные числа (123)
- шестнадцатеричные (0x7B)
- метки (имя_метки)
- метки (имя_метки) из .text, .data или .бнд
- константы (из .константа)
"""
if operand.isdigit():
@ -29,20 +29,29 @@ def parse_operand(operand, labels, label_sections, symbols, vaddr_text, vaddr_da
pass
if operand in labels:
section = label_sections.get(operand, '.text')
base = vaddr_text if section == '.text' else vaddr_data
return labels[operand] + base
if section == '.text':
return labels[operand] + vaddr_text
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
else:
return labels[operand] + vaddr_text
if operand in symbols:
return symbols[operand]
raise ValueError("Неизвестный операнд: " + operand)
def parse_memory_operand(operand_str, labels, label_sections, vaddr_text, vaddr_data):
def parse_memory_operand(operand_str, labels, label_sections, vaddr_text, vaddr_data, vaddr_bnd=None):
"""
Разбирает операнд памяти.
Возвращает словарь с информацией или None.
Поддерживает:
- [число] абсолютный адрес
- [метка] адрес метки (из .data или .text)
- [метка] адрес метки (из .data, .text или .бнд)
- [регистр] косвенная адресация (TODO)
"""
if not operand_str.startswith('[') or not operand_str.endswith(']'):
@ -69,7 +78,14 @@ def parse_memory_operand(operand_str, labels, label_sections, vaddr_text, vaddr_
# Проверяем, является ли содержимое меткой
if content in labels:
section = label_sections.get(content, '.data')
base = vaddr_text if section == '.text' else vaddr_data
if section == '.text':
base = vaddr_text
elif section == '.data':
base = vaddr_data
elif section == '.бнд':
base = vaddr_bnd if vaddr_bnd is not None else vaddr_data
else:
base = vaddr_text
addr = labels[content] + base
return {
'type': 'absolute',
@ -145,7 +161,7 @@ def encode_mov_mem_reg_absolute(reg_info, mem_info, current_pos, vaddr_text):
return code
def encode_mov_reg_mem(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos):
def encode_mov_reg_mem(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos, vaddr_bnd=None):
"""
MOV reg, mem - загрузить из памяти в регистр
Формат: загрузить <регистр>, [<адрес>]
@ -154,7 +170,7 @@ def encode_mov_reg_mem(operands, labels, label_sections, symbols, vaddr_text, va
mem_operand = operands[1]
# Пытаемся разобрать операнд памяти
mem_info = parse_memory_operand(mem_operand, labels, label_sections, vaddr_text, vaddr_data)
mem_info = parse_memory_operand(mem_operand, labels, label_sections, vaddr_text, vaddr_data, vaddr_bnd)
if mem_info and mem_info['type'] == 'absolute':
return encode_mov_reg_mem_absolute(reg_info, mem_info, current_pos, vaddr_text)
@ -163,7 +179,7 @@ def encode_mov_reg_mem(operands, labels, label_sections, symbols, vaddr_text, va
return b'\x90' * 3
def encode_mov_mem_reg(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos):
def encode_mov_mem_reg(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos, vaddr_bnd=None):
"""
MOV mem, reg - сохранить из регистра в память
Формат: сохранить [<адрес>], <регистр>
@ -172,7 +188,7 @@ def encode_mov_mem_reg(operands, labels, label_sections, symbols, vaddr_text, va
reg_info = get_reg_info(operands[1])
# Пытаемся разобрать операнд памяти
mem_info = parse_memory_operand(mem_operand, labels, label_sections, vaddr_text, vaddr_data)
mem_info = parse_memory_operand(mem_operand, labels, label_sections, vaddr_text, vaddr_data, vaddr_bnd)
if mem_info and mem_info['type'] == 'absolute':
return encode_mov_mem_reg_absolute(reg_info, mem_info, current_pos, vaddr_text)
@ -181,7 +197,7 @@ def encode_mov_mem_reg(operands, labels, label_sections, symbols, vaddr_text, va
return b'\x90' * 3
def encode_lea_mem(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos):
def encode_lea_mem(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos, vaddr_bnd=None):
"""
LEA reg, mem - загрузить эффективный адрес
Формат: загрузить_адрес <регистр>, [<адрес>]
@ -190,7 +206,7 @@ def encode_lea_mem(operands, labels, label_sections, symbols, vaddr_text, vaddr_
mem_operand = operands[1]
# Пытаемся разобрать операнд памяти
mem_info = parse_memory_operand(mem_operand, labels, label_sections, vaddr_text, vaddr_data)
mem_info = parse_memory_operand(mem_operand, labels, label_sections, vaddr_text, vaddr_data, vaddr_bnd)
if mem_info and mem_info['type'] == 'absolute':
target_addr = mem_info['address']
rip_at_end = vaddr_text + current_pos + 7
@ -217,7 +233,7 @@ def encode_lea_mem(operands, labels, label_sections, symbols, vaddr_text, vaddr_
# ========== 1. Инструкции перемещения данных (MOV, LEA, MOVZX, MOVSX) ==========
def encode_mov_reg_imm(operands, labels, label_sections, symbols, vaddr_text, vaddr_data):
def encode_mov_reg_imm(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, vaddr_bnd=None):
"""
MOV reg, imm - переместить непосредственное значение в регистр
Формат: переместить_имм <регистр>, <значение|метка|константа>
@ -226,7 +242,7 @@ def encode_mov_reg_imm(operands, labels, label_sections, symbols, vaddr_text, va
reg_info = get_reg_info(operands[0])
reg = reg_info["index"]
size = reg_info["size"]
imm = parse_operand(operands[1], labels, label_sections, symbols, vaddr_text, vaddr_data)
imm = parse_operand(operands[1], labels, label_sections, symbols, vaddr_text, vaddr_data, vaddr_bnd)
if size == 64:
if 0 <= reg <= 7:
@ -335,7 +351,7 @@ def encode_mov_reg8_imm8(operands):
return code
def encode_movzx(operands, labels, label_sections, symbols, vaddr_text, vaddr_data):
def encode_movzx(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, vaddr_bnd=None):
"""
MOVZX reg, mem8 - переместить с расширением нулями
Формат: переместить_сулями <регистр>, <адрес_байта>
@ -344,7 +360,7 @@ def encode_movzx(operands, labels, label_sections, symbols, vaddr_text, vaddr_da
instr = INSTRUCTIONS["переместить_сулями"]
reg_info = get_reg_info(operands[0])
reg = reg_info["index"]
addr = parse_operand(operands[1], labels, label_sections, symbols, vaddr_text, vaddr_data)
addr = parse_operand(operands[1], labels, label_sections, symbols, vaddr_text, vaddr_data, vaddr_bnd)
rex = 0x48 if reg_info["size"] == 64 else 0x40
if reg >= 8:
@ -357,7 +373,7 @@ def encode_movzx(operands, labels, label_sections, symbols, vaddr_text, vaddr_da
return code
def encode_movsx(operands, labels, label_sections, symbols, vaddr_text, vaddr_data):
def encode_movsx(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, vaddr_bnd=None):
"""
MOVSX reg, mem8 - переместить с расширением знака
Формат: переместить_со_знаком <регистр>, <адрес_байта>
@ -366,7 +382,7 @@ def encode_movsx(operands, labels, label_sections, symbols, vaddr_text, vaddr_da
instr = INSTRUCTIONS["переместить_со_знаком"]
reg_info = get_reg_info(operands[0])
reg = reg_info["index"]
addr = parse_operand(operands[1], labels, label_sections, symbols, vaddr_text, vaddr_data)
addr = parse_operand(operands[1], labels, label_sections, symbols, vaddr_text, vaddr_data, vaddr_bnd)
rex = 0x48 if reg_info["size"] == 64 else 0x40
if reg >= 8:
@ -381,7 +397,7 @@ def encode_movsx(operands, labels, label_sections, symbols, vaddr_text, vaddr_da
# ========== 2. Инструкции сравнения (CMP, TEST) ==========
def encode_cmp_reg_imm(operands, labels, label_sections, symbols, vaddr_text, vaddr_data):
def encode_cmp_reg_imm(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, vaddr_bnd=None):
"""
CMP reg, imm - сравнить регистр с непосредственным значением
Формат: сравнить_с <регистр>, <значение|метка|константа>
@ -390,7 +406,7 @@ def encode_cmp_reg_imm(operands, labels, label_sections, symbols, vaddr_text, va
reg_info = get_reg_info(operands[0])
reg = reg_info["index"]
size = reg_info["size"]
imm = parse_operand(operands[1], labels, label_sections, symbols, vaddr_text, vaddr_data)
imm = parse_operand(operands[1], labels, label_sections, symbols, vaddr_text, vaddr_data, vaddr_bnd)
if size == 64:
rex = 0x48
@ -493,7 +509,7 @@ def encode_cmp_reg_reg(mnemonic, operands):
# ========== 3. Арифметические инструкции (ADD, SUB, MUL, DIV) ==========
def encode_add_sub_reg_imm(mnemonic, operands, labels, label_sections, symbols, vaddr_text, vaddr_data):
def encode_add_sub_reg_imm(mnemonic, operands, labels, label_sections, symbols, vaddr_text, vaddr_data, vaddr_bnd=None):
"""
ADD/SUB reg, imm - прибавить/вычесть непосредственное значение
Формат: прибавить_непосредственно / вычесть_непосредственно <регистр>, <значение>
@ -502,7 +518,7 @@ def encode_add_sub_reg_imm(mnemonic, operands, labels, label_sections, symbols,
reg_info = get_reg_info(operands[0])
reg = reg_info["index"]
size = reg_info["size"]
imm = parse_operand(operands[1], labels, label_sections, symbols, vaddr_text, vaddr_data)
imm = parse_operand(operands[1], labels, label_sections, symbols, vaddr_text, vaddr_data, vaddr_bnd)
op_map = {
"прибавить_непосредственно": 0x81,
@ -671,26 +687,26 @@ def encode_not_neg(mnemonic, operands):
# ========== 5. Инструкции переходов и вызовов ==========
def encode_jmp_rel32(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos):
def encode_jmp_rel32(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos, vaddr_bnd=None):
"""
JMP rel32 - безусловный переход с 32-битным смещением
"""
code = bytearray()
instr = INSTRUCTIONS["переход"]
code.extend(instr["opcode"])
target = parse_operand(operands[0], labels, label_sections, symbols, vaddr_text, vaddr_data)
target = parse_operand(operands[0], labels, label_sections, symbols, vaddr_text, vaddr_data, vaddr_bnd)
offset = target - (vaddr_text + current_pos + 5)
code.extend(struct.pack('<i', offset))
return code
def encode_jmp_short(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos):
def encode_jmp_short(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos, vaddr_bnd=None):
"""
JMP SHORT - короткий безусловный переход с 8-битным смещением
"""
code = bytearray()
code.append(0xEB)
target = parse_operand(operands[0], labels, label_sections, symbols, vaddr_text, vaddr_data)
target = parse_operand(operands[0], labels, label_sections, symbols, vaddr_text, vaddr_data, vaddr_bnd)
offset = target - (vaddr_text + current_pos + 2)
if not (-128 <= offset <= 127):
raise ValueError(f"Смещение короткого перехода {offset} вне диапазона [-128..127]")
@ -698,27 +714,27 @@ def encode_jmp_short(operands, labels, label_sections, symbols, vaddr_text, vadd
return code
def encode_jcc_rel32(mnemonic, operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos):
def encode_jcc_rel32(mnemonic, operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos, vaddr_bnd=None):
"""
Jcc rel32 - условный переход с 32-битным смещением
"""
code = bytearray()
instr = INSTRUCTIONS[mnemonic]
code.extend(instr["opcode"])
target = parse_operand(operands[0], labels, label_sections, symbols, vaddr_text, vaddr_data)
target = parse_operand(operands[0], labels, label_sections, symbols, vaddr_text, vaddr_data, vaddr_bnd)
offset = target - (vaddr_text + current_pos + 6)
code.extend(struct.pack('<i', offset))
return code
def encode_jcc_short(mnemonic, operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos):
def encode_jcc_short(mnemonic, operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos, vaddr_bnd=None):
"""
Jcc SHORT - короткий условный переход с 8-битным смещением
"""
code = bytearray()
instr = INSTRUCTIONS[mnemonic]
code.extend(instr["opcode"])
target = parse_operand(operands[0], labels, label_sections, symbols, vaddr_text, vaddr_data)
target = parse_operand(operands[0], labels, label_sections, symbols, vaddr_text, vaddr_data, vaddr_bnd)
offset = target - (vaddr_text + current_pos + 2)
if not (-128 <= offset <= 127):
raise ValueError(f"Смещение короткого перехода {offset} вне диапазона [-128..127]")
@ -726,14 +742,14 @@ def encode_jcc_short(mnemonic, operands, labels, label_sections, symbols, vaddr_
return code
def encode_call(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos):
def encode_call(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos, vaddr_bnd=None):
"""
CALL rel32 - вызов процедуры
"""
code = bytearray()
instr = INSTRUCTIONS["вызвать"]
code.extend(instr["opcode"])
target = parse_operand(operands[0], labels, label_sections, symbols, vaddr_text, vaddr_data)
target = parse_operand(operands[0], labels, label_sections, symbols, vaddr_text, vaddr_data, vaddr_bnd)
offset = target - (vaddr_text + current_pos + 5)
code.extend(struct.pack('<i', offset))
return code
@ -744,14 +760,14 @@ def encode_ret():
return INSTRUCTIONS["вернуться"]["opcode"]
def encode_loop(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos):
def encode_loop(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos, vaddr_bnd=None):
"""
LOOP rel8 - инструкция цикла
"""
code = bytearray()
instr = INSTRUCTIONS["цикл"]
code.extend(instr["opcode"])
target = parse_operand(operands[0], labels, label_sections, symbols, vaddr_text, vaddr_data)
target = parse_operand(operands[0], labels, label_sections, symbols, vaddr_text, vaddr_data, vaddr_bnd)
offset = target - (vaddr_text + current_pos + 2)
if not (-128 <= offset <= 127):
raise ValueError(f"Смещение LOOP {offset} вне диапазона [-128..127]")
@ -1002,7 +1018,7 @@ def encode_xchg(operands):
# ========== ГЛАВНЫЙ ДИСПЕТЧЕР ==========
def encode_instruction(mnemonic, operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos):
def encode_instruction(mnemonic, operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos, vaddr_bnd=None):
"""
Главный диспетчер генерации машинного кода.
По мнемонике выбирает соответствующую функцию генерации.
@ -1031,33 +1047,33 @@ def encode_instruction(mnemonic, operands, labels, label_sections, symbols, vadd
# ----- MOV с памятью -----
elif mnemonic == "загрузить":
return encode_mov_reg_mem(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos)
return encode_mov_reg_mem(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos, vaddr_bnd)
elif mnemonic == "сохранить":
return encode_mov_mem_reg(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos)
return encode_mov_mem_reg(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos, vaddr_bnd)
elif mnemonic == "загрузить_адрес":
return encode_lea_mem(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos)
return encode_lea_mem(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos, vaddr_bnd)
# ----- MOV (разные формы) -----
elif mnemonic == "переместить_имм":
return encode_mov_reg_imm(operands, labels, label_sections, symbols, vaddr_text, vaddr_data)
return encode_mov_reg_imm(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, vaddr_bnd)
elif mnemonic == "переместить":
return encode_mov_reg_reg(operands)
elif mnemonic == "загрузить_байт":
return encode_mov_reg8_imm8(operands)
elif mnemonic == "переместить_сулями":
return encode_movzx(operands, labels, label_sections, symbols, vaddr_text, vaddr_data)
return encode_movzx(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, vaddr_bnd)
elif mnemonic == "переместить_со_знаком":
return encode_movsx(operands, labels, label_sections, symbols, vaddr_text, vaddr_data)
return encode_movsx(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, vaddr_bnd)
# ----- CMP (сравнение) -----
elif mnemonic == "сравнить_с":
return encode_cmp_reg_imm(operands, labels, label_sections, symbols, vaddr_text, vaddr_data)
return encode_cmp_reg_imm(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, vaddr_bnd)
elif mnemonic in ("сравнить", "сравнить_байт", "проверить"):
return encode_cmp_reg_reg(mnemonic, operands)
# ----- ADD/SUB (арифметика) -----
elif mnemonic in ("прибавить_непосредственно", "вычесть_непосредственно"):
return encode_add_sub_reg_imm(mnemonic, operands, labels, label_sections, symbols, vaddr_text, vaddr_data)
return encode_add_sub_reg_imm(mnemonic, operands, labels, label_sections, symbols, vaddr_text, vaddr_data, vaddr_bnd)
elif mnemonic in ("прибавить", "вычесть", "прибавить_байт", "вычесть_байт"):
return encode_add_sub_reg_reg(mnemonic, operands)
@ -1079,25 +1095,25 @@ def encode_instruction(mnemonic, operands, labels, label_sections, symbols, vadd
# ----- Переходы -----
elif mnemonic == "переход":
return encode_jmp_rel32(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos)
return encode_jmp_rel32(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos, vaddr_bnd)
elif mnemonic == "короткий_переход":
return encode_jmp_short(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos)
return encode_jmp_short(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos, vaddr_bnd)
elif mnemonic in ("переход_если_равно", "переход_если_неравно", "переход_если_меньше",
"переход_если_больше", "переход_если_меньше_или_равно", "переход_если_больше_или_равно",
"переход_если_перенос", "переход_если_нет_переноса", "переход_если_ноль", "переход_если_неоль"):
return encode_jcc_rel32(mnemonic, operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos)
return encode_jcc_rel32(mnemonic, operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos, vaddr_bnd)
elif mnemonic in ("короткий_переход_если_равно", "короткий_переход_если_неравно",
"короткий_переход_если_меньше", "короткий_переход_если_больше",
"короткий_переход_если_меньше_или_равно", "короткий_переход_если_больше_или_равно",
"короткий_переход_если_перенос", "короткий_переход_если_нет_переноса",
"короткий_переход_если_ноль", "короткий_переход_если_неоль"):
return encode_jcc_short(mnemonic, operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos)
return encode_jcc_short(mnemonic, operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos, vaddr_bnd)
# ----- CALL/RET/LOOP -----
elif mnemonic == "вызвать":
return encode_call(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos)
return encode_call(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos, vaddr_bnd)
elif mnemonic == "цикл":
return encode_loop(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos)
return encode_loop(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos, vaddr_bnd)
# ----- PUSH/POP -----
elif mnemonic == "втолкнуть":

View file

@ -243,4 +243,9 @@ Pass2 (шаг 5):
**Статус: v2.0 — абсолютная адресация реализована полностью.**
**Следующая цель: v3.0 — косвенная адресация `[reg]`.**
```
```
избавиться от ре и перенести таблицу фиксированных размеров
вынести работу с памятью из второго прохода в отдельный энкодер

View file

@ -0,0 +1,9 @@
.текст
.глобал _start
_start:
переместить_имм раикс, 60
переместить_имм рдиай, 0
вызов_системы
.бнд
буфер: .резб 1048576 ; 1 МБ = 1024 * 1024

View file

@ -25,4 +25,4 @@ _start:
.данные
msg: .строка "Тест пройден!\n" ; не менять их местами, чтоб не затереть текст
переменная: .байт 0 ; тут либо резервировать пустые, либо .bss изобретать
переменная: .байт 0 ; тут либо резервировать пустые, либо .bss изобретать (или кучу?)

View file

@ -0,0 +1,30 @@
.текст
.глобал _start
_start:
; 25 - длина сообщения из метки msg
; Запись значения 25 в переменную по метке
переместить_имм рдикс, 25
сохранить [переменная], рдикс
; перепишем для теста
переместить_имм рдикс, 0
; Системный вызов write(1, msg, len)
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, msg
загрузить рдикс, [переменная]
вызов_системы
; Системный вызов exit()
переместить_имм раикс, 60 ; номер syscall exit = 60
переместить_имм рдиай, 44 ; код возврата (старый метод)
вызов_системы
.данные
msg: .строка "Тест пройден!\n" ; строка остаётся в .данные
.бнд
переменная: .резкс 1 ; 8 байт под qword (как и было .байт 0)

View file

@ -0,0 +1,36 @@
.текст
.глобал _start
_start:
; 25 - длина сообщения из метки msg
; Запись значения 25 в переменную в .бнд
переместить_имм рдикс, 25
сохранить [переменная], рдикс
; Загружаем адрес строки и сохраняем в буфер в .бнд
загрузить_адрес раикс, [msg]
сохранить [буфер_строки], раикс
; перепишем для теста
переместить_имм рдикс, 0
; Системный вызов write(1, msg, len)
переместить_имм раикс, 1
переместить_имм рдиай, 1
загрузить рсиай, [буфер_строки]
загрузить рдикс, [переменная]
вызов_системы
; Системный вызов exit()
переместить_имм раикс, 60
переместить_имм рдиай, 44
вызов_системы
.данные
msg: .строка "Тест пройден!\n"
.бнд
переменная: .резкс 1 ; 8 байт под длину
буфер_строки: .резкс 1 ; 8 байт под указатель на строку