однотабличная сборка
This commit is contained in:
parent
6400d6105a
commit
3a04dc5447
20
kvs_build.py
20
kvs_build.py
|
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
"""kvs_build.py
|
||||
Главный сборочный скрипт КВС
|
||||
Последовательно запускает все этапы компиляции
|
||||
"""
|
||||
|
|
@ -23,17 +23,18 @@ if __name__ == "__main__":
|
|||
|
||||
tokens_file = base_name + ".токены"
|
||||
ast_file = base_name + ".аст"
|
||||
pass1_file = base_name + ".проход1"
|
||||
csv_file = base_name + ".csv"
|
||||
elf_file = base_name + ".elf"
|
||||
|
||||
stages = [
|
||||
("kvs_lexer.py", [source_file, tokens_file], "Лексический анализ"),
|
||||
("kvs_parser.py", [tokens_file, ast_file], "Парсинг"),
|
||||
("kvs_pass1.py", [ast_file, pass1_file], "Первый проход"),
|
||||
("kvs_pass2.py", [ast_file, pass1_file, csv_file], "Второй проход и генерация CSV"),
|
||||
("kvs_verify.py", [pass1_file, csv_file], "Проверка размеров инструкций"),
|
||||
("kvs_builder.py", [csv_file, pass1_file, elf_file], "Сборка ELF"),
|
||||
("kvs_pass1.py", [ast_file, csv_file], "Первый проход: генерация кода и CSV"),
|
||||
("kvs_pass2.py", [csv_file], "2 проход"),
|
||||
("kvs_pass3.py", [ast_file, csv_file], "3 проход"),
|
||||
("kvs_pass4.py", [csv_file], "4 проход"),
|
||||
#("kvs_pass2.py", [csv_file], "Второй проход: разрешение меток"),
|
||||
("kvs_builder.py", [csv_file, elf_file], "Сборка ELF"),
|
||||
]
|
||||
|
||||
for script, args, description in stages:
|
||||
|
|
@ -48,10 +49,9 @@ if __name__ == "__main__":
|
|||
print(result.stdout)
|
||||
sys.exit(1)
|
||||
|
||||
# Для верификатора показываем stdout (там детали проверки)
|
||||
if result.stdout:
|
||||
print(result.stdout)
|
||||
|
||||
print(f"\n=== Компиляция успешно завершена ===")
|
||||
print(f"Исполняемый файл: {elf_file}")
|
||||
print(f"Запустить: ./{elf_file}")
|
||||
#print(f"\n=== Компиляция успешно завершена ===")
|
||||
#print(f"Исполняемый файл: {elf_file}")
|
||||
#print(f"Запустить: ./{elf_file}")
|
||||
269
kvs_builder.py
269
kvs_builder.py
|
|
@ -2,216 +2,103 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Сборщик ELF из CSV
|
||||
kvs_builder.py - Сборка ELF из CSV таблицы
|
||||
Читает CSV, берёт колонки 'адрес' и 'рассчитанный_байт',
|
||||
заполняет пропуски в адресах нулями и записывает выходной файл
|
||||
"""
|
||||
|
||||
import sys
|
||||
import struct
|
||||
import csv
|
||||
import os
|
||||
sys.path.insert(0, '.')
|
||||
from kvs_data import PAGE_SIZE, align_up, SHT_NOBITS, SHF_WRITE, SHF_ALLOC
|
||||
import stat
|
||||
|
||||
def read_csv(input_file, vaddr_text, vaddr_data, text_size, data_size):
|
||||
"""Загружает байты из CSV используя точные виртуальные адреса"""
|
||||
text_bytes = bytearray(text_size)
|
||||
data_bytes = bytearray(data_size)
|
||||
|
||||
def read_csv(csv_file):
|
||||
"""Читает CSV и возвращает список адресов и байтов"""
|
||||
addresses = []
|
||||
bytes_list = []
|
||||
|
||||
with open(input_file, 'r', encoding='utf-8') as f:
|
||||
next(f)
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
parts = line.split(';')
|
||||
if len(parts) < 2:
|
||||
continue
|
||||
addr_str = parts[0]
|
||||
byte_str = parts[1]
|
||||
with open(csv_file, 'r', encoding='utf-8') as f:
|
||||
reader = csv.reader(f, delimiter=';')
|
||||
headers = next(reader)
|
||||
|
||||
# Находим индексы нужных колонок
|
||||
try:
|
||||
addr_idx = headers.index('адрес')
|
||||
byte_idx = headers.index('рассчитанный_байт')
|
||||
except ValueError as e:
|
||||
print(f"Ошибка: не найдена нужная колонка в CSV: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
for row in reader:
|
||||
addr_str = row[addr_idx].strip()
|
||||
byte_str = row[byte_idx].strip()
|
||||
|
||||
try:
|
||||
if addr_str and addr_str.startswith('0x'):
|
||||
addr = int(addr_str, 16)
|
||||
byte_val = int(byte_str, 16)
|
||||
except ValueError:
|
||||
continue
|
||||
|
||||
if addr >= vaddr_data:
|
||||
offset = addr - vaddr_data
|
||||
if 0 <= offset < data_size:
|
||||
data_bytes[offset] = byte_val
|
||||
elif addr >= vaddr_text:
|
||||
offset = addr - vaddr_text
|
||||
if 0 <= offset < text_size:
|
||||
text_bytes[offset] = byte_val
|
||||
addresses.append(addr)
|
||||
|
||||
if byte_str and byte_str.startswith('0x'):
|
||||
bytes_list.append(int(byte_str, 16))
|
||||
else:
|
||||
bytes_list.append(0)
|
||||
|
||||
# Заменяем хвостовые нули на NOP'ы (0x90)
|
||||
# Находим последний ненулевой байт
|
||||
last_nonzero = -1
|
||||
for i in range(len(text_bytes) - 1, -1, -1):
|
||||
if text_bytes[i] != 0:
|
||||
last_nonzero = i
|
||||
break
|
||||
|
||||
if last_nonzero >= 0 and last_nonzero < len(text_bytes) - 1:
|
||||
for i in range(last_nonzero + 1, len(text_bytes)):
|
||||
text_bytes[i] = 0x90
|
||||
|
||||
return text_bytes, data_bytes
|
||||
return addresses, bytes_list
|
||||
|
||||
def read_pass1(input_file):
|
||||
data = {}
|
||||
labels = {}
|
||||
|
||||
with open(input_file, 'r', encoding='utf-8') as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
parts = line.split(':')
|
||||
if parts[0] == "PARAM":
|
||||
key = parts[1]
|
||||
value = parts[2]
|
||||
if value.isdigit():
|
||||
value = int(value)
|
||||
data[key] = value
|
||||
elif parts[0] == "LABEL":
|
||||
label = parts[1]
|
||||
pos = int(parts[3])
|
||||
labels[label] = pos
|
||||
|
||||
return data, labels
|
||||
|
||||
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))
|
||||
data_size = pass1_data.get("data_size", len(data_bytes))
|
||||
bnd_size = pass1_data.get("bnd_size", 0)
|
||||
def build_file(addresses, bytes_list, output_file):
|
||||
"""Собирает файл, заполняя пропуски в адресах нулями"""
|
||||
if not addresses:
|
||||
print("Нет данных для сборки")
|
||||
return False
|
||||
|
||||
# Вычисляем виртуальные адреса
|
||||
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))
|
||||
# Определяем размер файла (максимальный адрес + 1)
|
||||
max_addr = max(addresses)
|
||||
file_size = max_addr + 1
|
||||
|
||||
offset_text = pass1_data.get("offset_text", 0x1000)
|
||||
offset_data = align_up(offset_text + len(text_bytes), PAGE_SIZE)
|
||||
offset_comment = pass1_data.get("offset_comment", align_up(offset_data + len(data_bytes), 1))
|
||||
shstrtab_offset = pass1_data.get("shstrtab_offset", align_up(offset_comment + 32, 8))
|
||||
shdr_offset = pass1_data.get("shdr_offset", align_up(shstrtab_offset + 32, 16))
|
||||
entry_point_name = pass1_data.get("entry_point", "_start")
|
||||
# Создаём буфер, заполненный нулями
|
||||
buffer = bytearray(file_size)
|
||||
|
||||
entry_addr = vaddr_text + labels.get(entry_point_name, 0)
|
||||
# Заполняем байты по известным адресам
|
||||
for addr, byte_val in zip(addresses, bytes_list):
|
||||
buffer[addr] = byte_val
|
||||
|
||||
comment_content = "Сборщик КВС".encode('utf-8') + b'\x00'
|
||||
# Записываем файл
|
||||
with open(output_file, 'wb') as f:
|
||||
f.write(buffer)
|
||||
|
||||
# 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"
|
||||
# Добавляем права на исполнение (chmod +x)
|
||||
st = os.stat(output_file)
|
||||
os.chmod(output_file, st.st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
|
||||
|
||||
elf_header_size = 64
|
||||
ph_size = 56
|
||||
ph_num = 3
|
||||
shdr_size = 64
|
||||
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)
|
||||
|
||||
# ELF header
|
||||
e_ident = b"\x7fELF\x02\x01\x01\x00" + b"\x00" * 8
|
||||
elf_header = struct.pack(
|
||||
'<16sHHIQQQIHHHHHH',
|
||||
e_ident, 2, 0x3e, 1, entry_addr, elf_header_size, shdr_offset,
|
||||
0, elf_header_size, ph_size, ph_num, shdr_size, shdr_num, 4
|
||||
)
|
||||
elf_data[0:64] = elf_header
|
||||
|
||||
def phdr(p_type, p_flags, p_offset, p_vaddr, p_filesz, p_memsz):
|
||||
return struct.pack('<IIQQQQQQ',
|
||||
p_type, p_flags, p_offset, p_vaddr, p_vaddr,
|
||||
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))
|
||||
|
||||
if bnd_size > 0:
|
||||
data_segment_filesz = len(data_bytes)
|
||||
# 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))
|
||||
|
||||
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
|
||||
elf_data[shstrtab_offset : shstrtab_offset + len(shstrtab_content)] = shstrtab_content
|
||||
|
||||
def shdr(name_idx, sh_type, flags, addr, offset, size, addralign=1):
|
||||
return struct.pack('<IIQQQQIIQQ',
|
||||
name_idx, sh_type, flags, addr, offset, size,
|
||||
0, 0, addralign, 0
|
||||
)
|
||||
|
||||
# Индексы имён в 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
|
||||
|
||||
elf_data[shdr_offset : shdr_offset + len(shdrs)] = shdrs
|
||||
|
||||
with open(output_file, "wb") as f:
|
||||
f.write(elf_data)
|
||||
|
||||
os.chmod(output_file, 0o755)
|
||||
|
||||
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}")
|
||||
if bnd_size > 0:
|
||||
print(f" .bss: {bnd_size} байт, адрес: 0x{vaddr_bnd:x}")
|
||||
return True
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) != 4:
|
||||
print("Использование: python kvs_builder.py <вход.csv> <вход.проход1> <выход.elf>")
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 3:
|
||||
print("Использование: python kvs_builder.py <входной.csv> <выходной.elf>")
|
||||
sys.exit(1)
|
||||
|
||||
pass1_data, labels = read_pass1(sys.argv[2])
|
||||
vaddr_text = pass1_data["vaddr_text"]
|
||||
text_size = pass1_data["text_size"]
|
||||
data_size = pass1_data["data_size"]
|
||||
csv_file = sys.argv[1]
|
||||
elf_file = sys.argv[2]
|
||||
|
||||
# Вычисляем vaddr_data
|
||||
vaddr_data = align_up(vaddr_text + text_size, PAGE_SIZE)
|
||||
print(f"\n=== Сборка ELF из CSV ===")
|
||||
print(f"Чтение CSV: {csv_file}")
|
||||
|
||||
text_bytes, data_bytes = read_csv(sys.argv[1], vaddr_text, vaddr_data, text_size, data_size)
|
||||
create_elf(text_bytes, data_bytes, pass1_data, labels, sys.argv[3])
|
||||
addresses, bytes_list = read_csv(csv_file)
|
||||
print(f"Найдено {len(addresses)} записей")
|
||||
|
||||
if build_file(addresses, bytes_list, elf_file):
|
||||
print(f"\n=== Сборка завершена ===")
|
||||
print(f" Записей в CSV: {len(addresses)}")
|
||||
print(f" Размер файла: {max(addresses) + 1} байт (0x{max(addresses) + 1:x})")
|
||||
print(f" Выходной файл: {elf_file}")
|
||||
print(f"\n Исполняемый файл готов!")
|
||||
print(f" Запустить: ./{elf_file}")
|
||||
else:
|
||||
print("Ошибка при сборке")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
1062
kvs_pass1.py
1062
kvs_pass1.py
File diff suppressed because it is too large
Load diff
534
kvs_pass2.py
534
kvs_pass2.py
|
|
@ -3,347 +3,231 @@
|
|||
|
||||
"""
|
||||
Второй проход КВС
|
||||
Генерирует машинный код и создаёт CSV-файл
|
||||
- Собирает адреса всех приводящих меток (поддерживает несколько меток через запятую)
|
||||
- Заменяет заглушки в уводящих адресах на реальные адреса
|
||||
- Записывает рассчитанные значения в колонку 'рассчитанный_уводящий_адрес' (файловое смещение)
|
||||
- Формирует команду с подставленными адресами в колонку 'команда_со_значениями' (виртуальный адрес)
|
||||
- Пропускает заглушки, которые не найдены (возможно это константы)
|
||||
- Выводит статистику по неразрешённым заглушкам
|
||||
"""
|
||||
|
||||
import sys
|
||||
import struct
|
||||
sys.path.insert(0, '.')
|
||||
from kvs_data import PAGE_SIZE, align_up
|
||||
from kvs_pass2_encoder import encode_instruction, parse_operand
|
||||
import csv
|
||||
from collections import Counter
|
||||
|
||||
|
||||
def unescape_string(s):
|
||||
"""Преобразует escape-последовательности в реальные символы"""
|
||||
result = []
|
||||
i = 0
|
||||
while i < len(s):
|
||||
if s[i] == '\\' and i + 1 < len(s):
|
||||
if s[i + 1] == 'n':
|
||||
result.append('\n')
|
||||
elif s[i + 1] == 't':
|
||||
result.append('\t')
|
||||
elif s[i + 1] == 'r':
|
||||
result.append('\r')
|
||||
def read_csv(csv_file):
|
||||
"""Читает CSV файл и возвращает список записей и заголовки"""
|
||||
entries = []
|
||||
headers = []
|
||||
|
||||
with open(csv_file, 'r', encoding='utf-8') as f:
|
||||
reader = csv.reader(f, delimiter=';')
|
||||
headers = next(reader)
|
||||
for row in reader:
|
||||
entries.append(row)
|
||||
|
||||
return headers, entries
|
||||
|
||||
|
||||
def get_virtual_addresses(entries, headers):
|
||||
"""
|
||||
Извлекает виртуальные адреса секций из заголовка CSV
|
||||
Возвращает (vaddr_text, vaddr_data)
|
||||
"""
|
||||
vaddr_text = 0x401000
|
||||
vaddr_data = 0x402000
|
||||
|
||||
try:
|
||||
source_idx = headers.index('исходная_команда')
|
||||
calc_target_idx = headers.index('рассчитанный_уводящий_адрес')
|
||||
except ValueError:
|
||||
return vaddr_text, vaddr_data
|
||||
|
||||
for row in entries:
|
||||
source = row[source_idx].strip()
|
||||
calc_target = row[calc_target_idx].strip()
|
||||
|
||||
if 'p_vaddr (text)' in source and calc_target:
|
||||
parts = calc_target.split('=')
|
||||
if len(parts) >= 2:
|
||||
addr_str = parts[1].strip()
|
||||
if addr_str.startswith('0x'):
|
||||
vaddr_text = int(addr_str, 16)
|
||||
|
||||
elif 'p_vaddr (data)' in source and calc_target:
|
||||
parts = calc_target.split('=')
|
||||
if len(parts) >= 2:
|
||||
addr_str = parts[1].strip()
|
||||
if addr_str.startswith('0x'):
|
||||
vaddr_data = int(addr_str, 16)
|
||||
|
||||
return vaddr_text, vaddr_data
|
||||
|
||||
|
||||
def collect_labels(entries, headers, vaddr_text, vaddr_data):
|
||||
"""
|
||||
Собирает адреса всех приводящих меток.
|
||||
Возвращает два словаря:
|
||||
- labels_file: имя метки -> файловое смещение
|
||||
- labels_virt: имя метки -> виртуальный адрес
|
||||
"""
|
||||
labels_file = {} # имя метки -> файловое смещение
|
||||
labels_virt = {} # имя метки -> виртуальный адрес
|
||||
|
||||
try:
|
||||
label_idx = headers.index('приводящая_метка')
|
||||
addr_idx = headers.index('адрес')
|
||||
segment_idx = headers.index('сегмент')
|
||||
except ValueError as e:
|
||||
print(f"Ошибка: не найдена нужная колонка в CSV: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
for row in entries:
|
||||
label_str = row[label_idx].strip()
|
||||
if label_str:
|
||||
addr_str = row[addr_idx].strip()
|
||||
if addr_str.startswith('0x'):
|
||||
file_addr = int(addr_str, 16)
|
||||
segment = row[segment_idx].strip()
|
||||
|
||||
# Вычисляем виртуальный адрес
|
||||
if segment == '.text':
|
||||
virt_addr = vaddr_text + (file_addr - 0x1000)
|
||||
elif segment == '.data':
|
||||
virt_addr = vaddr_data + (file_addr - 0x2000)
|
||||
else:
|
||||
virt_addr = file_addr
|
||||
|
||||
# Разделяем несколько меток через запятую
|
||||
for label_name in label_str.split(','):
|
||||
label_name = label_name.strip()
|
||||
if label_name:
|
||||
labels_file[label_name] = file_addr
|
||||
labels_virt[label_name] = virt_addr
|
||||
|
||||
return labels_file, labels_virt
|
||||
|
||||
|
||||
def resolve_targets(entries, headers, labels_file, labels_virt):
|
||||
"""
|
||||
Заменяет уводящие адреса-заглушки на реальные адреса
|
||||
- рассчитанный_уводящий_адрес: файловое смещение
|
||||
- команда_со_значениями: виртуальный адрес
|
||||
"""
|
||||
try:
|
||||
target_idx = headers.index('уводящий_адрес')
|
||||
calc_target_idx = headers.index('рассчитанный_уводящий_адрес')
|
||||
source_idx = headers.index('исходная_команда')
|
||||
source_with_values_idx = headers.index('команда_со_значениями')
|
||||
except ValueError as e:
|
||||
print(f"Ошибка: не найдена нужная колонка в CSV: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
resolved = [] # (имя_метки, файловый_адрес, виртуальный_адрес)
|
||||
unresolved = [] # имя_метки
|
||||
|
||||
for row in entries:
|
||||
target = row[target_idx].strip()
|
||||
|
||||
if target and target.startswith('ЗАГЛУШКА '):
|
||||
label_name = target.replace('ЗАГЛУШКА ', '').strip()
|
||||
|
||||
if label_name in labels_file:
|
||||
file_addr = labels_file[label_name]
|
||||
virt_addr = labels_virt[label_name]
|
||||
file_hex = f"0x{file_addr:08x}"
|
||||
virt_hex = f"0x{virt_addr:08x}"
|
||||
|
||||
# Файловое смещение в рассчитанный_уводящий_адрес
|
||||
row[calc_target_idx] = file_hex
|
||||
resolved.append((label_name, file_addr, virt_addr))
|
||||
|
||||
# Виртуальный адрес в команда_со_значениями
|
||||
source_cmd = row[source_idx].strip()
|
||||
if source_cmd:
|
||||
cmd_with_addr = source_cmd.replace(label_name, virt_hex)
|
||||
row[source_with_values_idx] = cmd_with_addr
|
||||
else:
|
||||
result.append(s[i])
|
||||
result.append(s[i + 1])
|
||||
i += 2
|
||||
else:
|
||||
result.append(s[i])
|
||||
i += 1
|
||||
return ''.join(result)
|
||||
|
||||
|
||||
def read_ast(input_file):
|
||||
"""Читает AST из файла"""
|
||||
ast_lines = []
|
||||
with open(input_file, 'r', encoding='utf-8') as f:
|
||||
for line in f:
|
||||
ast_lines.append(line.strip())
|
||||
return ast_lines
|
||||
|
||||
|
||||
def read_pass1(input_file):
|
||||
"""
|
||||
Читает результаты первого прохода:
|
||||
- PARAM: параметры компоновки (размеры, адреса)
|
||||
- LABEL: метки и их позиции
|
||||
- SYMBOL: константы
|
||||
"""
|
||||
data = {}
|
||||
labels = {}
|
||||
label_sections = {}
|
||||
symbols = {}
|
||||
unresolved.append(label_name)
|
||||
row[calc_target_idx] = ""
|
||||
|
||||
with open(input_file, 'r', encoding='utf-8') as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
parts = line.split(':')
|
||||
if parts[0] == "PARAM":
|
||||
key = parts[1]
|
||||
value = parts[2]
|
||||
if value.isdigit() or (value.startswith('-') and value[1:].isdigit()):
|
||||
value = int(value)
|
||||
data[key] = value
|
||||
elif parts[0] == "LABEL":
|
||||
label = parts[1]
|
||||
sec = parts[2]
|
||||
pos = int(parts[3])
|
||||
labels[label] = pos
|
||||
label_sections[label] = sec
|
||||
elif parts[0] == "SYMBOL":
|
||||
name = parts[1]
|
||||
value = int(parts[2])
|
||||
symbols[name] = value
|
||||
|
||||
return data, labels, label_sections, symbols
|
||||
return resolved, unresolved
|
||||
|
||||
|
||||
# ========== ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ ПАРСИНГА AST ==========
|
||||
|
||||
def parse_ast_line(line):
|
||||
"""
|
||||
Универсальный разбор строки AST.
|
||||
Возвращает (тип, словарь_полей).
|
||||
|
||||
Форматы AST:
|
||||
- DIRECTIVE:имя
|
||||
- DIRECTIVE:имя:секция
|
||||
- DIRECTIVE:имя:секция:данные
|
||||
- DIRECTIVE:имя:имя_константы:значение
|
||||
- LABEL:имя:секция
|
||||
- INSTR:мнемоника:секция:операнд1,операнд2,...
|
||||
|
||||
Операнды могут содержать двоеточия (MEM:reg_indirect:рбикс).
|
||||
Поэтому для INSTR используется специальный разбор: первые 3 двоеточия
|
||||
отделяют служебные поля, остальное — операнды.
|
||||
"""
|
||||
if not line:
|
||||
return None, {}
|
||||
|
||||
line_type = line.split(':')[0]
|
||||
|
||||
if line_type == "INSTR":
|
||||
# Формат: INSTR:мнемоника:секция:операнды
|
||||
# Находим первые три двоеточия
|
||||
first_colon = line.find(':')
|
||||
second_colon = line.find(':', first_colon + 1)
|
||||
third_colon = line.find(':', second_colon + 1)
|
||||
|
||||
if first_colon == -1 or second_colon == -1 or third_colon == -1:
|
||||
return "INSTR", {}
|
||||
|
||||
mnemonic = line[first_colon + 1 : second_colon]
|
||||
section = line[second_colon + 1 : third_colon]
|
||||
operands_str = line[third_colon + 1 :]
|
||||
|
||||
operands = []
|
||||
if operands_str:
|
||||
operands = operands_str.split(',')
|
||||
|
||||
return "INSTR", {
|
||||
'mnemonic': mnemonic,
|
||||
'section': section,
|
||||
'operands': operands,
|
||||
'operands_str': operands_str
|
||||
}
|
||||
|
||||
elif line_type == "DIRECTIVE":
|
||||
parts = line.split(':')
|
||||
directive = parts[1] if len(parts) > 1 else ""
|
||||
|
||||
if directive in ('.текст', '.данные', '.бнд'):
|
||||
return "DIRECTIVE", {'directive': directive}
|
||||
|
||||
elif directive == '.глобал':
|
||||
label = parts[2] if len(parts) > 2 else ""
|
||||
return "DIRECTIVE", {'directive': directive, 'label': label}
|
||||
|
||||
elif directive in ('.строка_нуль', '.строка'):
|
||||
sec = parts[2] if len(parts) > 2 else ""
|
||||
s = parts[3] if len(parts) > 3 else ""
|
||||
return "DIRECTIVE", {'directive': directive, 'section': sec, 'string': s}
|
||||
|
||||
elif directive == '.константа':
|
||||
name = parts[2] if len(parts) > 2 else ""
|
||||
value = parts[3] if len(parts) > 3 else ""
|
||||
return "DIRECTIVE", {'directive': directive, 'name': name, 'value': value}
|
||||
|
||||
elif directive == '.байт':
|
||||
sec = parts[2] if len(parts) > 2 else ""
|
||||
bytes_str = parts[3] if len(parts) > 3 else ""
|
||||
return "DIRECTIVE", {'directive': directive, 'section': sec, 'bytes': bytes_str}
|
||||
|
||||
elif directive in ('.резб', '.резс', '.рездс', '.резкс'):
|
||||
sec = parts[2] if len(parts) > 2 else ""
|
||||
count = parts[3] if len(parts) > 3 else "0"
|
||||
return "DIRECTIVE", {'directive': directive, 'section': sec, 'count': count}
|
||||
|
||||
else:
|
||||
return "DIRECTIVE", {'directive': directive}
|
||||
|
||||
elif line_type == "LABEL":
|
||||
parts = line.split(':')
|
||||
label_name = parts[1] if len(parts) > 1 else ""
|
||||
sec = parts[2] if len(parts) > 2 else ""
|
||||
return "LABEL", {'name': label_name, 'section': sec}
|
||||
|
||||
return line_type, {}
|
||||
def save_csv(csv_file, headers, entries):
|
||||
"""Сохраняет обновлённый CSV файл"""
|
||||
with open(csv_file, 'w', newline='', encoding='utf-8') as f:
|
||||
writer = csv.writer(f, delimiter=';')
|
||||
writer.writerow(headers)
|
||||
writer.writerows(entries)
|
||||
|
||||
|
||||
# ========== ОСНОВНОЙ КЛАСС ВТОРОГО ПРОХОДА ==========
|
||||
|
||||
class Pass2:
|
||||
def __init__(self, pass1_data, labels, label_sections, symbols):
|
||||
self.labels = labels
|
||||
self.label_sections = label_sections
|
||||
self.symbols = symbols
|
||||
self.vaddr_text = pass1_data["vaddr_text"]
|
||||
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 = []
|
||||
self.data_bytes = {".text": bytearray(), ".data": bytearray()}
|
||||
|
||||
def get_target_addr(self, mnemonic, operands):
|
||||
"""Вычисляет целевой адрес для инструкций перехода"""
|
||||
jump_instructions = {
|
||||
"переход", "короткий_переход", "вызвать", "цикл",
|
||||
"переход_если_равно", "переход_если_неравно", "переход_если_меньше",
|
||||
"переход_если_больше", "переход_если_меньше_или_равно", "переход_если_больше_или_равно",
|
||||
"переход_если_перенос", "переход_если_нет_переноса", "переход_если_ноль", "переход_если_не_ноль",
|
||||
"короткий_переход_если_равно", "короткий_переход_если_неравно", "короткий_переход_если_меньше",
|
||||
"короткий_переход_если_больше", "короткий_переход_если_меньше_или_равно", "короткий_переход_если_больше_или_равно",
|
||||
"короткий_переход_если_перенос", "короткий_переход_если_нет_переноса",
|
||||
"короткий_переход_если_ноль", "короткий_переход_если_не_ноль"
|
||||
}
|
||||
|
||||
try:
|
||||
if mnemonic in jump_instructions:
|
||||
target = parse_operand(operands[0], self.labels, self.label_sections,
|
||||
self.symbols, self.vaddr_text, self.vaddr_data)
|
||||
return hex(target)
|
||||
elif mnemonic == "переместить_имм" and len(operands) >= 2:
|
||||
op_str = operands[1]
|
||||
if op_str in self.labels:
|
||||
sec = self.label_sections[op_str]
|
||||
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])
|
||||
except Exception:
|
||||
return "ошибка"
|
||||
|
||||
return ""
|
||||
def print_statistics(labels_count, resolved, unresolved, vaddr_text, vaddr_data):
|
||||
"""Выводит статистику по разрешению меток"""
|
||||
print(f"\n--- Статистика разрешения меток ---")
|
||||
print(f" Виртуальный адрес .text: 0x{vaddr_text:x}")
|
||||
print(f" Виртуальный адрес .data: 0x{vaddr_data:x}")
|
||||
print(f" Всего приводящих меток: {labels_count}")
|
||||
print(f" Разрешено заглушек: {len(resolved)}")
|
||||
print(f" Не разрешено заглушек (возможно константы): {len(unresolved)}")
|
||||
|
||||
def process_line(self, line):
|
||||
"""Обрабатывает одну строку AST"""
|
||||
line_type, fields = parse_ast_line(line)
|
||||
if resolved:
|
||||
unique_resolved = {}
|
||||
for name, file_addr, virt_addr in resolved:
|
||||
if name not in unique_resolved:
|
||||
unique_resolved[name] = (file_addr, virt_addr)
|
||||
|
||||
if line_type == "DIRECTIVE":
|
||||
directive = fields.get('directive', '')
|
||||
|
||||
if directive == '.текст':
|
||||
self.current_section = ".text"
|
||||
elif directive == '.данные':
|
||||
self.current_section = ".data"
|
||||
elif directive in ('.строка_нуль', '.строка'):
|
||||
s = fields.get('string', '')
|
||||
real_s = unescape_string(s)
|
||||
bstring = real_s.encode('utf-8')
|
||||
if directive == '.строка_нуль':
|
||||
bstring += b'\x00'
|
||||
|
||||
original_cmd = f'{directive} "{s}"'
|
||||
start_addr = self.vaddr_data + self.position[".data"]
|
||||
|
||||
for i, byte in enumerate(bstring):
|
||||
addr = start_addr + i
|
||||
byte_hex = "{:02X}".format(byte)
|
||||
cmd = original_cmd if i == 0 else ""
|
||||
self.csv_lines.append((hex(addr), byte_hex, "", cmd))
|
||||
|
||||
self.data_bytes[".data"] += bstring
|
||||
self.position[".data"] += len(bstring)
|
||||
|
||||
elif directive == '.байт':
|
||||
bytes_str = fields.get('bytes', '')
|
||||
if bytes_str:
|
||||
byte_values = bytes_str.split(',')
|
||||
original_cmd = f".байт {bytes_str}"
|
||||
start_addr = self.vaddr_data + self.position[".data"]
|
||||
|
||||
for i, byte_str in enumerate(byte_values):
|
||||
if byte_str.startswith('0x'):
|
||||
val = int(byte_str, 16)
|
||||
elif byte_str.isdigit() or (byte_str.startswith('-') and byte_str[1:].isdigit()):
|
||||
val = int(byte_str)
|
||||
else:
|
||||
continue
|
||||
|
||||
addr = start_addr + i
|
||||
byte_hex = "{:02X}".format(val & 0xFF)
|
||||
cmd = original_cmd if i == 0 else ""
|
||||
self.csv_lines.append((hex(addr), byte_hex, "", cmd))
|
||||
self.data_bytes[".data"].append(val & 0xFF)
|
||||
|
||||
self.position[".data"] += len(byte_values)
|
||||
|
||||
elif line_type == "LABEL":
|
||||
label_name = fields.get('name', '')
|
||||
sec = fields.get('section', '')
|
||||
if label_name in self.labels:
|
||||
self.position[sec] = self.labels[label_name]
|
||||
|
||||
elif line_type == "INSTR":
|
||||
mnemonic = fields.get('mnemonic', '')
|
||||
sec = fields.get('section', '')
|
||||
operands = fields.get('operands', [])
|
||||
|
||||
if operands:
|
||||
original_cmd = f"{mnemonic} {', '.join(operands)}"
|
||||
else:
|
||||
original_cmd = mnemonic
|
||||
|
||||
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.vaddr_bnd)
|
||||
|
||||
target_addr = self.get_target_addr(mnemonic, operands)
|
||||
|
||||
start_addr = (self.vaddr_text if sec == ".text" else self.vaddr_data) + current_pos
|
||||
|
||||
for i, byte in enumerate(code):
|
||||
addr = start_addr + i
|
||||
byte_hex = "{:02X}".format(byte)
|
||||
cmd = original_cmd if i == 0 else ""
|
||||
addr_target = target_addr if i == 0 else ""
|
||||
self.csv_lines.append((hex(addr), byte_hex, addr_target, cmd))
|
||||
|
||||
self.data_bytes[sec] += code
|
||||
self.position[sec] += len(code)
|
||||
print(f"\n--- Разрешённые заглушки (первые 20) ---")
|
||||
for i, (name, (file_addr, virt_addr)) in enumerate(list(unique_resolved.items())[:20]):
|
||||
print(f" {name} -> файл:0x{file_addr:08x}, вирт:0x{virt_addr:08x}")
|
||||
if len(unique_resolved) > 20:
|
||||
print(f" ... и ещё {len(unique_resolved) - 20}")
|
||||
|
||||
def process_all(self, ast_lines):
|
||||
"""Обрабатывает все строки AST"""
|
||||
for line in ast_lines:
|
||||
self.process_line(line)
|
||||
return self.csv_lines
|
||||
if unresolved:
|
||||
unresolved_counts = Counter(unresolved)
|
||||
print(f"\n--- Неразрешённые заглушки (возможно константы) ---")
|
||||
for name, count in sorted(unresolved_counts.items(), key=lambda x: x[1], reverse=True)[:20]:
|
||||
print(f" {name}: {count} раз(а)")
|
||||
if len(unresolved_counts) > 20:
|
||||
print(f" ... и ещё {len(unresolved_counts) - 20} различных имён")
|
||||
|
||||
|
||||
def write_csv(csv_lines, output_file):
|
||||
"""Записывает сгенерированные байты в CSV файл"""
|
||||
with open(output_file, 'w', encoding='utf-8') as f:
|
||||
f.write("адрес;байт;целевой_адрес;исходная_команда\n")
|
||||
for addr, byte, target, cmd in csv_lines:
|
||||
if cmd and (';' in cmd or '\n' in cmd):
|
||||
cmd = '"' + cmd.replace('"', '""') + '"'
|
||||
f.write(f"{addr};{byte};{target};{cmd}\n")
|
||||
def main():
|
||||
if len(sys.argv) != 2:
|
||||
print("Использование: python kvs_pass2.py <входной.csv>")
|
||||
sys.exit(1)
|
||||
|
||||
csv_file = sys.argv[1]
|
||||
|
||||
print(f"\n=== Второй проход КВС ===")
|
||||
print(f"Чтение CSV: {csv_file}")
|
||||
|
||||
headers, entries = read_csv(csv_file)
|
||||
|
||||
vaddr_text, vaddr_data = get_virtual_addresses(entries, headers)
|
||||
print(f"Виртуальный адрес .text: 0x{vaddr_text:x}")
|
||||
print(f"Виртуальный адрес .data: 0x{vaddr_data:x}")
|
||||
|
||||
print(f"\n--- Сбор приводящих меток ---")
|
||||
labels_file, labels_virt = collect_labels(entries, headers, vaddr_text, vaddr_data)
|
||||
print(f"Найдено приводящих меток: {len(labels_file)}")
|
||||
|
||||
if labels_file:
|
||||
print(f"\n--- Примеры приводящих меток (первые 20) ---")
|
||||
for i, name in enumerate(list(labels_file.keys())[:20]):
|
||||
print(f" {name} -> файл:0x{labels_file[name]:08x}, вирт:0x{labels_virt[name]:08x}")
|
||||
if len(labels_file) > 20:
|
||||
print(f" ... и ещё {len(labels_file) - 20}")
|
||||
|
||||
print(f"\n--- Разрешение уводящих адресов и формирование команд ---")
|
||||
resolved, unresolved = resolve_targets(entries, headers, labels_file, labels_virt)
|
||||
|
||||
print_statistics(len(labels_file), resolved, unresolved, vaddr_text, vaddr_data)
|
||||
|
||||
save_csv(csv_file, headers, entries)
|
||||
print(f"\nCSV сохранен: {csv_file}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) != 4:
|
||||
print("Использование: python kvs_pass2.py <вход.аст> <вход.проход1> <выход.csv>")
|
||||
sys.exit(1)
|
||||
|
||||
ast_lines = read_ast(sys.argv[1])
|
||||
pass1_data, labels, label_sections, symbols = read_pass1(sys.argv[2])
|
||||
|
||||
pass2 = Pass2(pass1_data, labels, label_sections, symbols)
|
||||
csv_lines = pass2.process_all(ast_lines)
|
||||
write_csv(csv_lines, sys.argv[3])
|
||||
|
||||
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}")
|
||||
main()
|
||||
141
kvs_pass3.py
Normal file
141
kvs_pass3.py
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Третий проход КВС
|
||||
- Читает AST для получения констант
|
||||
- Заменяет имена констант в 'исходная_команда' на их числовые значения
|
||||
- Записывает результат в колонку 'команда_со_значениями'
|
||||
- Поддерживает константы в операндах (как непосредственные значения)
|
||||
"""
|
||||
|
||||
import sys
|
||||
import csv
|
||||
|
||||
|
||||
def read_ast(ast_file):
|
||||
"""Читает AST файл и извлекает константы"""
|
||||
symbols = {} # имя константы -> значение
|
||||
|
||||
with open(ast_file, 'r', encoding='utf-8') as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
|
||||
parts = line.split(':')
|
||||
if parts[0] == "DIRECTIVE" and len(parts) >= 4:
|
||||
directive = parts[1]
|
||||
if directive == '.константа':
|
||||
name = parts[2]
|
||||
value_str = parts[3]
|
||||
if value_str.startswith('0x') or value_str.startswith('0X'):
|
||||
value = int(value_str, 16)
|
||||
else:
|
||||
value = int(value_str)
|
||||
symbols[name] = value
|
||||
print(f" константа: {name} = {value}")
|
||||
|
||||
return symbols
|
||||
|
||||
|
||||
def read_csv(csv_file):
|
||||
"""Читает CSV файл и возвращает список записей и заголовки"""
|
||||
entries = []
|
||||
headers = []
|
||||
|
||||
with open(csv_file, 'r', encoding='utf-8') as f:
|
||||
reader = csv.reader(f, delimiter=';')
|
||||
headers = next(reader)
|
||||
for row in reader:
|
||||
entries.append(row)
|
||||
|
||||
return headers, entries
|
||||
|
||||
|
||||
def substitute_constants(entries, headers, symbols):
|
||||
"""Заменяет константы в исходной команде на их значения"""
|
||||
try:
|
||||
source_idx = headers.index('исходная_команда')
|
||||
source_with_values_idx = headers.index('команда_со_значениями')
|
||||
except ValueError as e:
|
||||
print(f"Ошибка: не найдена нужная колонка в CSV: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
substituted_count = 0
|
||||
|
||||
for row in entries:
|
||||
source = row[source_idx].strip()
|
||||
if not source:
|
||||
continue
|
||||
|
||||
# Копируем исходную команду
|
||||
new_source = source
|
||||
|
||||
# Заменяем константы в команде
|
||||
for name, value in symbols.items():
|
||||
if name in new_source:
|
||||
# Заменяем имя константы на её значение
|
||||
new_source = new_source.replace(name, str(value))
|
||||
|
||||
# Если команда изменилась, записываем в колонку команда_со_значениями
|
||||
if new_source != source:
|
||||
row[source_with_values_idx] = new_source
|
||||
substituted_count += 1
|
||||
|
||||
return substituted_count
|
||||
|
||||
|
||||
def save_csv(csv_file, headers, entries):
|
||||
"""Сохраняет обновлённый CSV файл"""
|
||||
with open(csv_file, 'w', newline='', encoding='utf-8') as f:
|
||||
writer = csv.writer(f, delimiter=';')
|
||||
writer.writerow(headers)
|
||||
writer.writerows(entries)
|
||||
|
||||
|
||||
def print_statistics(symbols_count, substituted_count, symbols):
|
||||
"""Выводит статистику по заменам констант"""
|
||||
print(f"\n--- Статистика замены констант ---")
|
||||
print(f" Всего констант в AST: {symbols_count}")
|
||||
print(f" Заменено в командах: {substituted_count}")
|
||||
|
||||
if symbols:
|
||||
print(f"\n--- Найденные константы ---")
|
||||
for name, value in sorted(symbols.items()):
|
||||
print(f" {name} = {value}")
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 3:
|
||||
print("Использование: python kvs_pass3.py <аст.файл> <входной.csv>")
|
||||
print(" <аст.файл> - файл с AST (например, программа.аст)")
|
||||
print(" <входной.csv> - CSV файл для обновления")
|
||||
sys.exit(1)
|
||||
|
||||
ast_file = sys.argv[1]
|
||||
csv_file = sys.argv[2]
|
||||
|
||||
print(f"\n=== Третий проход КВС ===")
|
||||
print(f"Чтение AST: {ast_file}")
|
||||
|
||||
# Читаем константы из AST
|
||||
symbols = read_ast(ast_file)
|
||||
print(f"Найдено констант: {len(symbols)}")
|
||||
|
||||
print(f"\nЧтение CSV: {csv_file}")
|
||||
headers, entries = read_csv(csv_file)
|
||||
|
||||
print(f"\n--- Замена констант в командах ---")
|
||||
substituted_count = substitute_constants(entries, headers, symbols)
|
||||
|
||||
print_statistics(len(symbols), substituted_count, symbols)
|
||||
|
||||
# Сохраняем результат
|
||||
save_csv(csv_file, headers, entries)
|
||||
print(f"\nCSV сохранен: {csv_file}")
|
||||
print(f"Колонка 'команда_со_значениями' обновлена")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
262
kvs_pass4.py
Normal file
262
kvs_pass4.py
Normal file
|
|
@ -0,0 +1,262 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Четвёртый проход КВС
|
||||
- Перекодирует инструкции, используя подставленные значения
|
||||
- Смотрит колонки 'команда_со_значениями' и 'рассчитанный_уводящий_адрес'
|
||||
- Записывает перекодированные байты в колонку 'рассчитанный_байт'
|
||||
"""
|
||||
|
||||
import sys
|
||||
import csv
|
||||
import struct
|
||||
|
||||
sys.path.insert(0, '.')
|
||||
from kvs_data import PAGE_SIZE, text_vaddr_base, align_up
|
||||
from kvs_encoder import encode_instruction
|
||||
|
||||
# ========== ГЛОБАЛЬНОЕ СОСТОЯНИЕ ==========
|
||||
vaddr_text = text_vaddr_base
|
||||
vaddr_data = None
|
||||
vaddr_bnd = None
|
||||
|
||||
labels = {} # имя метки -> адрес
|
||||
label_sections = {} # имя метки -> секция
|
||||
symbols = {} # имя константы -> значение
|
||||
|
||||
|
||||
def read_csv(csv_file):
|
||||
"""Читает CSV файл и возвращает список записей и заголовки"""
|
||||
entries = []
|
||||
headers = []
|
||||
|
||||
with open(csv_file, 'r', encoding='utf-8') as f:
|
||||
reader = csv.reader(f, delimiter=';')
|
||||
headers = next(reader)
|
||||
for row in reader:
|
||||
entries.append(row)
|
||||
|
||||
return headers, entries
|
||||
|
||||
|
||||
def parse_command(cmd_str):
|
||||
"""Разбирает команду вида 'мнемоника операнд1, операнд2, ...'"""
|
||||
if not cmd_str:
|
||||
return None, []
|
||||
|
||||
parts = cmd_str.split(' ', 1)
|
||||
mnemonic = parts[0]
|
||||
|
||||
operands = []
|
||||
if len(parts) > 1 and parts[1]:
|
||||
# Разбираем операнды, разделённые запятыми
|
||||
operands = [op.strip() for op in parts[1].split(',')]
|
||||
|
||||
return mnemonic, operands
|
||||
|
||||
|
||||
def collect_labels_from_csv(entries, headers):
|
||||
"""Собирает метки из CSV для перекодирования"""
|
||||
global labels, label_sections, vaddr_data, vaddr_bnd
|
||||
|
||||
try:
|
||||
label_idx = headers.index('приводящая_метка')
|
||||
addr_idx = headers.index('адрес')
|
||||
segment_idx = headers.index('сегмент')
|
||||
byte_idx = headers.index('байт')
|
||||
except ValueError as e:
|
||||
print(f"Ошибка: не найдена нужная колонка в CSV: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
# Сначала нужно определить виртуальные адреса секций
|
||||
max_addr = 0
|
||||
for row in entries:
|
||||
addr_str = row[addr_idx].strip()
|
||||
if addr_str.startswith('0x'):
|
||||
addr = int(addr_str, 16)
|
||||
if addr > max_addr:
|
||||
max_addr = addr
|
||||
segment = row[segment_idx].strip()
|
||||
|
||||
# Определяем vaddr_data по первому адресу в .data
|
||||
if segment == '.data' and vaddr_data is None:
|
||||
vaddr_data = addr
|
||||
# Определяем vaddr_bnd по первому адресу в .bss
|
||||
elif segment == '.bss' and vaddr_bnd is None:
|
||||
vaddr_bnd = addr
|
||||
|
||||
if vaddr_data is None:
|
||||
vaddr_data = align_up(vaddr_text + max_addr, PAGE_SIZE)
|
||||
if vaddr_bnd is None:
|
||||
vaddr_bnd = align_up(vaddr_data + max_addr, PAGE_SIZE)
|
||||
|
||||
# Собираем метки
|
||||
for row in entries:
|
||||
label_str = row[label_idx].strip()
|
||||
if label_str:
|
||||
addr_str = row[addr_idx].strip()
|
||||
if addr_str.startswith('0x'):
|
||||
addr = int(addr_str, 16)
|
||||
for label_name in label_str.split(','):
|
||||
label_name = label_name.strip()
|
||||
if label_name:
|
||||
labels[label_name] = addr
|
||||
# Определяем секцию по адресу
|
||||
if addr >= vaddr_text and addr < vaddr_text + PAGE_SIZE:
|
||||
label_sections[label_name] = '.text'
|
||||
elif vaddr_data and addr >= vaddr_data and addr < vaddr_data + PAGE_SIZE:
|
||||
label_sections[label_name] = '.data'
|
||||
elif vaddr_bnd and addr >= vaddr_bnd:
|
||||
label_sections[label_name] = '.bss'
|
||||
|
||||
|
||||
def reencode_instructions(entries, headers):
|
||||
"""Перекодирует инструкции, используя подставленные значения"""
|
||||
try:
|
||||
source_with_values_idx = headers.index('команда_со_значениями')
|
||||
calc_target_idx = headers.index('рассчитанный_уводящий_адрес')
|
||||
calc_byte_idx = headers.index('рассчитанный_байт')
|
||||
addr_idx = headers.index('адрес')
|
||||
segment_idx = headers.index('сегмент')
|
||||
byte_idx = headers.index('байт')
|
||||
except ValueError as e:
|
||||
print(f"Ошибка: не найдена нужная колонка в CSV: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
reencoded_count = 0
|
||||
error_count = 0
|
||||
|
||||
# Проходим по всем строкам
|
||||
i = 0
|
||||
while i < len(entries):
|
||||
row = entries[i]
|
||||
addr_str = row[addr_idx].strip()
|
||||
if not addr_str.startswith('0x'):
|
||||
i += 1
|
||||
continue
|
||||
|
||||
addr = int(addr_str, 16)
|
||||
segment = row[segment_idx].strip()
|
||||
|
||||
# Проверяем, есть ли команда для перекодирования
|
||||
cmd = row[source_with_values_idx].strip()
|
||||
calc_target = row[calc_target_idx].strip()
|
||||
|
||||
# Определяем, нужно ли перекодировать
|
||||
need_reencode = False
|
||||
|
||||
if cmd:
|
||||
# Есть команда с подставленными константами
|
||||
need_reencode = True
|
||||
elif calc_target and calc_target.startswith('0x'):
|
||||
# Есть рассчитанный адрес для заглушки
|
||||
# Нужно взять исходную команду и подставить адрес
|
||||
source_idx = headers.index('исходная_команда')
|
||||
source = row[source_idx].strip()
|
||||
if source:
|
||||
# Заменяем ЗАГЛУШКА имя на реальный адрес
|
||||
target_addr = int(calc_target, 16)
|
||||
cmd = source.replace('ЗАГЛУШКА', '').strip()
|
||||
# Добавляем адрес как операнд
|
||||
cmd = f"{cmd} 0x{target_addr:08x}"
|
||||
need_reencode = True
|
||||
|
||||
if need_reencode and cmd:
|
||||
try:
|
||||
mnemonic, operands = parse_command(cmd)
|
||||
if mnemonic:
|
||||
# Вычисляем текущую позицию в секции
|
||||
if segment == '.text':
|
||||
current_pos = addr - vaddr_text
|
||||
elif segment == '.data' and vaddr_data:
|
||||
current_pos = addr - vaddr_data
|
||||
else:
|
||||
current_pos = 0
|
||||
|
||||
# Кодируем инструкцию
|
||||
encoded = encode_instruction(
|
||||
mnemonic, operands, labels, label_sections, symbols,
|
||||
vaddr_text, vaddr_data if vaddr_data else 0,
|
||||
current_pos, vaddr_bnd if vaddr_bnd else 0
|
||||
)
|
||||
|
||||
# Записываем байты в колонку рассчитанный_байт
|
||||
# Для много-байтовых инструкций записываем в последовательные строки
|
||||
for j, byte in enumerate(encoded):
|
||||
if i + j < len(entries):
|
||||
entries[i + j][calc_byte_idx] = f"0x{byte:02x}"
|
||||
else:
|
||||
# Не хватает строк, создаём новую
|
||||
# (в нормальной ситуации не должно происходить)
|
||||
pass
|
||||
|
||||
reencoded_count += 1
|
||||
|
||||
# Пропускаем следующие строки, принадлежащие этой инструкции
|
||||
# (обычно в CSV одна строка = один байт)
|
||||
i += len(encoded)
|
||||
continue
|
||||
|
||||
except Exception as e:
|
||||
print(f"Ошибка перекодирования '{cmd}': {e}")
|
||||
error_count += 1
|
||||
# Записываем INT3 как заглушку
|
||||
row[calc_byte_idx] = "0xcc"
|
||||
i += 1
|
||||
else:
|
||||
# Если нет команды для перекодирования, просто копируем исходный байт
|
||||
byte_str = row[byte_idx].strip()
|
||||
if byte_str.startswith('0x'):
|
||||
row[calc_byte_idx] = byte_str
|
||||
i += 1
|
||||
|
||||
return reencoded_count, error_count
|
||||
|
||||
|
||||
def save_csv(csv_file, headers, entries):
|
||||
"""Сохраняет обновлённый CSV файл"""
|
||||
with open(csv_file, 'w', newline='', encoding='utf-8') as f:
|
||||
writer = csv.writer(f, delimiter=';')
|
||||
writer.writerow(headers)
|
||||
writer.writerows(entries)
|
||||
|
||||
|
||||
def print_statistics(reencoded_count, error_count):
|
||||
"""Выводит статистику перекодирования"""
|
||||
print(f"\n--- Статистика перекодирования ---")
|
||||
print(f" Перекодировано инструкций: {reencoded_count}")
|
||||
if error_count:
|
||||
print(f" Ошибок: {error_count}")
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 2:
|
||||
print("Использование: python kvs_pass4.py <входной.csv>")
|
||||
sys.exit(1)
|
||||
|
||||
csv_file = sys.argv[1]
|
||||
|
||||
print(f"\n=== Четвёртый проход КВС ===")
|
||||
print(f"Чтение CSV: {csv_file}")
|
||||
|
||||
# Читаем CSV
|
||||
headers, entries = read_csv(csv_file)
|
||||
|
||||
print(f"\n--- Сбор меток из CSV ---")
|
||||
collect_labels_from_csv(entries, headers)
|
||||
print(f"Найдено меток: {len(labels)}")
|
||||
|
||||
print(f"\n--- Перекодирование инструкций ---")
|
||||
reencoded_count, error_count = reencode_instructions(entries, headers)
|
||||
|
||||
print_statistics(reencoded_count, error_count)
|
||||
|
||||
# Сохраняем результат
|
||||
save_csv(csv_file, headers, entries)
|
||||
print(f"\nCSV сохранен: {csv_file}")
|
||||
print(f"Колонка 'рассчитанный_байт' обновлена")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
249
kvs_verify.py
249
kvs_verify.py
|
|
@ -1,249 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Верификатор КВС
|
||||
Сравнивает размеры инструкций из pass1 с реальными размерами из CSV.
|
||||
Выводит расхождения и останавливает сборку при ошибках.
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
# Если True — разрешает сборку, когда единственная ошибка это общий размер .text
|
||||
# (расхождение до 16 байт считается допустимым)
|
||||
ENABLE = False
|
||||
ALLOW_TEXT_SIZE_MISMATCH = True
|
||||
MAX_TEXT_SIZE_MISMATCH = 25
|
||||
|
||||
|
||||
def read_pass1(input_file):
|
||||
"""Читает pass1-файл: PARAM и LABEL"""
|
||||
params = {}
|
||||
labels = {}
|
||||
label_sections = {}
|
||||
|
||||
with open(input_file, 'r', encoding='utf-8') as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
parts = line.split(':')
|
||||
if parts[0] == "PARAM":
|
||||
key = parts[1]
|
||||
value = parts[2]
|
||||
if value.isdigit() or (value.startswith('-') and value[1:].isdigit()):
|
||||
value = int(value)
|
||||
params[key] = value
|
||||
elif parts[0] == "LABEL":
|
||||
label = parts[1]
|
||||
sec = parts[2]
|
||||
pos = int(parts[3])
|
||||
labels[label] = pos
|
||||
label_sections[label] = sec
|
||||
|
||||
return params, labels, label_sections
|
||||
|
||||
|
||||
def read_csv(input_file):
|
||||
"""
|
||||
Читает CSV-файл.
|
||||
Возвращает:
|
||||
- instr_list: список инструкций с адресами и размерами
|
||||
"""
|
||||
instr_list = []
|
||||
current_cmd = None
|
||||
current_start = None
|
||||
current_size = 0
|
||||
|
||||
with open(input_file, 'r', encoding='utf-8') as f:
|
||||
header = f.readline()
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
parts = line.split(';')
|
||||
if len(parts) < 2:
|
||||
continue
|
||||
|
||||
addr_str = parts[0]
|
||||
byte_str = parts[1]
|
||||
cmd_str = parts[3] if len(parts) > 3 else ""
|
||||
|
||||
try:
|
||||
addr = int(addr_str, 16)
|
||||
except ValueError:
|
||||
continue
|
||||
|
||||
if addr >= 0x402000:
|
||||
break
|
||||
|
||||
if cmd_str:
|
||||
if current_cmd is not None:
|
||||
instr_list.append({
|
||||
'cmd': current_cmd,
|
||||
'start': current_start,
|
||||
'size': current_size
|
||||
})
|
||||
current_cmd = cmd_str
|
||||
current_start = addr
|
||||
current_size = 1
|
||||
else:
|
||||
current_size += 1
|
||||
|
||||
if current_cmd is not None:
|
||||
instr_list.append({
|
||||
'cmd': current_cmd,
|
||||
'start': current_start,
|
||||
'size': current_size
|
||||
})
|
||||
|
||||
return instr_list
|
||||
|
||||
|
||||
def verify(pass1_file, csv_file):
|
||||
"""Сравнивает pass1 и pass2, возвращает список ошибок"""
|
||||
from kvs_data import FIXED_SIZE_INSTRUCTIONS, INSTRUCTIONS
|
||||
|
||||
params, labels, label_sections = read_pass1(pass1_file)
|
||||
instr_list = read_csv(csv_file)
|
||||
|
||||
vaddr_text = params.get("vaddr_text", 0x401000)
|
||||
text_size_pass1 = params.get("text_size", 0)
|
||||
text_size_pass2 = sum(instr['size'] for instr in instr_list)
|
||||
|
||||
errors = []
|
||||
warnings = []
|
||||
|
||||
print(f"Pass1 .text: {text_size_pass1} байт")
|
||||
print(f"Pass2 .text: {text_size_pass2} байт")
|
||||
print()
|
||||
|
||||
# Проверка общего размера
|
||||
text_size_error = None
|
||||
if text_size_pass1 != text_size_pass2:
|
||||
diff = text_size_pass2 - text_size_pass1
|
||||
text_size_error = f"Общий размер .text: pass1={text_size_pass1}, pass2={text_size_pass2} (разница {diff:+d} байт)"
|
||||
if ALLOW_TEXT_SIZE_MISMATCH and abs(diff) <= MAX_TEXT_SIZE_MISMATCH:
|
||||
warnings.append(text_size_error + " — допустимо, сборка продолжена")
|
||||
else:
|
||||
errors.append(text_size_error)
|
||||
|
||||
# Проверка позиций меток
|
||||
print("Проверка позиций меток (.text):")
|
||||
for label, pass1_offset in labels.items():
|
||||
if label_sections.get(label) != ".text":
|
||||
continue
|
||||
|
||||
pass1_addr = vaddr_text + pass1_offset
|
||||
|
||||
found = False
|
||||
for instr in instr_list:
|
||||
if instr['start'] == pass1_addr:
|
||||
found = True
|
||||
break
|
||||
|
||||
if found:
|
||||
print(f" [✓] {label} — 0x{pass1_addr:x}")
|
||||
else:
|
||||
closest = None
|
||||
for instr in instr_list:
|
||||
if instr['start'] <= pass1_addr:
|
||||
closest = instr
|
||||
|
||||
if closest:
|
||||
real_addr = closest['start']
|
||||
shift = real_addr - pass1_addr
|
||||
if shift != 0:
|
||||
errors.append(f"Метка '{label}': pass1=0x{pass1_addr:x}, pass2=0x{real_addr:x} (сдвиг {shift:+d} байт)")
|
||||
print(f" [✗] {label} — pass1: 0x{pass1_addr:x}, pass2: 0x{real_addr:x} (сдвиг {shift:+d})")
|
||||
else:
|
||||
print(f" [✓] {label} — 0x{pass1_addr:x}")
|
||||
else:
|
||||
warnings.append(f"Метка '{label}' не найдена в CSV")
|
||||
print(f" [?] {label} — не найдена в CSV")
|
||||
|
||||
print()
|
||||
|
||||
# Сравнение размеров инструкций
|
||||
print("Проверка размеров инструкций:")
|
||||
|
||||
for instr in instr_list:
|
||||
cmd = instr['cmd']
|
||||
real_size = instr['size']
|
||||
real_addr = instr['start']
|
||||
|
||||
mnemonic = cmd.split()[0] if cmd else ""
|
||||
|
||||
if mnemonic in FIXED_SIZE_INSTRUCTIONS:
|
||||
pass1_size = FIXED_SIZE_INSTRUCTIONS[mnemonic]
|
||||
elif mnemonic in ("загрузить", "сохранить", "загрузить_адрес"):
|
||||
if 'MEM:reg_indirect:' in cmd:
|
||||
pass1_size = 3
|
||||
else:
|
||||
pass1_size = 7
|
||||
elif mnemonic in ("втолкнуть", "вытолкнуть"):
|
||||
parts = cmd.split()
|
||||
if len(parts) >= 2:
|
||||
reg = parts[1]
|
||||
if reg in ('р8', 'р9', 'р10', 'р11', 'р12', 'р13', 'р14', 'р15'):
|
||||
pass1_size = 2
|
||||
else:
|
||||
pass1_size = 1
|
||||
else:
|
||||
pass1_size = 1
|
||||
elif mnemonic in ("прибавить_непосредственно", "вычесть_непосредственно", "сравнить_с"):
|
||||
pass1_size = 7
|
||||
elif mnemonic == "переместить_имм":
|
||||
pass1_size = 10
|
||||
elif mnemonic in ("переместить_с_нулями", "переместить_со_знаком"):
|
||||
pass1_size = 8
|
||||
elif mnemonic == "загрузить_байт":
|
||||
pass1_size = 2
|
||||
elif mnemonic == "втолкнуть_непосредственно":
|
||||
pass1_size = 5
|
||||
else:
|
||||
instr_info = INSTRUCTIONS.get(mnemonic)
|
||||
if instr_info and "opcode" in instr_info and instr_info["opcode"] is not None:
|
||||
pass1_size = len(instr_info["opcode"])
|
||||
else:
|
||||
pass1_size = 3
|
||||
|
||||
status = "✓" if pass1_size == real_size else "✗"
|
||||
if pass1_size != real_size:
|
||||
diff = real_size - pass1_size
|
||||
errors.append(f"Инструкция '{cmd}' на 0x{real_addr:x}: pass1={pass1_size}, pass2={real_size} (ошибка {diff:+d})")
|
||||
|
||||
print(f" [{status}] 0x{real_addr:x} {cmd} — pass1: {pass1_size}, pass2: {real_size}" +
|
||||
(f" (ошибка {real_size - pass1_size:+d})" if pass1_size != real_size else ""))
|
||||
|
||||
print()
|
||||
|
||||
return errors, warnings
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if ENABLE:
|
||||
if len(sys.argv) != 3:
|
||||
print("Использование: python kvs_verify.py <вход.проход1> <вход.csv>")
|
||||
sys.exit(1)
|
||||
|
||||
pass1_file = sys.argv[1]
|
||||
csv_file = sys.argv[2]
|
||||
|
||||
errors, warnings = verify(pass1_file, csv_file)
|
||||
|
||||
if warnings:
|
||||
print(f"Предупреждений: {len(warnings)}")
|
||||
for w in warnings:
|
||||
print(f" ⚠ {w}")
|
||||
print()
|
||||
|
||||
if errors:
|
||||
print(f"ОШИБОК: {len(errors)}")
|
||||
for e in errors:
|
||||
print(f" ❌ {e}")
|
||||
print("\nСборка остановлена. Исправьте расхождения в размерах инструкций.")
|
||||
sys.exit(1)
|
||||
else:
|
||||
print("Все размеры инструкций совпадают. Можно собирать.")
|
||||
sys.exit(0)
|
||||
237
инструменты/kvs_csv_builder.py
Normal file
237
инструменты/kvs_csv_builder.py
Normal file
|
|
@ -0,0 +1,237 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Генератор CSV-таблицы для программы на КВС (функциональная версия)
|
||||
Экспериментальный однопроходный ассемблер - с корректными заглушками ELF
|
||||
"""
|
||||
|
||||
import sys
|
||||
import csv
|
||||
from typing import List, Optional, Tuple
|
||||
|
||||
# Глобальное состояние
|
||||
entries = [] # Список записей: (address, byte, target, source, segment)
|
||||
current_address = 0
|
||||
current_segment = '.header'
|
||||
last_segment = None
|
||||
relocations = [] # Список отложенных ссылок: (pos, label, type, source)
|
||||
|
||||
def reset_state():
|
||||
"""Сбросить состояние генератора"""
|
||||
global entries, current_address, current_segment, last_segment, relocations
|
||||
entries = []
|
||||
current_address = 0
|
||||
current_segment = '.header'
|
||||
last_segment = None
|
||||
relocations = []
|
||||
|
||||
def set_segment(segment: str):
|
||||
"""Переключить текущий сегмент"""
|
||||
global current_segment
|
||||
current_segment = segment
|
||||
|
||||
def add_byte(value: int, source: str = "", target: Optional[int] = None):
|
||||
"""Добавить один байт"""
|
||||
global current_address, last_segment
|
||||
|
||||
# Показываем сегмент только при смене
|
||||
show_segment = current_segment if current_segment != last_segment else None
|
||||
if show_segment:
|
||||
last_segment = current_segment
|
||||
|
||||
entries.append((
|
||||
current_address,
|
||||
value & 0xFF,
|
||||
target,
|
||||
source,
|
||||
show_segment
|
||||
))
|
||||
current_address += 1
|
||||
|
||||
def add_bytes(values: List[int], source: str = ""):
|
||||
"""Добавить последовательность байтов"""
|
||||
for v in values:
|
||||
add_byte(v, source)
|
||||
|
||||
def add_word32(value: int, source: str = ""):
|
||||
"""Добавить 32-битное слово (little-endian)"""
|
||||
add_bytes([
|
||||
(value >> 0) & 0xFF,
|
||||
(value >> 8) & 0xFF,
|
||||
(value >> 16) & 0xFF,
|
||||
(value >> 24) & 0xFF,
|
||||
], source)
|
||||
|
||||
def add_word64(value: int, source: str = ""):
|
||||
"""Добавить 64-битное слово (little-endian)"""
|
||||
add_bytes([
|
||||
(value >> 0) & 0xFF,
|
||||
(value >> 8) & 0xFF,
|
||||
(value >> 16) & 0xFF,
|
||||
(value >> 24) & 0xFF,
|
||||
(value >> 32) & 0xFF,
|
||||
(value >> 40) & 0xFF,
|
||||
(value >> 48) & 0xFF,
|
||||
(value >> 56) & 0xFF,
|
||||
], source)
|
||||
|
||||
def align_to(alignment: int):
|
||||
"""Выровнять адрес до границы (просто двигаем адрес)"""
|
||||
global current_address
|
||||
padding = (alignment - (current_address % alignment)) % alignment
|
||||
current_address += padding
|
||||
|
||||
def add_relocation(pos: int, label: str, reloc_type: str, source: str = ""):
|
||||
"""Запомнить место для отложенной подстановки"""
|
||||
relocations.append((pos, label, reloc_type, source))
|
||||
|
||||
def generate_elf_header():
|
||||
"""Сгенерировать корректный ELF заголовок с заглушками"""
|
||||
# EI_MAGIC
|
||||
add_bytes([0x7F, 0x45, 0x4C, 0x46], "ELF magic")
|
||||
|
||||
# ei_class: 64-bit (2)
|
||||
add_byte(2, "ELFCLASS64")
|
||||
|
||||
# ei_data: little-endian (1)
|
||||
add_byte(1, "ELFDATA2LSB")
|
||||
|
||||
# ei_version: 1
|
||||
add_byte(1, "ELF version")
|
||||
|
||||
# ei_osabi: System V (0)
|
||||
add_byte(0, "OS ABI")
|
||||
|
||||
# ei_abiversion: 0
|
||||
add_byte(0, "ABI version")
|
||||
|
||||
# ei_pad: 7 байт паддинга
|
||||
add_bytes([0] * 7, "Padding")
|
||||
|
||||
# e_type: ET_EXEC (2)
|
||||
add_word32(2, "e_type = ET_EXEC")
|
||||
|
||||
# e_machine: EM_X86_64 (62)
|
||||
add_word32(62, "e_machine = EM_X86_64")
|
||||
|
||||
# e_version: 1
|
||||
add_word32(1, "e_version")
|
||||
|
||||
# e_entry: точка входа (заглушка 0x401000)
|
||||
add_word64(0x401000, "e_entry (stub: _start)")
|
||||
|
||||
# e_phoff: смещение до program headers (64 байта)
|
||||
add_word64(64, "e_phoff")
|
||||
|
||||
# e_shoff: смещение до section headers (0 = нет секций)
|
||||
add_word64(0, "e_shoff = 0")
|
||||
|
||||
# e_flags: 0
|
||||
add_word32(0, "e_flags")
|
||||
|
||||
# e_ehsize: размер ELF заголовка (64)
|
||||
add_word32(64, "e_ehsize")
|
||||
|
||||
# e_phentsize: размер program header entry (56)
|
||||
add_word32(56, "e_phentsize")
|
||||
|
||||
# e_phnum: количество program headers (2)
|
||||
add_word32(2, "e_phnum = 2")
|
||||
|
||||
# e_shentsize: размер section header entry (0)
|
||||
add_word32(0, "e_shentsize = 0")
|
||||
|
||||
# e_shnum: количество section headers (0)
|
||||
add_word32(0, "e_shnum = 0")
|
||||
|
||||
# e_shstrndx: индекс секции строк (0)
|
||||
add_word32(0, "e_shstrndx")
|
||||
|
||||
def generate_program_headers():
|
||||
"""Сгенерировать program headers с корректными выравниваниями"""
|
||||
|
||||
# Смещения в файле (должны быть кратны 4096)
|
||||
text_offset = 0x1000 # 4096
|
||||
data_offset = 0x2000 # 8192
|
||||
|
||||
# Program Header 1: TEXT (RX)
|
||||
add_word32(1, "p_type = PT_LOAD")
|
||||
add_word32(5, "p_flags = RX")
|
||||
add_word64(text_offset, "p_offset (text)")
|
||||
add_word64(0x401000, "p_vaddr (text)")
|
||||
add_word64(0x401000, "p_paddr (text)")
|
||||
add_word64(0, "p_filesz (stub)") # Заглушка
|
||||
add_word64(0, "p_memsz (stub)") # Заглушка
|
||||
add_word64(0x1000, "p_align (4KB)")
|
||||
|
||||
# Program Header 2: DATA (RW)
|
||||
add_word32(1, "p_type = PT_LOAD")
|
||||
add_word32(6, "p_flags = RW")
|
||||
add_word64(data_offset, "p_offset (data)")
|
||||
add_word64(0x402000, "p_vaddr (data)")
|
||||
add_word64(0x402000, "p_paddr (data)")
|
||||
add_word64(0, "p_filesz (stub)") # Заглушка
|
||||
add_word64(0, "p_memsz (stub)") # Заглушка
|
||||
add_word64(0x1000, "p_align (4KB)")
|
||||
|
||||
def generate_empty_program():
|
||||
"""Сгенерировать пустую программу с корректным ELF скелетом"""
|
||||
reset_state()
|
||||
|
||||
# Генерируем заголовки
|
||||
set_segment('.header')
|
||||
generate_elf_header()
|
||||
generate_program_headers()
|
||||
|
||||
# Выравнивание до .text секции
|
||||
align_to(0x1000)
|
||||
|
||||
# .text секция
|
||||
set_segment('.text')
|
||||
add_byte(0xCC, ".text section start (INT3)")
|
||||
|
||||
# Выравнивание до .data секции
|
||||
align_to(0x1000)
|
||||
|
||||
# .data секция
|
||||
set_segment('.data')
|
||||
add_byte(0x00, ".data section start")
|
||||
|
||||
# Вывод информации
|
||||
print(f"\n=== Сгенерирован скелет программы ===", file=sys.stderr)
|
||||
print(f"ELF заголовок: 64 байта", file=sys.stderr)
|
||||
print(f"Program headers: 112 байт (2 * 56)", file=sys.stderr)
|
||||
print(f".text: 1 байт по адресу 0x401000", file=sys.stderr)
|
||||
print(f".data: 1 байт по адресу 0x402000", file=sys.stderr)
|
||||
print(f"\nПроверка readelf:", file=sys.stderr)
|
||||
print(f" e_phoff = 64 (0x40) - верно", file=sys.stderr)
|
||||
print(f" p_offset(text) = 4096 (0x1000) - кратно p_align", file=sys.stderr)
|
||||
print(f" p_offset(data) = 8192 (0x2000) - кратно p_align", file=sys.stderr)
|
||||
|
||||
def save_to_csv(filename: str):
|
||||
"""Сохранить таблицу в CSV"""
|
||||
with open(filename, 'w', newline='', encoding='utf-8') as f:
|
||||
writer = csv.writer(f, delimiter=';')
|
||||
writer.writerow(['адрес', 'байт', 'целевой_адрес', 'исходная_команда', 'сегмент'])
|
||||
|
||||
for addr, byte, target, source, segment in entries:
|
||||
writer.writerow([
|
||||
f"0x{addr:08x}",
|
||||
f"0x{byte:02x}",
|
||||
f"0x{target:08x}" if target is not None else "",
|
||||
source,
|
||||
segment if segment else ""
|
||||
])
|
||||
|
||||
print(f"CSV сохранен: {filename}", file=sys.stderr)
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: python3 kvs_csv_builder.py <output.csv>")
|
||||
sys.exit(1)
|
||||
|
||||
generate_empty_program()
|
||||
save_to_csv(sys.argv[1])
|
||||
print("\nГотово!", file=sys.stderr)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
@ -1,136 +0,0 @@
|
|||
## Исходник
|
||||
|
||||
```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` для меток `.бнд`.
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
.текст
|
||||
.глобал _start
|
||||
|
||||
_start:
|
||||
; =============================================
|
||||
; ТЕСТ 1: Абсолютная адресация в .data
|
||||
; =============================================
|
||||
переместить_имм раикс, 0x42
|
||||
сохранить [абс_данные], раикс
|
||||
|
||||
; =============================================
|
||||
; ТЕСТ 2: Косвенная адресация в .data
|
||||
; =============================================
|
||||
переместить_имм рбикс, косв_данные
|
||||
переместить_имм раикс, 0x99
|
||||
сохранить [рбикс], раикс
|
||||
|
||||
; =============================================
|
||||
; ТЕСТ 3: Косвенная адресация в .бнд
|
||||
; =============================================
|
||||
переместить_имм рсикс, неиниц_бнд
|
||||
переместить_имм раикс, 0x77
|
||||
сохранить [рсикс], раикс
|
||||
|
||||
; =============================================
|
||||
; Читаем всё обратно и проверяем
|
||||
; =============================================
|
||||
|
||||
; Читаем абсолютную из .data
|
||||
загрузить р8, [абс_данные]
|
||||
|
||||
; Читаем косвенную из .data
|
||||
загрузить р9, [рбикс]
|
||||
|
||||
; Читаем косвенную из .бнд
|
||||
загрузить р10, [рсикс]
|
||||
|
||||
; =============================================
|
||||
; ЗАВЕРШЕНИЕ: возвращаем значение из абсолютной .data
|
||||
; =============================================
|
||||
загрузить рдиай, [абс_данные]
|
||||
переместить_имм раикс, 60
|
||||
вызов_системы
|
||||
|
||||
.данные
|
||||
абс_данные:
|
||||
.байт 0
|
||||
косв_данные:
|
||||
.байт 0
|
||||
|
||||
.бнд
|
||||
неиниц_бнд:
|
||||
.резб 8
|
||||
|
|
@ -1,67 +0,0 @@
|
|||
.текст
|
||||
.глобал _start
|
||||
|
||||
_start:
|
||||
; Число для преобразования
|
||||
переместить_имм раикс, 73
|
||||
|
||||
; Сохраняем число в .бнд
|
||||
сохранить [число], раикс
|
||||
|
||||
; Загружаем обратно
|
||||
загрузить раикс, [число]
|
||||
|
||||
; Делим на 10
|
||||
переместить_имм рдикс, 0
|
||||
переместить_имм рсикс, 10
|
||||
разделить рсикс ; rax = 7 (частное), rdx = 3 (остаток)
|
||||
|
||||
; Сохраняем остаток в .бнд
|
||||
сохранить [остаток], рдикс
|
||||
|
||||
; Частное (rax) — в цифру и выводим
|
||||
прибавить_непосредственно раикс, 0x30
|
||||
сохранить [буфер], раикс
|
||||
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, буфер
|
||||
переместить_имм рдикс, 1
|
||||
вызов_системы
|
||||
|
||||
; Загружаем остаток из .бнд
|
||||
загрузить раикс, [остаток]
|
||||
|
||||
; Остаток — в цифру и выводим
|
||||
прибавить_непосредственно раикс, 0x30
|
||||
сохранить [буфер], раикс
|
||||
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, буфер
|
||||
переместить_имм рдикс, 1
|
||||
вызов_системы
|
||||
|
||||
; Перевод строки
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, nl
|
||||
переместить_имм рдикс, 1
|
||||
вызов_системы
|
||||
|
||||
; exit(0)
|
||||
переместить_имм раикс, 60
|
||||
переместить_имм рдиай, 0
|
||||
вызов_системы
|
||||
|
||||
.данные
|
||||
буфер:
|
||||
.байт 0, 0, 0, 0, 0, 0, 0, 0
|
||||
nl:
|
||||
.байт 0x0A
|
||||
|
||||
.бнд
|
||||
число:
|
||||
.резб 8
|
||||
остаток:
|
||||
.резб 8
|
||||
|
|
@ -1,80 +0,0 @@
|
|||
.текст
|
||||
.глобал _start
|
||||
|
||||
_start:
|
||||
; Конвертируем 1034
|
||||
переместить_имм раикс, 1034
|
||||
|
||||
; 1234 / 10 = 123, остаток 4
|
||||
переместить_имм рдикс, 0
|
||||
переместить_имм рсикс, 10
|
||||
разделить рсикс
|
||||
прибавить_непосредственно рдикс, 0x30
|
||||
сохранить [цифра3], рдикс
|
||||
|
||||
; 123 / 10 = 12, остаток 3
|
||||
переместить_имм рдикс, 0
|
||||
разделить рсикс
|
||||
прибавить_непосредственно рдикс, 0x30
|
||||
сохранить [цифра2], рдикс
|
||||
|
||||
; 12 / 10 = 1, остаток 2
|
||||
переместить_имм рдикс, 0
|
||||
разделить рсикс
|
||||
прибавить_непосредственно рдикс, 0x30
|
||||
сохранить [цифра1], рдикс
|
||||
|
||||
; Частное 1 → последняя цифра
|
||||
прибавить_непосредственно раикс, 0x30
|
||||
сохранить [цифра0], раикс
|
||||
|
||||
; Выводим 4 цифры по одной
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, цифра0
|
||||
переместить_имм рдикс, 1
|
||||
вызов_системы
|
||||
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, цифра1
|
||||
переместить_имм рдикс, 1
|
||||
вызов_системы
|
||||
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, цифра2
|
||||
переместить_имм рдикс, 1
|
||||
вызов_системы
|
||||
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, цифра3
|
||||
переместить_имм рдикс, 1
|
||||
вызов_системы
|
||||
|
||||
; Перевод строки
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, nl
|
||||
переместить_имм рдикс, 1
|
||||
вызов_системы
|
||||
|
||||
; exit(0)
|
||||
переместить_имм раикс, 60
|
||||
переместить_имм рдиай, 0
|
||||
вызов_системы
|
||||
|
||||
.данные
|
||||
nl:
|
||||
.байт 0x0A
|
||||
|
||||
.бнд
|
||||
цифра0:
|
||||
.резб 8
|
||||
цифра1:
|
||||
.резб 8
|
||||
цифра2:
|
||||
.резб 8
|
||||
цифра3:
|
||||
.резб 8
|
||||
|
|
@ -1,94 +0,0 @@
|
|||
.текст
|
||||
.глобал _start
|
||||
|
||||
_start:
|
||||
; МЕНЯЙ ЧИСЛО:
|
||||
переместить_имм раикс, 57321
|
||||
|
||||
; 1-й разряд (единицы): число / 10
|
||||
переместить_имм рдикс, 0
|
||||
переместить_имм рсикс, 10
|
||||
разделить рсикс ; rax = 5432, rdx = 1
|
||||
прибавить_непосредственно рдикс, 0x30
|
||||
сохранить [цифра4], рдикс
|
||||
|
||||
; 2-й разряд (десятки): частное / 10
|
||||
переместить_имм рдикс, 0
|
||||
разделить рсикс ; rax = 543, rdx = 2
|
||||
прибавить_непосредственно рдикс, 0x30
|
||||
сохранить [цифра3], рдикс
|
||||
|
||||
; 3-й разряд (сотни)
|
||||
переместить_имм рдикс, 0
|
||||
разделить рсикс ; rax = 54, rdx = 3
|
||||
прибавить_непосредственно рдикс, 0x30
|
||||
сохранить [цифра2], рдикс
|
||||
|
||||
; 4-й разряд (тысячи)
|
||||
переместить_имм рдикс, 0
|
||||
разделить рсикс ; rax = 5, rdx = 4
|
||||
прибавить_непосредственно рдикс, 0x30
|
||||
сохранить [цифра1], рдикс
|
||||
|
||||
; 5-й разряд (десятки тысяч)
|
||||
прибавить_непосредственно раикс, 0x30
|
||||
сохранить [цифра0], раикс
|
||||
|
||||
; Выводим 5 цифр по одной
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, цифра0
|
||||
переместить_имм рдикс, 1
|
||||
вызов_системы
|
||||
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, цифра1
|
||||
переместить_имм рдикс, 1
|
||||
вызов_системы
|
||||
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, цифра2
|
||||
переместить_имм рдикс, 1
|
||||
вызов_системы
|
||||
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, цифра3
|
||||
переместить_имм рдикс, 1
|
||||
вызов_системы
|
||||
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, цифра4
|
||||
переместить_имм рдикс, 1
|
||||
вызов_системы
|
||||
|
||||
; Перевод строки
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, nl
|
||||
переместить_имм рдикс, 1
|
||||
вызов_системы
|
||||
|
||||
; exit(0)
|
||||
переместить_имм раикс, 60
|
||||
переместить_имм рдиай, 0
|
||||
вызов_системы
|
||||
|
||||
.данные
|
||||
nl:
|
||||
.байт 0x0A
|
||||
|
||||
.бнд
|
||||
цифра0:
|
||||
.резб 8
|
||||
цифра1:
|
||||
.резб 8
|
||||
цифра2:
|
||||
.резб 8
|
||||
цифра3:
|
||||
.резб 8
|
||||
цифра4:
|
||||
.резб 8
|
||||
|
|
@ -1,94 +0,0 @@
|
|||
.текст
|
||||
.глобал _start
|
||||
|
||||
_start:
|
||||
; МЕНЯЙ ЧИСЛО:
|
||||
переместить_имм раикс, 59321
|
||||
|
||||
; 1-й разряд (единицы): число / 10
|
||||
переместить_имм рдикс, 0
|
||||
переместить_имм рсикс, 10
|
||||
разделить рсикс ; rax = 5432, rdx = 1
|
||||
прибавить_непосредственно рдикс, 0x30
|
||||
сохранить [цифра4], рдикс
|
||||
|
||||
; 2-й разряд (десятки): частное / 10
|
||||
переместить_имм рдикс, 0
|
||||
разделить рсикс ; rax = 543, rdx = 2
|
||||
прибавить_непосредственно рдикс, 0x30
|
||||
сохранить [цифра3], рдикс
|
||||
|
||||
; 3-й разряд (сотни)
|
||||
переместить_имм рдикс, 0
|
||||
разделить рсикс ; rax = 54, rdx = 3
|
||||
прибавить_непосредственно рдикс, 0x30
|
||||
сохранить [цифра2], рдикс
|
||||
|
||||
; 4-й разряд (тысячи)
|
||||
переместить_имм рдикс, 0
|
||||
разделить рсикс ; rax = 5, rdx = 4
|
||||
прибавить_непосредственно рдикс, 0x30
|
||||
сохранить [цифра1], рдикс
|
||||
|
||||
; 5-й разряд (десятки тысяч)
|
||||
прибавить_непосредственно раикс, 0x30
|
||||
сохранить [цифра0], раикс
|
||||
|
||||
; Выводим 5 цифр по одной
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, цифра0
|
||||
переместить_имм рдикс, 1
|
||||
вызов_системы
|
||||
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, цифра1
|
||||
переместить_имм рдикс, 1
|
||||
вызов_системы
|
||||
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, цифра2
|
||||
переместить_имм рдикс, 1
|
||||
вызов_системы
|
||||
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, цифра3
|
||||
переместить_имм рдикс, 1
|
||||
вызов_системы
|
||||
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, цифра4
|
||||
переместить_имм рдикс, 1
|
||||
вызов_системы
|
||||
|
||||
; Перевод строки
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, nl
|
||||
переместить_имм рдикс, 1
|
||||
вызов_системы
|
||||
|
||||
; exit(0)
|
||||
переместить_имм раикс, 60
|
||||
переместить_имм рдиай, 0
|
||||
вызов_системы
|
||||
|
||||
.данные
|
||||
nl:
|
||||
.байт 0x0A
|
||||
|
||||
.бнд
|
||||
цифра0:
|
||||
.резб 8
|
||||
цифра1:
|
||||
.резб 8
|
||||
цифра2:
|
||||
.резб 8
|
||||
цифра3:
|
||||
.резб 8
|
||||
цифра4:
|
||||
.резб 8
|
||||
337
тесты/t1.py
337
тесты/t1.py
|
|
@ -1,337 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Тестовый скрипт для проверки инструкций с фиксированной длиной
|
||||
Запуск: python3 test_fixed_instructions.py [--keep-files]
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import subprocess
|
||||
import csv
|
||||
|
||||
# ANSI color codes
|
||||
GREEN = '\033[92m'
|
||||
RED = '\033[91m'
|
||||
YELLOW = '\033[93m'
|
||||
RESET = '\033[0m'
|
||||
|
||||
# === ТЕСТОВЫЙ ИСХОДНИК ===
|
||||
TEST_SOURCE = '''.глобал _start
|
||||
.текст
|
||||
|
||||
_start:
|
||||
нет_операции
|
||||
вызов_системы
|
||||
вернуться
|
||||
втолкнуть раикс
|
||||
втолкнуть р8
|
||||
вытолкнуть раикс
|
||||
вытолкнуть р8
|
||||
переместить раикс, рбикс
|
||||
переместить р8, р9
|
||||
сравнить раикс, рбикс
|
||||
сравнить р8, р9
|
||||
проверить раикс, рбикс
|
||||
проверить р8, р9
|
||||
прибавить раикс, рбикс
|
||||
прибавить р8, р9
|
||||
вычесть раикс, рбикс
|
||||
вычесть р8, р9
|
||||
и раикс, рбикс
|
||||
и р8, р9
|
||||
или раикс, рбикс
|
||||
или р8, р9
|
||||
исключающее_или раикс, рбикс
|
||||
исключающее_или р8, р9
|
||||
увеличить раикс
|
||||
увеличить р8
|
||||
увеличить еаикс
|
||||
уменьшить раикс
|
||||
уменьшить р8
|
||||
уменьшить еаикс
|
||||
инвертировать раикс
|
||||
инвертировать еаикс
|
||||
отрицать раикс
|
||||
отрицать еаикс
|
||||
переместить_имм раикс, 10
|
||||
переместить_имм рбикс, 5
|
||||
умножить рбикс
|
||||
переместить_имм раикс, 100
|
||||
переместить_имм рбикс, 7
|
||||
разделить рбикс
|
||||
умножить_знаковое рбикс
|
||||
разделить_знаковое рбикс
|
||||
сдвиг_влево раикс, 2
|
||||
сдвиг_вправо раикс, 2
|
||||
сдвиг_арифметический_вправо раикс, 2
|
||||
вращать_влево раикс, 2
|
||||
вращать_вправо раикс, 2
|
||||
переход метка_длинная
|
||||
короткий_переход метка_короткая
|
||||
цикл метка_короткая
|
||||
вызвать метка_длинная
|
||||
|
||||
метка_длинная:
|
||||
нет_операции
|
||||
нет_операции
|
||||
нет_операции
|
||||
|
||||
метка_короткая:
|
||||
нет_операции
|
||||
|
||||
переместить_имм раикс, 60
|
||||
переместить_имм рдикс, 0
|
||||
вызов_системы
|
||||
'''
|
||||
|
||||
|
||||
# === ОЖИДАЕМЫЕ РЕЗУЛЬТАТЫ ===
|
||||
# Для инструкций с фиксированным кодом — полная проверка
|
||||
EXPECTED_INSTRUCTIONS_FULL = {
|
||||
"нет_операции": [0x90],
|
||||
"вызов_системы": [0x0F, 0x05],
|
||||
"вернуться": [0xC3],
|
||||
"втолкнуть раикс": [0x50],
|
||||
"втолкнуть р8": [0x41, 0x50],
|
||||
"вытолкнуть раикс": [0x58],
|
||||
"вытолкнуть р8": [0x41, 0x58],
|
||||
"переместить раикс, рбикс": [0x48, 0x89, 0xD8],
|
||||
"переместить р8, р9": [0x4D, 0x89, 0xC8],
|
||||
"сравнить раикс, рбикс": [0x48, 0x39, 0xD8],
|
||||
"сравнить р8, р9": [0x4D, 0x39, 0xC8],
|
||||
"проверить раикс, рбикс": [0x48, 0x85, 0xD8],
|
||||
"проверить р8, р9": [0x4D, 0x85, 0xC8],
|
||||
"прибавить раикс, рбикс": [0x48, 0x01, 0xD8],
|
||||
"прибавить р8, р9": [0x4D, 0x01, 0xC8],
|
||||
"вычесть раикс, рбикс": [0x48, 0x29, 0xD8],
|
||||
"вычесть р8, р9": [0x4D, 0x29, 0xC8],
|
||||
"и раикс, рбикс": [0x48, 0x21, 0xD8],
|
||||
"и р8, р9": [0x4D, 0x21, 0xC8],
|
||||
"или раикс, рбикс": [0x48, 0x09, 0xD8],
|
||||
"или р8, р9": [0x4D, 0x09, 0xC8],
|
||||
"исключающее_или раикс, рбикс": [0x48, 0x31, 0xD8],
|
||||
"исключающее_или р8, р9": [0x4D, 0x31, 0xC8],
|
||||
"увеличить раикс": [0x48, 0xFF, 0xC0],
|
||||
"увеличить р8": [0x49, 0xFF, 0xC0],
|
||||
"увеличить еаикс": [0xFF, 0xC0],
|
||||
"уменьшить раикс": [0x48, 0xFF, 0xC8],
|
||||
"уменьшить р8": [0x49, 0xFF, 0xC8],
|
||||
"уменьшить еаикс": [0xFF, 0xC8],
|
||||
"инвертировать раикс": [0x48, 0xF7, 0xD0],
|
||||
"инвертировать еаикс": [0xF7, 0xD0],
|
||||
"отрицать раикс": [0x48, 0xF7, 0xD8],
|
||||
"отрицать еаикс": [0xF7, 0xD8],
|
||||
"умножить рбикс": [0x48, 0xF7, 0xE0],
|
||||
"разделить рбикс": [0x48, 0xF7, 0xF0],
|
||||
"умножить_знаковое рбикс": [0x48, 0xF7, 0xE8],
|
||||
"разделить_знаковое рбикс": [0x48, 0xF7, 0xF8],
|
||||
"сдвиг_влево раикс, 2": [0x48, 0xC1, 0xE0, 0x02],
|
||||
"сдвиг_вправо раикс, 2": [0x48, 0xC1, 0xE8, 0x02],
|
||||
"сдвиг_арифметический_вправо раикс, 2": [0x48, 0xC1, 0xF8, 0x02],
|
||||
"вращать_влево раикс, 2": [0x48, 0xC1, 0xC0, 0x02],
|
||||
"вращать_вправо раикс, 2": [0x48, 0xC1, 0xC8, 0x02],
|
||||
"переместить_имм раикс, 10": [0x48, 0xB8, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
|
||||
"переместить_имм рбикс, 5": [0x48, 0xBB, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
|
||||
"переместить_имм раикс, 100": [0x48, 0xB8, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
|
||||
"переместить_имм рбикс, 7": [0x48, 0xBB, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
|
||||
"переместить_имм раикс, 60": [0x48, 0xB8, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
|
||||
"переместить_имм рдикс, 0": [0x48, 0xBA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
|
||||
}
|
||||
|
||||
# Инструкции, у которых проверяем только opcode (первые байты)
|
||||
EXPECTED_INSTRUCTIONS_PREFIX = {
|
||||
"переход метка_длинная": [0xE9], # JMP rel32
|
||||
"короткий_переход метка_короткая": [0xEB], # JMP SHORT
|
||||
"цикл метка_короткая": [0xE2], # LOOP
|
||||
"вызвать метка_длинная": [0xE8], # CALL rel32
|
||||
}
|
||||
|
||||
|
||||
def read_csv_instructions(csv_file):
|
||||
"""Читает CSV и возвращает словарь {мнемоника: [байты]}"""
|
||||
instructions = {}
|
||||
current_mnemonic = None
|
||||
current_bytes = []
|
||||
|
||||
with open(csv_file, 'r', encoding='utf-8') as f:
|
||||
reader = csv.reader(f, delimiter=';')
|
||||
header = next(reader)
|
||||
|
||||
for row in reader:
|
||||
if len(row) < 4:
|
||||
continue
|
||||
|
||||
cmd = row[3].strip()
|
||||
byte_str = row[1].strip()
|
||||
|
||||
if not byte_str:
|
||||
continue
|
||||
|
||||
byte_val = int(byte_str, 16)
|
||||
|
||||
if cmd:
|
||||
if current_mnemonic and current_bytes:
|
||||
instructions[current_mnemonic] = current_bytes
|
||||
current_mnemonic = cmd
|
||||
current_bytes = [byte_val]
|
||||
else:
|
||||
if current_mnemonic:
|
||||
current_bytes.append(byte_val)
|
||||
|
||||
if current_mnemonic and current_bytes:
|
||||
instructions[current_mnemonic] = current_bytes
|
||||
|
||||
return instructions
|
||||
|
||||
|
||||
def run_tests(generated_instructions):
|
||||
"""Сравнивает сгенерированные инструкции с ожидаемыми"""
|
||||
errors = []
|
||||
missing = []
|
||||
|
||||
# Проверяем инструкции с полным совпадением
|
||||
for mnemonic, expected_bytes in EXPECTED_INSTRUCTIONS_FULL.items():
|
||||
if mnemonic not in generated_instructions:
|
||||
missing.append(mnemonic)
|
||||
continue
|
||||
|
||||
actual_bytes = generated_instructions[mnemonic]
|
||||
if actual_bytes != expected_bytes:
|
||||
expected_hex = ' '.join(f'{b:02X}' for b in expected_bytes)
|
||||
actual_hex = ' '.join(f'{b:02X}' for b in actual_bytes)
|
||||
errors.append(f" {mnemonic}: ожидалось [{expected_hex}], получено [{actual_hex}]")
|
||||
|
||||
# Проверяем инструкции только по префиксу
|
||||
for mnemonic, expected_prefix in EXPECTED_INSTRUCTIONS_PREFIX.items():
|
||||
if mnemonic not in generated_instructions:
|
||||
missing.append(mnemonic)
|
||||
continue
|
||||
|
||||
actual_bytes = generated_instructions[mnemonic]
|
||||
prefix_len = len(expected_prefix)
|
||||
|
||||
if len(actual_bytes) < prefix_len:
|
||||
errors.append(f" {mnemonic}: слишком короткая ({len(actual_bytes)} байт, ожидалось минимум {prefix_len})")
|
||||
elif actual_bytes[:prefix_len] != expected_prefix:
|
||||
expected_hex = ' '.join(f'{b:02X}' for b in expected_prefix)
|
||||
actual_hex = ' '.join(f'{b:02X}' for b in actual_bytes[:prefix_len])
|
||||
errors.append(f" {mnemonic}: префикс [{expected_hex}...], получено [{actual_hex}...]")
|
||||
|
||||
return errors, missing
|
||||
|
||||
|
||||
def cleanup(files_to_delete, keep_files=False):
|
||||
"""Удаляет временные файлы"""
|
||||
if keep_files:
|
||||
print("\nФлаг --keep-files указан, промежуточные файлы сохранены:")
|
||||
for f in files_to_delete:
|
||||
if os.path.exists(f):
|
||||
print(f" {f}")
|
||||
return
|
||||
|
||||
deleted = []
|
||||
for f in files_to_delete:
|
||||
if os.path.exists(f):
|
||||
os.remove(f)
|
||||
deleted.append(f)
|
||||
|
||||
if deleted:
|
||||
print(f"\nУдалено {len(deleted)} временных файлов")
|
||||
|
||||
|
||||
def main():
|
||||
keep_files = '--keep-files' in sys.argv or '-k' in sys.argv
|
||||
|
||||
base_name = "т1"
|
||||
source_file = f"{base_name}.квс"
|
||||
tokens_file = f"{base_name}.токены"
|
||||
ast_file = f"{base_name}.аст"
|
||||
p1_file = f"{base_name}.проход1"
|
||||
csv_file = f"{base_name}.csv"
|
||||
elf_file = f"{base_name}.elf"
|
||||
|
||||
|
||||
temp_files = [tokens_file, ast_file, p1_file, csv_file, elf_file]
|
||||
|
||||
print("КВС Тестировщик - Инструкции с фиксированной длиной\n")
|
||||
print("=" * 60)
|
||||
|
||||
# Шаг 1: Создание исходного файла
|
||||
print("Шаг 1: Создание тестового исходника...")
|
||||
with open(source_file, 'w', encoding='utf-8') as f:
|
||||
f.write(TEST_SOURCE)
|
||||
print(f" Создан {source_file}")
|
||||
|
||||
# Шаг 2: Компиляция
|
||||
print("\nШаг 2: Компиляция...")
|
||||
result = subprocess.run(
|
||||
[sys.executable, "kvs_build.py", source_file],
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
|
||||
if result.returncode != 0:
|
||||
print(" ОШИБКА компиляции:")
|
||||
print(result.stderr)
|
||||
print("\nОставшиеся файлы для отладки:")
|
||||
print(f" {source_file}")
|
||||
if os.path.exists(csv_file):
|
||||
print(f" {csv_file}")
|
||||
sys.exit(1)
|
||||
|
||||
print(" Компиляция успешна")
|
||||
|
||||
# Шаг 3: Проверка результатов
|
||||
print("\nШаг 3: Проверка сгенерированного кода...")
|
||||
|
||||
if not os.path.exists(csv_file):
|
||||
print(f" Файл {csv_file} не найден!")
|
||||
sys.exit(1)
|
||||
|
||||
generated_instructions = read_csv_instructions(csv_file)
|
||||
errors, missing = run_tests(generated_instructions)
|
||||
|
||||
# Вывод результатов
|
||||
print("\n" + "=" * 60)
|
||||
print("РЕЗУЛЬТАТЫ ТЕСТИРОВАНИЯ:")
|
||||
print("=" * 60)
|
||||
|
||||
if missing:
|
||||
print(f"\n{YELLOW}ОТСУТСТВУЮТ ИНСТРУКЦИИ ({len(missing)}):{RESET}")
|
||||
for m in missing[:10]:
|
||||
print(f" - {m}")
|
||||
if len(missing) > 10:
|
||||
print(f" ... и ещё {len(missing)-10}")
|
||||
|
||||
if errors:
|
||||
print(f"\n{RED}НАЙДЕНО {len(errors)} ОШИБОК В КОДЕ:{RESET}")
|
||||
for err in errors:
|
||||
print(err)
|
||||
success = False
|
||||
else:
|
||||
print(f"\n{GREEN}НЕТ ОШИБОК! ВСЕ ИНСТРУКЦИИ ЗАКОДИРОВАНЫ ВЕРНО!{RESET}")
|
||||
success = True
|
||||
|
||||
# Статистика
|
||||
print(f"\nСтатистика:")
|
||||
print(f" Ожидалось инструкций (полная проверка): {len(EXPECTED_INSTRUCTIONS_FULL)}")
|
||||
print(f" Ожидалось инструкций (проверка префикса): {len(EXPECTED_INSTRUCTIONS_PREFIX)}")
|
||||
print(f" Сгенерировано инструкций: {len(generated_instructions)}")
|
||||
|
||||
# Шаг 4: Очистка
|
||||
cleanup([source_file] + temp_files, keep_files)
|
||||
|
||||
# Финальный вердикт
|
||||
print("\n" + "=" * 60)
|
||||
if success:
|
||||
print(f"{GREEN}ТЕСТЫ ПРОЙДЕНЫ УСПЕШНО!{RESET}")
|
||||
sys.exit(0)
|
||||
else:
|
||||
print(f"{RED}ТЕСТЫ НЕ ПРОЙДЕНЫ!{RESET}")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
.текст
|
||||
.глобал _start
|
||||
_start:
|
||||
переместить_имм раикс, 60
|
||||
переместить_имм рдиай, 0
|
||||
вызов_системы
|
||||
|
||||
.бнд
|
||||
буфер: .резб 1048576 ; 1 МБ = 1024 * 1024
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
.текст
|
||||
.глобал _start
|
||||
|
||||
_start:
|
||||
; =============================================
|
||||
; ТЕСТ 1: Абсолютная адресация в .бнд
|
||||
; =============================================
|
||||
переместить_имм раикс, 0x42
|
||||
сохранить [абс_перем], раикс
|
||||
|
||||
; =============================================
|
||||
; ТЕСТ 2: Косвенная адресация в .бнд
|
||||
; =============================================
|
||||
переместить_имм рбикс, косв_перем
|
||||
переместить_имм раикс, 0x99
|
||||
сохранить [рбикс], раикс
|
||||
|
||||
; =============================================
|
||||
; ТЕСТ 3: Ещё одна косвенная адресация в .бнд
|
||||
; =============================================
|
||||
переместить_имм рсикс, ещё_перем
|
||||
переместить_имм раикс, 0x77
|
||||
сохранить [рсикс], раикс
|
||||
|
||||
; =============================================
|
||||
; Читаем всё обратно
|
||||
; =============================================
|
||||
загрузить р8, [абс_перем]
|
||||
загрузить р9, [рбикс]
|
||||
загрузить р10, [рсикс]
|
||||
|
||||
; =============================================
|
||||
; ЗАВЕРШЕНИЕ: возвращаем из абс_перем
|
||||
; =============================================
|
||||
загрузить рдиай, [абс_перем]
|
||||
переместить_имм раикс, 60
|
||||
вызов_системы
|
||||
|
||||
.бнд
|
||||
абс_перем:
|
||||
.резб 1
|
||||
косв_перем:
|
||||
.резб 1
|
||||
ещё_перем:
|
||||
.резб 8
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
.текст
|
||||
.глобал _start
|
||||
|
||||
_start:
|
||||
; Запись значения 42 в переменную по метке
|
||||
переместить_имм раикс, 42
|
||||
сохранить [переменная], раикс
|
||||
|
||||
; Завершение с кодом 42
|
||||
переместить_имм раикс, 60
|
||||
загрузить рдиай, [переменная]
|
||||
вызов_системы
|
||||
|
||||
.данные
|
||||
переменная: .байт 0
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
.текст
|
||||
.глобал _start
|
||||
|
||||
_start:
|
||||
; Запись значения 42 в переменную по адресу 0x402000
|
||||
переместить_имм раикс, 42
|
||||
сохранить [0x402000], раикс
|
||||
|
||||
; Завершение с кодом 42 (читаем из переменной)
|
||||
переместить_имм раикс, 60
|
||||
загрузить рдиай, [0x402000]
|
||||
вызов_системы
|
||||
|
||||
.данные
|
||||
тестовая_переменная: .байт 0
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
.текст
|
||||
.глобал _start
|
||||
|
||||
_start:
|
||||
; === ТЕСТ 1: Запись через косвенную адресацию ===
|
||||
; Загружаем адрес переменной в регистр
|
||||
переместить_имм рбикс, тестовая_переменная
|
||||
|
||||
; Записываем 42 через косвенную адресацию [рбикс]
|
||||
переместить_имм раикс, 42
|
||||
сохранить [рбикс], раикс
|
||||
|
||||
; === ТЕСТ 2: Чтение через косвенную адресацию ===
|
||||
; Загружаем адрес другой переменной в регистр
|
||||
переместить_имм рсикс, вторая_переменная
|
||||
|
||||
; Читаем через косвенную адресацию [рсикс]
|
||||
загрузить рдикс, [рсикс]
|
||||
|
||||
; === ТЕСТ 3: Проверяем, что записалось ===
|
||||
; Читаем первую переменную через косвенную
|
||||
загрузить рсикс, [рбикс]
|
||||
|
||||
; === ЗАВЕРШЕНИЕ ===
|
||||
; Выходим с кодом из первой переменной (должно быть 42)
|
||||
переместить_имм раикс, 60
|
||||
переместить рдиай, рсикс
|
||||
вызов_системы
|
||||
|
||||
.данные
|
||||
тестовая_переменная:
|
||||
.байт 0
|
||||
вторая_переменная:
|
||||
.байт 99
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
.текст
|
||||
.глобал _start
|
||||
|
||||
_start:
|
||||
; =============================================
|
||||
; ТЕСТ 1: Абсолютная адресация
|
||||
; =============================================
|
||||
переместить_имм раикс, 0x42
|
||||
сохранить [абс_данные], раикс
|
||||
|
||||
; =============================================
|
||||
; ТЕСТ 2: Косвенная адресация
|
||||
; =============================================
|
||||
переместить_имм рбикс, косв_данные
|
||||
переместить_имм раикс, 0x99
|
||||
сохранить [рбикс], раикс
|
||||
|
||||
; =============================================
|
||||
; ТЕСТ 3: Ещё одна косвенная адресация
|
||||
; =============================================
|
||||
переместить_имм рсикс, ещё_данные
|
||||
переместить_имм раикс, 0x77
|
||||
сохранить [рсикс], раикс
|
||||
|
||||
; =============================================
|
||||
; Читаем всё обратно
|
||||
; =============================================
|
||||
загрузить р8, [абс_данные]
|
||||
загрузить р9, [рбикс]
|
||||
загрузить р10, [рсикс]
|
||||
|
||||
; =============================================
|
||||
; ЗАВЕРШЕНИЕ: возвращаем из абсолютной переменной
|
||||
; =============================================
|
||||
загрузить рдиай, [абс_данные]
|
||||
переместить_имм раикс, 60
|
||||
вызов_системы
|
||||
|
||||
.данные
|
||||
абс_данные:
|
||||
.байт 0
|
||||
косв_данные:
|
||||
.байт 0
|
||||
ещё_данные:
|
||||
.байт 0, 0, 0, 0, 0, 0, 0, 0
|
||||
|
||||
.бнд
|
||||
буфер: .резб 1048576 ; 1 МБ = 1024 * 1024
|
||||
переменная: .резкс 1 ; 8 байт под длину
|
||||
буфер_строки: .резкс 1 ; 8 байт под указатель на строку
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
.текст
|
||||
.глобал _start
|
||||
|
||||
_start:
|
||||
; 25 - длина сообщения из метки msg
|
||||
; Запись значения 25 в переменную по метке
|
||||
переместить_имм рдикс, 25
|
||||
сохранить [переменная], рдикс
|
||||
; перепишем для теста
|
||||
переместить_имм рдикс, 0
|
||||
|
||||
|
||||
; Системный вызов write(1, msg, len)
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, msg
|
||||
загрузить рдикс, [переменная]
|
||||
вызов_системы
|
||||
|
||||
|
||||
; Системный вызов exit()
|
||||
переместить_имм раикс, 60 ; номер syscall exit = 60
|
||||
переместить_имм рдиай, 44 ; код возврата (старый метод)
|
||||
вызов_системы
|
||||
|
||||
.данные
|
||||
msg: .строка "Тест пройден!\n" ; не менять их местами, чтоб не затереть текст
|
||||
переменная: .байт 0 ; тут либо резервировать пустые, либо .bss изобретать (или кучу?)
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
.текст
|
||||
.глобал _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)
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
.текст
|
||||
.глобал _start
|
||||
|
||||
_start:
|
||||
; 25 - длина сообщения из метки msg
|
||||
; Запись значения 25 в переменную в .бнд
|
||||
переместить_имм рдикс, 25
|
||||
сохранить [переменная], рдикс
|
||||
|
||||
; Загружаем адрес строки и сохраняем в буфер в .бнд
|
||||
загрузить_адрес раикс, [msg]
|
||||
сохранить [буфер_строки], раикс
|
||||
|
||||
; перепишем для теста
|
||||
переместить_имм рдикс, 0
|
||||
|
||||
|
||||
; Системный вызов write(1, msg, len)
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
загрузить рсиай, [буфер_строки]
|
||||
загрузить рдикс, [переменная]
|
||||
вызов_системы
|
||||
|
||||
|
||||
; Системный вызов exit()
|
||||
переместить_имм раикс, 60
|
||||
переместить_имм рдиай, 44
|
||||
вызов_системы
|
||||
|
||||
.данные
|
||||
msg: .строка "Тест пройден!\n"
|
||||
|
||||
.бнд
|
||||
переменная: .резкс 1 ; 8 байт под длину
|
||||
буфер_строки: .резкс 1 ; 8 байт под указатель на строку
|
||||
|
|
@ -1,835 +0,0 @@
|
|||
; длин_тест9.квс
|
||||
; Тест: запутанные переходы, крякмис (для длинных переходов)
|
||||
|
||||
.текст
|
||||
.глобал _start
|
||||
|
||||
_start:
|
||||
; Инициализация регистров
|
||||
переместить_имм раикс, 10 ; rax = 10
|
||||
переместить_имм рбикс, 5 ; rbx = 5
|
||||
переместить_имм рсикс, 10 ; rcx = 10 (для проверки ZF в jz)
|
||||
|
||||
; ПЕРВЫЙ ПЕРЕХОД: переход_если_не_ноль
|
||||
; ZF=0 (так как rax=10), значит jnz сработает
|
||||
; Прыгаем к метке 'проверка_2', пропуская мертвый_код_1
|
||||
переход_если_не_ноль проверка_2
|
||||
|
||||
; --- МЕРТВЫЙ КОД 1 ---
|
||||
; Этот код НЕ должен выполниться
|
||||
; Добавляем "мусор", чтобы точно выйти за пределы короткого перехода
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, msg_dead_1
|
||||
переместить_имм рдикс, len_msg_dead_1
|
||||
вызов_системы
|
||||
переместить_имм раикс, 2
|
||||
переместить_имм рдиай, 2
|
||||
переместить_имм рсиай, msg_dead_1
|
||||
переместить_имм рдикс, len_msg_dead_1
|
||||
вызов_системы
|
||||
переместить_имм раикс, 3
|
||||
переместить_имм рдиай, 3
|
||||
переместить_имм рсиай, msg_dead_1
|
||||
переместить_имм рдикс, len_msg_dead_1
|
||||
вызов_системы
|
||||
переместить_имм раикс, 4
|
||||
переместить_имм рдиай, 4
|
||||
переместить_имм рсиай, msg_dead_1
|
||||
переместить_имм рдикс, len_msg_dead_1
|
||||
вызов_системы
|
||||
переместить_имм раикс, 5
|
||||
переместить_имм рдиай, 5
|
||||
переместить_имм рсиай, msg_dead_1
|
||||
переместить_имм рдикс, len_msg_dead_1
|
||||
вызов_системы
|
||||
переместить_имм раикс, 6
|
||||
переместить_имм рдиай, 6
|
||||
переместить_имм рсиай, msg_dead_1
|
||||
переместить_имм рдикс, len_msg_dead_1
|
||||
вызов_системы
|
||||
переместить_имм раикс, 7
|
||||
переместить_имм рдиай, 7
|
||||
переместить_имм рсиай, msg_dead_1
|
||||
переместить_имм рдикс, len_msg_dead_1
|
||||
вызов_системы
|
||||
переместить_имм раикс, 8
|
||||
переместить_имм рдиай, 8
|
||||
переместить_имм рсиай, msg_dead_1
|
||||
переместить_имм рдикс, len_msg_dead_1
|
||||
вызов_системы
|
||||
переместить_имм раикс, 9
|
||||
переместить_имм рдиай, 9
|
||||
переместить_имм рсиай, msg_dead_1
|
||||
переместить_имм рдикс, len_msg_dead_1
|
||||
вызов_системы
|
||||
переместить_имм раикс, 10
|
||||
переместить_имм рдиай, 10
|
||||
переместить_имм рсиай, msg_dead_1
|
||||
переместить_имм рдикс, len_msg_dead_1
|
||||
вызов_системы
|
||||
переместить_имм раикс, 11
|
||||
переместить_имм рдиай, 11
|
||||
переместить_имм рсиай, msg_dead_1
|
||||
переместить_имм рдикс, len_msg_dead_1
|
||||
вызов_системы
|
||||
переместить_имм раикс, 12
|
||||
переместить_имм рдиай, 12
|
||||
переместить_имм рсиай, msg_dead_1
|
||||
переместить_имм рдикс, len_msg_dead_1
|
||||
вызов_системы
|
||||
переместить_имм раикс, 13
|
||||
переместить_имм рдиай, 13
|
||||
переместить_имм рсиай, msg_dead_1
|
||||
переместить_имм рдикс, len_msg_dead_1
|
||||
вызов_системы
|
||||
переместить_имм раикс, 14
|
||||
переместить_имм рдиай, 14
|
||||
переместить_имм рсиай, msg_dead_1
|
||||
переместить_имм рдикс, len_msg_dead_1
|
||||
вызов_системы
|
||||
переместить_имм раикс, 15
|
||||
переместить_имм рдиай, 15
|
||||
переместить_имм рсиай, msg_dead_1
|
||||
переместить_имм рдикс, len_msg_dead_1
|
||||
вызов_системы
|
||||
; ---------------------
|
||||
|
||||
проверка_2:
|
||||
; ДОПОЛНИТЕЛЬНЫЙ ПЕРЕХОД 1: "Два шага вперед" - переход через мертвый_код_2 и мертвый_код_3
|
||||
; Прыгаем к проверка_4, минуя мертвый_код_2 и мертвый_код_3
|
||||
переход проверка_4
|
||||
|
||||
; --- МЕРТВЫЙ КОД 2 ---
|
||||
; Этот код НЕ должен выполниться из-за прыжка выше
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, msg_dead_2
|
||||
переместить_имм рдикс, len_msg_dead_2
|
||||
вызов_системы
|
||||
переместить_имм раикс, 2
|
||||
переместить_имм рдиай, 2
|
||||
переместить_имм рсиай, msg_dead_2
|
||||
переместить_имм рдикс, len_msg_dead_2
|
||||
вызов_системы
|
||||
переместить_имм раикс, 3
|
||||
переместить_имм рдиай, 3
|
||||
переместить_имм рсиай, msg_dead_2
|
||||
переместить_имм рдикс, len_msg_dead_2
|
||||
вызов_системы
|
||||
переместить_имм раикс, 4
|
||||
переместить_имм рдиай, 4
|
||||
переместить_имм рсиай, msg_dead_2
|
||||
переместить_имм рдикс, len_msg_dead_2
|
||||
вызов_системы
|
||||
переместить_имм раикс, 5
|
||||
переместить_имм рдиай, 5
|
||||
переместить_имм рсиай, msg_dead_2
|
||||
переместить_имм рдикс, len_msg_dead_2
|
||||
вызов_системы
|
||||
переместить_имм раикс, 6
|
||||
переместить_имм рдиай, 6
|
||||
переместить_имм рсиай, msg_dead_2
|
||||
переместить_имм рдикс, len_msg_dead_2
|
||||
вызов_системы
|
||||
переместить_имм раикс, 7
|
||||
переместить_имм рдиай, 7
|
||||
переместить_имм рсиай, msg_dead_2
|
||||
переместить_имм рдикс, len_msg_dead_2
|
||||
вызов_системы
|
||||
переместить_имм раикс, 8
|
||||
переместить_имм рдиай, 8
|
||||
переместить_имм рсиай, msg_dead_2
|
||||
переместить_имм рдикс, len_msg_dead_2
|
||||
вызов_системы
|
||||
переместить_имм раикс, 9
|
||||
переместить_имм рдиай, 9
|
||||
переместить_имм рсиай, msg_dead_2
|
||||
переместить_имм рдикс, len_msg_dead_2
|
||||
вызов_системы
|
||||
переместить_имм раикс, 10
|
||||
переместить_имм рдиай, 10
|
||||
переместить_имм рсиай, msg_dead_2
|
||||
переместить_имм рдикс, len_msg_dead_2
|
||||
вызов_системы
|
||||
переместить_имм раикс, 11
|
||||
переместить_имм рдиай, 11
|
||||
переместить_имм рсиай, msg_dead_2
|
||||
переместить_имм рдикс, len_msg_dead_2
|
||||
вызов_системы
|
||||
переместить_имм раикс, 12
|
||||
переместить_имм рдиай, 12
|
||||
переместить_имм рсиай, msg_dead_2
|
||||
переместить_имм рдикс, len_msg_dead_2
|
||||
вызов_системы
|
||||
переместить_имм раикс, 13
|
||||
переместить_имм рдиай, 13
|
||||
переместить_имм рсиай, msg_dead_2
|
||||
переместить_имм рдикс, len_msg_dead_2
|
||||
вызов_системы
|
||||
переместить_имм раикс, 14
|
||||
переместить_имм рдиай, 14
|
||||
переместить_имм рсиай, msg_dead_2
|
||||
переместить_имм рдикс, len_msg_dead_2
|
||||
вызов_системы
|
||||
переместить_имм раикс, 15
|
||||
переместить_имм рдиай, 15
|
||||
переместить_имм рсиай, msg_dead_2
|
||||
переместить_имм рдикс, len_msg_dead_2
|
||||
вызов_системы
|
||||
; ---------------------
|
||||
|
||||
мертвый_код_3:
|
||||
; ЖИВОЙ КОД 3: Этот код выполнится благодаря прыжку "назад"
|
||||
; Выведем сообщение, чтобы убедиться, что он выполнился
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, msg_live_from_3
|
||||
переместить_имм рдикс, len_msg_live_from_3
|
||||
вызов_системы
|
||||
; ДОПОЛНИТЕЛЬНЫЙ ПЕРЕХОД 3: "Четыре вперед" - переход через мертвый_код_4, 5, 6, 7
|
||||
; Цель слишком далеко для короткого перехода. Используем длинный.
|
||||
; Прыгаем к проверка_8
|
||||
переход проверка_8
|
||||
; ---------------------
|
||||
|
||||
проверка_4:
|
||||
; ЧЕТВЁРТЫЙ ПЕРЕХОД: переход_если_больше
|
||||
; Сравниваем rax (10) и rbx (5) -> rax > rbx, ZF=0, SF=0, OF=0
|
||||
сравнить раикс, рбикс
|
||||
; Условие jg: ZF=0 (истина) И SF=OF (0=0, истина). jg СРАБОТАЕТ.
|
||||
; Мы хотим прыгнуть МИМО мертвого кода 4, если jg сработает (т.е. если rax > rbx).
|
||||
переход_если_больше мимо_мертвого_кода_4
|
||||
; --- МЕРТВЫЙ КОД 4 ---
|
||||
; Этот код НЕ должен выполниться (так как jg сработал)
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, msg_dead_4
|
||||
переместить_имм рдикс, len_msg_dead_4
|
||||
вызов_системы
|
||||
переместить_имм раикс, 2
|
||||
переместить_имм рдиай, 2
|
||||
переместить_имм рсиай, msg_dead_4
|
||||
переместить_имм рдикс, len_msg_dead_4
|
||||
вызов_системы
|
||||
переместить_имм раикс, 3
|
||||
переместить_имм рдиай, 3
|
||||
переместить_имм рсиай, msg_dead_4
|
||||
переместить_имм рдикс, len_msg_dead_4
|
||||
вызов_системы
|
||||
переместить_имм раикс, 4
|
||||
переместить_имм рдиай, 4
|
||||
переместить_имм рсиай, msg_dead_4
|
||||
переместить_имм рдикс, len_msg_dead_4
|
||||
вызов_системы
|
||||
переместить_имм раикс, 5
|
||||
переместить_имм рдиай, 5
|
||||
переместить_имм рсиай, msg_dead_4
|
||||
переместить_имм рдикс, len_msg_dead_4
|
||||
вызов_системы
|
||||
переместить_имм раикс, 6
|
||||
переместить_имм рдиай, 6
|
||||
переместить_имм рсиай, msg_dead_4
|
||||
переместить_имм рдикс, len_msg_dead_4
|
||||
вызов_системы
|
||||
переместить_имм раикс, 7
|
||||
переместить_имм рдиай, 7
|
||||
переместить_имм рсиай, msg_dead_4
|
||||
переместить_имм рдикс, len_msg_dead_4
|
||||
вызов_системы
|
||||
переместить_имм раикс, 8
|
||||
переместить_имм рдиай, 8
|
||||
переместить_имм рсиай, msg_dead_4
|
||||
переместить_имм рдикс, len_msg_dead_4
|
||||
вызов_системы
|
||||
переместить_имм раикс, 9
|
||||
переместить_имм рдиай, 9
|
||||
переместить_имм рсиай, msg_dead_4
|
||||
переместить_имм рдикс, len_msg_dead_4
|
||||
вызов_системы
|
||||
переместить_имм раикс, 10
|
||||
переместить_имм рдиай, 10
|
||||
переместить_имм рсиай, msg_dead_4
|
||||
переместить_имм рдикс, len_msg_dead_4
|
||||
вызов_системы
|
||||
переместить_имм раикс, 11
|
||||
переместить_имм рдиай, 11
|
||||
переместить_имм рсиай, msg_dead_4
|
||||
переместить_имм рдикс, len_msg_dead_4
|
||||
вызов_системы
|
||||
переместить_имм раикс, 12
|
||||
переместить_имм рдиай, 12
|
||||
переместить_имм рсиай, msg_dead_4
|
||||
переместить_имм рдикс, len_msg_dead_4
|
||||
вызов_системы
|
||||
переместить_имм раикс, 13
|
||||
переместить_имм рдиай, 13
|
||||
переместить_имм рсиай, msg_dead_4
|
||||
переместить_имм рдикс, len_msg_dead_4
|
||||
вызов_системы
|
||||
переместить_имм раикс, 14
|
||||
переместить_имм рдиай, 14
|
||||
переместить_имм рсиай, msg_dead_4
|
||||
переместить_имм рдикс, len_msg_dead_4
|
||||
вызов_системы
|
||||
переместить_имм раикс, 15
|
||||
переместить_имм рдиай, 15
|
||||
переместить_имм рсиай, msg_dead_4
|
||||
переместить_имм рдикс, len_msg_dead_4
|
||||
вызов_системы
|
||||
; ---------------------
|
||||
мимо_мертвого_кода_4:
|
||||
|
||||
; ДОПОЛНИТЕЛЬНЫЙ ПЕРЕХОД 2: "Один назад" - переход к мертвому_коду_3 (делая его живым)
|
||||
переход мертвый_код_3
|
||||
|
||||
; --- МЕРТВЫЙ КОД 5 ---
|
||||
; Этот код НЕ должен выполниться
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, msg_dead_5
|
||||
переместить_имм рдикс, len_msg_dead_5
|
||||
вызов_системы
|
||||
переместить_имм раикс, 2
|
||||
переместить_имм рдиай, 2
|
||||
переместить_имм рсиай, msg_dead_5
|
||||
переместить_имм рдикс, len_msg_dead_5
|
||||
вызов_системы
|
||||
переместить_имм раикс, 3
|
||||
переместить_имм рдиай, 3
|
||||
переместить_имм рсиай, msg_dead_5
|
||||
переместить_имм рдикс, len_msg_dead_5
|
||||
вызов_системы
|
||||
переместить_имм раикс, 4
|
||||
переместить_имм рдиай, 4
|
||||
переместить_имм рсиай, msg_dead_5
|
||||
переместить_имм рдикс, len_msg_dead_5
|
||||
вызов_системы
|
||||
переместить_имм раикс, 5
|
||||
переместить_имм рдиай, 5
|
||||
переместить_имм рсиай, msg_dead_5
|
||||
переместить_имм рдикс, len_msg_dead_5
|
||||
вызов_системы
|
||||
переместить_имм раикс, 6
|
||||
переместить_имм рдиай, 6
|
||||
переместить_имм рсиай, msg_dead_5
|
||||
переместить_имм рдикс, len_msg_dead_5
|
||||
вызов_системы
|
||||
переместить_имм раикс, 7
|
||||
переместить_имм рдиай, 7
|
||||
переместить_имм рсиай, msg_dead_5
|
||||
переместить_имм рдикс, len_msg_dead_5
|
||||
вызов_системы
|
||||
переместить_имм раикс, 8
|
||||
переместить_имм рдиай, 8
|
||||
переместить_имм рсиай, msg_dead_5
|
||||
переместить_имм рдикс, len_msg_dead_5
|
||||
вызов_системы
|
||||
переместить_имм раикс, 9
|
||||
переместить_имм рдиай, 9
|
||||
переместить_имм рсиай, msg_dead_5
|
||||
переместить_имм рдикс, len_msg_dead_5
|
||||
вызов_системы
|
||||
переместить_имм раикс, 10
|
||||
переместить_имм рдиай, 10
|
||||
переместить_имм рсиай, msg_dead_5
|
||||
переместить_имм рдикс, len_msg_dead_5
|
||||
вызов_системы
|
||||
переместить_имм раикс, 11
|
||||
переместить_имм рдиай, 11
|
||||
переместить_имм рсиай, msg_dead_5
|
||||
переместить_имм рдикс, len_msg_dead_5
|
||||
вызов_системы
|
||||
переместить_имм раикс, 12
|
||||
переместить_имм рдиай, 12
|
||||
переместить_имм рсиай, msg_dead_5
|
||||
переместить_имм рдикс, len_msg_dead_5
|
||||
вызов_системы
|
||||
переместить_имм раикс, 13
|
||||
переместить_имм рдиай, 13
|
||||
переместить_имм рсиай, msg_dead_5
|
||||
переместить_имм рдикс, len_msg_dead_5
|
||||
вызов_системы
|
||||
переместить_имм раикс, 14
|
||||
переместить_имм рдиай, 14
|
||||
переместить_имм рсиай, msg_dead_5
|
||||
переместить_имм рдикс, len_msg_dead_5
|
||||
вызов_системы
|
||||
переместить_имм раикс, 15
|
||||
переместить_имм рдиай, 15
|
||||
переместить_имм рсиай, msg_dead_5
|
||||
переместить_имм рдикс, len_msg_dead_5
|
||||
вызов_системы
|
||||
; ---------------------
|
||||
|
||||
; --- МЕРТВЫЙ КОД 6 ---
|
||||
; Этот код НЕ должен выполниться
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, msg_dead_6
|
||||
переместить_имм рдикс, len_msg_dead_6
|
||||
вызов_системы
|
||||
переместить_имм раикс, 2
|
||||
переместить_имм рдиай, 2
|
||||
переместить_имм рсиай, msg_dead_6
|
||||
переместить_имм рдикс, len_msg_dead_6
|
||||
вызов_системы
|
||||
переместить_имм раикс, 3
|
||||
переместить_имм рдиай, 3
|
||||
переместить_имм рсиай, msg_dead_6
|
||||
переместить_имм рдикс, len_msg_dead_6
|
||||
вызов_системы
|
||||
переместить_имм раикс, 4
|
||||
переместить_имм рдиай, 4
|
||||
переместить_имм рсиай, msg_dead_6
|
||||
переместить_имм рдикс, len_msg_dead_6
|
||||
вызов_системы
|
||||
переместить_имм раикс, 5
|
||||
переместить_имм рдиай, 5
|
||||
переместить_имм рсиай, msg_dead_6
|
||||
переместить_имм рдикс, len_msg_dead_6
|
||||
вызов_системы
|
||||
переместить_имм раикс, 6
|
||||
переместить_имм рдиай, 6
|
||||
переместить_имм рсиай, msg_dead_6
|
||||
переместить_имм рдикс, len_msg_dead_6
|
||||
вызов_системы
|
||||
переместить_имм раикс, 7
|
||||
переместить_имм рдиай, 7
|
||||
переместить_имм рсиай, msg_dead_6
|
||||
переместить_имм рдикс, len_msg_dead_6
|
||||
вызов_системы
|
||||
переместить_имм раикс, 8
|
||||
переместить_имм рдиай, 8
|
||||
переместить_имм рсиай, msg_dead_6
|
||||
переместить_имм рдикс, len_msg_dead_6
|
||||
вызов_системы
|
||||
переместить_имм раикс, 9
|
||||
переместить_имм рдиай, 9
|
||||
переместить_имм рсиай, msg_dead_6
|
||||
переместить_имм рдикс, len_msg_dead_6
|
||||
вызов_системы
|
||||
переместить_имм раикс, 10
|
||||
переместить_имм рдиай, 10
|
||||
переместить_имм рсиай, msg_dead_6
|
||||
переместить_имм рдикс, len_msg_dead_6
|
||||
вызов_системы
|
||||
переместить_имм раикс, 11
|
||||
переместить_имм рдиай, 11
|
||||
переместить_имм рсиай, msg_dead_6
|
||||
переместить_имм рдикс, len_msg_dead_6
|
||||
вызов_системы
|
||||
переместить_имм раикс, 12
|
||||
переместить_имм рдиай, 12
|
||||
переместить_имм рсиай, msg_dead_6
|
||||
переместить_имм рдикс, len_msg_dead_6
|
||||
вызов_системы
|
||||
переместить_имм раикс, 13
|
||||
переместить_имм рдиай, 13
|
||||
переместить_имм рсиай, msg_dead_6
|
||||
переместить_имм рдикс, len_msg_dead_6
|
||||
вызов_системы
|
||||
переместить_имм раикс, 14
|
||||
переместить_имм рдиай, 14
|
||||
переместить_имм рсиай, msg_dead_6
|
||||
переместить_имм рдикс, len_msg_dead_6
|
||||
вызов_системы
|
||||
переместить_имм раикс, 15
|
||||
переместить_имм рдиай, 15
|
||||
переместить_имм рсиай, msg_dead_6
|
||||
переместить_имм рдикс, len_msg_dead_6
|
||||
вызов_системы
|
||||
; ---------------------
|
||||
|
||||
; --- МЕРТВЫЙ КОД 7 ---
|
||||
; Этот код НЕ должен выполниться
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, msg_dead_7
|
||||
переместить_имм рдикс, len_msg_dead_7
|
||||
вызов_системы
|
||||
переместить_имм раикс, 2
|
||||
переместить_имм рдиай, 2
|
||||
переместить_имм рсиай, msg_dead_7
|
||||
переместить_имм рдикс, len_msg_dead_7
|
||||
вызов_системы
|
||||
переместить_имм раикс, 3
|
||||
переместить_имм рдиай, 3
|
||||
переместить_имм рсиай, msg_dead_7
|
||||
переместить_имм рдикс, len_msg_dead_7
|
||||
вызов_системы
|
||||
переместить_имм раикс, 4
|
||||
переместить_имм рдиай, 4
|
||||
переместить_имм рсиай, msg_dead_7
|
||||
переместить_имм рдикс, len_msg_dead_7
|
||||
вызов_системы
|
||||
переместить_имм раикс, 5
|
||||
переместить_имм рдиай, 5
|
||||
переместить_имм рсиай, msg_dead_7
|
||||
переместить_имм рдикс, len_msg_dead_7
|
||||
вызов_системы
|
||||
переместить_имм раикс, 6
|
||||
переместить_имм рдиай, 6
|
||||
переместить_имм рсиай, msg_dead_7
|
||||
переместить_имм рдикс, len_msg_dead_7
|
||||
вызов_системы
|
||||
переместить_имм раикс, 7
|
||||
переместить_имм рдиай, 7
|
||||
переместить_имм рсиай, msg_dead_7
|
||||
переместить_имм рдикс, len_msg_dead_7
|
||||
вызов_системы
|
||||
переместить_имм раикс, 8
|
||||
переместить_имм рдиай, 8
|
||||
переместить_имм рсиай, msg_dead_7
|
||||
переместить_имм рдикс, len_msg_dead_7
|
||||
вызов_системы
|
||||
переместить_имм раикс, 9
|
||||
переместить_имм рдиай, 9
|
||||
переместить_имм рсиай, msg_dead_7
|
||||
переместить_имм рдикс, len_msg_dead_7
|
||||
вызов_системы
|
||||
переместить_имм раикс, 10
|
||||
переместить_имм рдиай, 10
|
||||
переместить_имм рсиай, msg_dead_7
|
||||
переместить_имм рдикс, len_msg_dead_7
|
||||
вызов_системы
|
||||
переместить_имм раикс, 11
|
||||
переместить_имм рдиай, 11
|
||||
переместить_имм рсиай, msg_dead_7
|
||||
переместить_имм рдикс, len_msg_dead_7
|
||||
вызов_системы
|
||||
переместить_имм раикс, 12
|
||||
переместить_имм рдиай, 12
|
||||
переместить_имм рсиай, msg_dead_7
|
||||
переместить_имм рдикс, len_msg_dead_7
|
||||
вызов_системы
|
||||
переместить_имм раикс, 13
|
||||
переместить_имм рдиай, 13
|
||||
переместить_имм рсиай, msg_dead_7
|
||||
переместить_имм рдикс, len_msg_dead_7
|
||||
вызов_системы
|
||||
переместить_имм раикс, 14
|
||||
переместить_имм рдиай, 14
|
||||
переместить_имм рсиай, msg_dead_7
|
||||
переместить_имм рдикс, len_msg_dead_7
|
||||
вызов_системы
|
||||
переместить_имм раикс, 15
|
||||
переместить_имм рдиай, 15
|
||||
переместить_имм рсиай, msg_dead_7
|
||||
переместить_имм рдикс, len_msg_dead_7
|
||||
вызов_системы
|
||||
; ---------------------
|
||||
|
||||
проверка_8:
|
||||
; СЕДЬМОЙ ПЕРЕХОД: переход_если_перенос
|
||||
; Выполним вычитание, которое вызовет перенос: rbx - rax = 5 - 10
|
||||
переместить_имм рбикс, 5 ; rbx = 5
|
||||
переместить_имм раикс, 10 ; rax = 10
|
||||
; rbx - rax = 5 - 10 -> CF=1
|
||||
вычесть рбикс, раикс ; rbx = rbx - rax = 5 - 10. Это вызовет перенос (CF=1).
|
||||
; Условие jc: CF=1. CF=1. jc СРАБОТАЕТ.
|
||||
; Мы хотим прыгнуть МИМО мертвого кода 8, если jc сработает (т.е. если был перенос).
|
||||
переход_если_перенос мимо_мертвого_кода_8
|
||||
; --- МЕРТВЫЙ КОД 8 ---
|
||||
; Этот код НЕ должен выполниться (так как jc сработал)
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, msg_dead_8
|
||||
переместить_имм рдикс, len_msg_dead_8
|
||||
вызов_системы
|
||||
переместить_имм раикс, 2
|
||||
переместить_имм рдиай, 2
|
||||
переместить_имм рсиай, msg_dead_8
|
||||
переместить_имм рдикс, len_msg_dead_8
|
||||
вызов_системы
|
||||
переместить_имм раикс, 3
|
||||
переместить_имм рдиай, 3
|
||||
переместить_имм рсиай, msg_dead_8
|
||||
переместить_имм рдикс, len_msg_dead_8
|
||||
вызов_системы
|
||||
переместить_имм раикс, 4
|
||||
переместить_имм рдиай, 4
|
||||
переместить_имм рсиай, msg_dead_8
|
||||
переместить_имм рдикс, len_msg_dead_8
|
||||
вызов_системы
|
||||
переместить_имм раикс, 5
|
||||
переместить_имм рдиай, 5
|
||||
переместить_имм рсиай, msg_dead_8
|
||||
переместить_имм рдикс, len_msg_dead_8
|
||||
вызов_системы
|
||||
переместить_имм раикс, 6
|
||||
переместить_имм рдиай, 6
|
||||
переместить_имм рсиай, msg_dead_8
|
||||
переместить_имм рдикс, len_msg_dead_8
|
||||
вызов_системы
|
||||
переместить_имм раикс, 7
|
||||
переместить_имм рдиай, 7
|
||||
переместить_имм рсиай, msg_dead_8
|
||||
переместить_имм рдикс, len_msg_dead_8
|
||||
вызов_системы
|
||||
переместить_имм раикс, 8
|
||||
переместить_имм рдиай, 8
|
||||
переместить_имм рсиай, msg_dead_8
|
||||
переместить_имм рдикс, len_msg_dead_8
|
||||
вызов_системы
|
||||
переместить_имм раикс, 9
|
||||
переместить_имм рдиай, 9
|
||||
переместить_имм рсиай, msg_dead_8
|
||||
переместить_имм рдикс, len_msg_dead_8
|
||||
вызов_системы
|
||||
переместить_имм раикс, 10
|
||||
переместить_имм рдиай, 10
|
||||
переместить_имм рсиай, msg_dead_8
|
||||
переместить_имм рдикс, len_msg_dead_8
|
||||
вызов_системы
|
||||
переместить_имм раикс, 11
|
||||
переместить_имм рдиай, 11
|
||||
переместить_имм рсиай, msg_dead_8
|
||||
переместить_имм рдикс, len_msg_dead_8
|
||||
вызов_системы
|
||||
переместить_имм раикс, 12
|
||||
переместить_имм рдиай, 12
|
||||
переместить_имм рсиай, msg_dead_8
|
||||
переместить_имм рдикс, len_msg_dead_8
|
||||
вызов_системы
|
||||
переместить_имм раикс, 13
|
||||
переместить_имм рдиай, 13
|
||||
переместить_имм рсиай, msg_dead_8
|
||||
переместить_имм рдикс, len_msg_dead_8
|
||||
вызов_системы
|
||||
переместить_имм раикс, 14
|
||||
переместить_имм рдиай, 14
|
||||
переместить_имм рсиай, msg_dead_8
|
||||
переместить_имм рдикс, len_msg_dead_8
|
||||
вызов_системы
|
||||
переместить_имм раикс, 15
|
||||
переместить_имм рдиай, 15
|
||||
переместить_имм рсиай, msg_dead_8
|
||||
переместить_имм рдикс, len_msg_dead_8
|
||||
вызов_системы
|
||||
; ---------------------
|
||||
|
||||
мимо_мертвого_кода_8:
|
||||
|
||||
; ВОСЬМОЙ ПЕРЕХОД: переход_если_нет_переноса
|
||||
; Убедимся, что CF=0. Выполним операцию, которая сбросит CF.
|
||||
сравнить раикс, раикс ; CF = 0 (так как rax - rax = 0, без переноса)
|
||||
; Условие jnc: CF=0. CF=0. jnc СРАБОТАЕТ.
|
||||
; Мы хотим прыгнуть МИМО мертвого кода 9, если jnc сработает (т.е. если НЕ было переноса).
|
||||
переход_если_нет_переноса мимо_мертвого_кода_9
|
||||
; --- МЕРТВЫЙ КОД 9 ---
|
||||
; Этот код НЕ должен выполниться (так как jnc сработал)
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, msg_dead_9
|
||||
переместить_имм рдикс, len_msg_dead_9
|
||||
вызов_системы
|
||||
переместить_имм раикс, 2
|
||||
переместить_имм рдиай, 2
|
||||
переместить_имм рсиай, msg_dead_9
|
||||
переместить_имм рдикс, len_msg_dead_9
|
||||
вызов_системы
|
||||
переместить_имм раикс, 3
|
||||
переместить_имм рдиай, 3
|
||||
переместить_имм рсиай, msg_dead_9
|
||||
переместить_имм рдикс, len_msg_dead_9
|
||||
вызов_системы
|
||||
переместить_имм раикс, 4
|
||||
переместить_имм рдиай, 4
|
||||
переместить_имм рсиай, msg_dead_9
|
||||
переместить_имм рдикс, len_msg_dead_9
|
||||
вызов_системы
|
||||
переместить_имм раикс, 5
|
||||
переместить_имм рдиай, 5
|
||||
переместить_имм рсиай, msg_dead_9
|
||||
переместить_имм рдикс, len_msg_dead_9
|
||||
вызов_системы
|
||||
переместить_имм раикс, 6
|
||||
переместить_имм рдиай, 6
|
||||
переместить_имм рсиай, msg_dead_9
|
||||
переместить_имм рдикс, len_msg_dead_9
|
||||
вызов_системы
|
||||
переместить_имм раикс, 7
|
||||
переместить_имм рдиай, 7
|
||||
переместить_имм рсиай, msg_dead_9
|
||||
переместить_имм рдикс, len_msg_dead_9
|
||||
вызов_системы
|
||||
переместить_имм раикс, 8
|
||||
переместить_имм рдиай, 8
|
||||
переместить_имм рсиай, msg_dead_9
|
||||
переместить_имм рдикс, len_msg_dead_9
|
||||
вызов_системы
|
||||
переместить_имм раикс, 9
|
||||
переместить_имм рдиай, 9
|
||||
переместить_имм рсиай, msg_dead_9
|
||||
переместить_имм рдикс, len_msg_dead_9
|
||||
вызов_системы
|
||||
переместить_имм раикс, 10
|
||||
переместить_имм рдиай, 10
|
||||
переместить_имм рсиай, msg_dead_9
|
||||
переместить_имм рдикс, len_msg_dead_9
|
||||
вызов_системы
|
||||
переместить_имм раикс, 11
|
||||
переместить_имм рдиай, 11
|
||||
переместить_имм рсиай, msg_dead_9
|
||||
переместить_имм рдикс, len_msg_dead_9
|
||||
вызов_системы
|
||||
переместить_имм раикс, 12
|
||||
переместить_имм рдиай, 12
|
||||
переместить_имм рсиай, msg_dead_9
|
||||
переместить_имм рдикс, len_msg_dead_9
|
||||
вызов_системы
|
||||
переместить_имм раикс, 13
|
||||
переместить_имм рдиай, 13
|
||||
переместить_имм рсиай, msg_dead_9
|
||||
переместить_имм рдикс, len_msg_dead_9
|
||||
вызов_системы
|
||||
переместить_имм раикс, 14
|
||||
переместить_имм рдиай, 14
|
||||
переместить_имм рсиай, msg_dead_9
|
||||
переместить_имм рдикс, len_msg_dead_9
|
||||
вызов_системы
|
||||
переместить_имм раикс, 15
|
||||
переместить_имм рдиай, 15
|
||||
переместить_имм рсиай, msg_dead_9
|
||||
переместить_имм рдикс, len_msg_dead_9
|
||||
вызов_системы
|
||||
; ---------------------
|
||||
|
||||
мимо_мертвого_кода_9:
|
||||
|
||||
; ДЕВЯТЫЙ ПЕРЕХОД: переход (безусловный)
|
||||
; Просто прыгаем мимо мертвого кода 10.
|
||||
переход мимо_мертвого_кода_10
|
||||
; --- МЕРТВЫЙ КОД 10 ---
|
||||
; Этот код НЕ должен выполниться (так как jmp сработал)
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, msg_dead_10
|
||||
переместить_имм рдикс, len_msg_dead_10
|
||||
вызов_системы
|
||||
переместить_имм раикс, 2
|
||||
переместить_имм рдиай, 2
|
||||
переместить_имм рсиай, msg_dead_10
|
||||
переместить_имм рдикс, len_msg_dead_10
|
||||
вызов_системы
|
||||
переместить_имм раикс, 3
|
||||
переместить_имм рдиай, 3
|
||||
переместить_имм рсиай, msg_dead_10
|
||||
переместить_имм рдикс, len_msg_dead_10
|
||||
вызов_системы
|
||||
переместить_имм раикс, 4
|
||||
переместить_имм рдиай, 4
|
||||
переместить_имм рсиай, msg_dead_10
|
||||
переместить_имм рдикс, len_msg_dead_10
|
||||
вызов_системы
|
||||
переместить_имм раикс, 5
|
||||
переместить_имм рдиай, 5
|
||||
переместить_имм рсиай, msg_dead_10
|
||||
переместить_имм рдикс, len_msg_dead_10
|
||||
вызов_системы
|
||||
переместить_имм раикс, 6
|
||||
переместить_имм рдиай, 6
|
||||
переместить_имм рсиай, msg_dead_10
|
||||
переместить_имм рдикс, len_msg_dead_10
|
||||
вызов_системы
|
||||
переместить_имм раикс, 7
|
||||
переместить_имм рдиай, 7
|
||||
переместить_имм рсиай, msg_dead_10
|
||||
переместить_имм рдикс, len_msg_dead_10
|
||||
вызов_системы
|
||||
переместить_имм раикс, 8
|
||||
переместить_имм рдиай, 8
|
||||
переместить_имм рсиай, msg_dead_10
|
||||
переместить_имм рдикс, len_msg_dead_10
|
||||
вызов_системы
|
||||
переместить_имм раикс, 9
|
||||
переместить_имм рдиай, 9
|
||||
переместить_имм рсиай, msg_dead_10
|
||||
переместить_имм рдикс, len_msg_dead_10
|
||||
вызов_системы
|
||||
переместить_имм раикс, 10
|
||||
переместить_имм рдиай, 10
|
||||
переместить_имм рсиай, msg_dead_10
|
||||
переместить_имм рдикс, len_msg_dead_10
|
||||
вызов_системы
|
||||
переместить_имм раикс, 11
|
||||
переместить_имм рдиай, 11
|
||||
переместить_имм рсиай, msg_dead_10
|
||||
переместить_имм рдикс, len_msg_dead_10
|
||||
вызов_системы
|
||||
переместить_имм раикс, 12
|
||||
переместить_имм рдиай, 12
|
||||
переместить_имм рсиай, msg_dead_10
|
||||
переместить_имм рдикс, len_msg_dead_10
|
||||
вызов_системы
|
||||
переместить_имм раикс, 13
|
||||
переместить_имм рдиай, 13
|
||||
переместить_имм рсиай, msg_dead_10
|
||||
переместить_имм рдикс, len_msg_dead_10
|
||||
вызов_системы
|
||||
переместить_имм раикс, 14
|
||||
переместить_имм рдиай, 14
|
||||
переместить_имм рсиай, msg_dead_10
|
||||
переместить_имм рдикс, len_msg_dead_10
|
||||
вызов_системы
|
||||
переместить_имм раикс, 15
|
||||
переместить_имм рдиай, 15
|
||||
переместить_имм рсиай, msg_dead_10
|
||||
переместить_имм рдикс, len_msg_dead_10
|
||||
вызов_системы
|
||||
; ---------------------
|
||||
|
||||
мимо_мертвого_кода_10:
|
||||
|
||||
; --- ВЫВОД ЦЕЛЕВОГО СООБЩЕНИЯ ---
|
||||
вывести_сообщение:
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, msg_success
|
||||
переместить_имм рдикс, len_msg_success
|
||||
вызов_системы
|
||||
|
||||
; --- ЗАВЕРШЕНИЕ ---
|
||||
переместить_имм раикс, 60
|
||||
переместить_имм рдиай, 0
|
||||
вызов_системы
|
||||
|
||||
.данные
|
||||
; Перемешиваем строки и константы
|
||||
; "Живой из 3!\n" = 8 букв * 2 + 1 (!) + 1 (\n от .строка_нуль) = 16 + 2 = 18 байт на содержимое. len = 18
|
||||
msg_live_from_3: .строка_нуль "Живой из 3!\n"
|
||||
.константа len_msg_live_from_3 = 18
|
||||
; "Успех!\n" = 5 букв * 2 + 1 (!) + 1 (\n от .строка_нуль) = 10 + 2 = 12 байт на содержимое. len = 12
|
||||
msg_success: .строка_нуль "Успех!\n"
|
||||
.константа len_msg_success = 12
|
||||
; "Мертвый код 10!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строка_нуль) = 14 + 4 + 1 = 19 байт на содержимое. len = 19
|
||||
msg_dead_10: .строка_нуль "Мертвый код 10!"
|
||||
.константа len_msg_dead_10 = 19
|
||||
; "Мертвый код 9!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строка_нуль) = 14 + 4 + 1 = 19 байт на содержимое. len = 19
|
||||
msg_dead_9: .строка_нуль "Мертвый код 9!"
|
||||
.константа len_msg_dead_9 = 19
|
||||
; "Мертвый код 8!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строка_нуль) = 14 + 4 + 1 = 19 байт на содержимое. len = 19
|
||||
msg_dead_8: .строка_нуль "Мертвый код 8!"
|
||||
.константа len_msg_dead_8 = 19
|
||||
; "Мертвый код 7!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строка_нуль) = 14 + 4 + 1 = 19 байт на содержимое. len = 19
|
||||
msg_dead_7: .строка_нуль "Мертвый код 7!"
|
||||
.константа len_msg_dead_7 = 19
|
||||
; "Мертвый код 6!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строка_нуль) = 14 + 4 + 1 = 19 байт на содержимое. len = 19
|
||||
msg_dead_6: .строка_нуль "Мертвый код 6!"
|
||||
.константа len_msg_dead_6 = 19
|
||||
; "Мертвый код 5!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строка_нуль) = 14 + 4 + 1 = 19 байт на содержимое. len = 19
|
||||
msg_dead_5: .строка_нуль "Мертвый код 5!"
|
||||
.константа len_msg_dead_5 = 19
|
||||
; "Мертвый код 4!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строка_нуль) = 14 + 4 + 1 = 19 байт на содержимое. len = 19
|
||||
msg_dead_4: .строка_нуль "Мертвый код 4!"
|
||||
.константа len_msg_dead_4 = 19
|
||||
; "Мертвый код 3!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строка_нуль) = 14 + 4 + 1 = 19 байт на содержимое. len = 19
|
||||
msg_dead_3: .строка_нуль "Мертвый код 3!"
|
||||
.константа len_msg_dead_3 = 19
|
||||
; "Мертвый код 2!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строка_нуль) = 14 + 4 + 1 = 19 байт на содержимое. len = 19
|
||||
msg_dead_2: .строка_нуль "Мертвый код 2!"
|
||||
.константа len_msg_dead_2 = 19
|
||||
; "Мертвый код 1!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строка_нуль) = 14 + 4 + 1 = 19 байт на содержимое. len = 19
|
||||
msg_dead_1: .строка_нуль "Мертвый код 1!"
|
||||
.константа len_msg_dead_1 = 19
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
.текст
|
||||
.глобал _start
|
||||
|
||||
_start:
|
||||
; Тест: длина числа 1234
|
||||
переместить_имм раикс, 1234
|
||||
вызвать длина_числа ; rax = количество цифр
|
||||
|
||||
; Выводим результат как цифру
|
||||
прибавить_непосредственно раикс, 0x30
|
||||
сохранить [буфер], раикс
|
||||
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, буфер
|
||||
переместить_имм рдикс, 1
|
||||
вызов_системы
|
||||
|
||||
; Перевод строки
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, nl
|
||||
переместить_имм рдикс, 1
|
||||
вызов_системы
|
||||
|
||||
; exit(0)
|
||||
переместить_имм раикс, 60
|
||||
переместить_имм рдиай, 0
|
||||
вызов_системы
|
||||
|
||||
; =============================================
|
||||
; длина_числа: количество десятичных цифр в rax
|
||||
; Вход: rax = число
|
||||
; Выход: rax = количество цифр (1..20)
|
||||
; =============================================
|
||||
длина_числа:
|
||||
втолкнуть р8
|
||||
втолкнуть р9
|
||||
|
||||
переместить р8, раикс ; р8 = число
|
||||
переместить_имм р9, 0 ; счётчик = 0
|
||||
|
||||
; Проверка на 0
|
||||
сравнить_с р8, 0
|
||||
короткий_переход_если_неравно длина_цикл
|
||||
переместить_имм раикс, 1 ; 0 — это 1 цифра
|
||||
вытолкнуть р9
|
||||
вытолкнуть р8
|
||||
вернуться
|
||||
|
||||
длина_цикл:
|
||||
увеличить р9 ; счётчик++
|
||||
|
||||
; Делим на 10
|
||||
переместить раикс, р8
|
||||
переместить_имм рдикс, 0
|
||||
переместить_имм рсикс, 10
|
||||
разделить рсикс
|
||||
переместить р8, раикс ; частное
|
||||
|
||||
сравнить_с р8, 0
|
||||
короткий_переход_если_неравно длина_цикл
|
||||
|
||||
переместить раикс, р9 ; результат
|
||||
вытолкнуть р9
|
||||
вытолкнуть р8
|
||||
вернуться
|
||||
|
||||
.данные
|
||||
буфер:
|
||||
.байт 0, 0, 0, 0, 0, 0, 0, 0
|
||||
nl:
|
||||
.байт 0x0A
|
||||
|
|
@ -1,104 +0,0 @@
|
|||
00000000 7F45 jg 0x47
|
||||
00000002 4C rex.wr
|
||||
00000003 460201 add r8b,[rcx]
|
||||
00000006 0100 add [rax],eax
|
||||
00000010 0200 add al,[rax]
|
||||
00000012 3E0001 add [ds:rcx],al
|
||||
00000019 104000 adc [rax+0x0],al
|
||||
00000027 005020 add [rax+0x20],dl
|
||||
00000034 400038 add [rax],dil
|
||||
00000037 0003 add [rbx],al
|
||||
00000039 004000 add [rax+0x0],al
|
||||
0000003C 0500040001 add eax,0x1000400
|
||||
00000043 000400 add [rax+rax],al
|
||||
00000059 004000 add [rax+0x0],al
|
||||
00000060 E800000000 call 0x65
|
||||
00000069 1000 adc [rax],al
|
||||
00000071 1000 adc [rax],al
|
||||
00000077 0001 add [rcx],al
|
||||
0000007B 000500000000 add [rel 0x81],al
|
||||
00000081 1000 adc [rax],al
|
||||
00000089 104000 adc [rax+0x0],al
|
||||
00000090 0010 add [rax],dl
|
||||
00000097 004000 add [rax+0x0],al
|
||||
000000A0 0010 add [rax],dl
|
||||
000000A8 0010 add [rax],dl
|
||||
000000B0 0100 add [rax],eax
|
||||
000000B4 06 db 0x06
|
||||
000000B9 2000 and [rax],al
|
||||
000000C1 204000 and [rax+0x0],al
|
||||
000000C8 0020 add [rax],ah
|
||||
000000CF 001500000000 add [rel 0xd5],dl
|
||||
000000D9 1000 adc [rax],al
|
||||
000000E1 1000 adc [rax],al
|
||||
00000FFF 0048B8 add [rax-0x48],cl
|
||||
00001002 0100 add [rax],eax
|
||||
0000100A 48BF010000000000 mov rdi,0x1
|
||||
-0000
|
||||
00001014 48BE002040000000 mov rsi,0x402000
|
||||
-0000
|
||||
0000101E 48BA150000000000 mov rdx,0x15
|
||||
-0000
|
||||
00001028 0F05 syscall
|
||||
0000102A 48B83C0000000000 mov rax,0x3c
|
||||
-0000
|
||||
00001034 48BF000000000000 mov rdi,0x0
|
||||
-0000
|
||||
0000103E 0F05 syscall
|
||||
00002000 D09FD180D0B8 rcr byte [rdi-0x472f7f2f],1
|
||||
00002006 D0 db 0xd0
|
||||
00002007 B2D0 mov dl,0xd0
|
||||
00002009 B5D1 mov ch,0xd1
|
||||
0000200B 82 db 0x82
|
||||
0000200C 20D0 and al,dl
|
||||
0000200E BCD0B8D180 mov esp,0x80d1b8d0
|
||||
00002013 210A and [rdx],ecx
|
||||
00002015 D0A1D0B1D0BE shl byte [rcx-0x412f4e30],1
|
||||
0000201B D180D189D0B8 rol dword [rax-0x472f762f],1
|
||||
00002021 D0BA20D09AD0 sar byte [rdx-0x2f652fe0],1
|
||||
00002027 92 xchg eax,edx
|
||||
00002028 D0A100000000 shl byte [rcx+0x0],1
|
||||
00002030 002E add [rsi],ch
|
||||
00002032 7465 jz 0x2099
|
||||
00002034 7874 js 0x20aa
|
||||
00002036 002E add [rsi],ch
|
||||
00002038 64 fs
|
||||
00002039 61 db 0x61
|
||||
0000203A 7461 jz 0x209d
|
||||
0000203C 002E add [rsi],ch
|
||||
0000203E 63 db 0x63
|
||||
0000203F 6F outsd
|
||||
00002040 6D insd
|
||||
00002041 6D insd
|
||||
00002042 656E gs outsb
|
||||
00002044 7400 jz 0x2046
|
||||
00002046 2E7368 cs jnc 0x20b1
|
||||
00002049 7374 jnc 0x20bf
|
||||
0000204B 7274 jc 0x20c1
|
||||
0000204D 61 db 0x61
|
||||
0000204E 62 db 0x62
|
||||
0000207F 0001 add [rcx],al
|
||||
0000208F 0001 add [rcx],al
|
||||
00002093 0001 add [rcx],al
|
||||
00002097 0006 add [rsi],al
|
||||
000020A1 104000 adc [rax+0x0],al
|
||||
000020A8 0010 add [rax],dl
|
||||
000020BF 0010 add [rax],dl
|
||||
000020CF 0007 add [rdi],al
|
||||
000020D3 0001 add [rcx],al
|
||||
000020D7 0003 add [rbx],al
|
||||
000020E1 204000 and [rax+0x0],al
|
||||
000020E8 0020 add [rax],ah
|
||||
000020F0 1500000000 adc eax,0x0
|
||||
000020FF 0008 add [rax],cl
|
||||
0000210F 000D00000001 add [rel 0x1002115],cl
|
||||
00002127 001520000000 add [rel 0x214d],dl
|
||||
0000212F 0016 add [rsi],dl
|
||||
0000213F 0001 add [rcx],al
|
||||
0000214F 0016 add [rsi],dl
|
||||
00002153 0003 add [rbx],al
|
||||
00002167 0030 add [rax],dh
|
||||
00002169 2000 and [rax],al
|
||||
0000216F 0020 add [rax],ah
|
||||
0000217F 0001 add [rcx],al
|
||||
0000218F 00 db 0x00
|
||||
|
|
@ -1,204 +0,0 @@
|
|||
; сложный_тест9.квс
|
||||
; Тест: запутанные переходы, крякмис
|
||||
|
||||
.текст
|
||||
.глобал _start
|
||||
|
||||
_start:
|
||||
; Инициализация регистров
|
||||
переместить_имм раикс, 10 ; rax = 10
|
||||
переместить_имм рбикс, 5 ; rbx = 5
|
||||
переместить_имм рсикс, 10 ; rcx = 10 (для проверки ZF в jz)
|
||||
|
||||
; ПЕРВЫЙ ПЕРЕХОД: короткий_переход_если_не_ноль
|
||||
; ZF=0 (так как rax=10), значит jnz сработает
|
||||
; Прыгаем к метке 'проверка_2', пропуская мертвый_код_1
|
||||
короткий_переход_если_не_ноль проверка_2
|
||||
|
||||
; --- МЕРТВЫЙ КОД 1 ---
|
||||
; Этот код НЕ должен выполниться
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, msg_dead_1
|
||||
переместить_имм рдикс, len_msg_dead_1
|
||||
вызов_системы
|
||||
; ---------------------
|
||||
|
||||
проверка_2:
|
||||
; ДОПОЛНИТЕЛЬНЫЙ ПЕРЕХОД 1: "Два шага вперед" - короткий_переход через мертвый_код_2 и мертвый_код_3
|
||||
; Прыгаем к проверка_4, минуя мертвый_код_2 и мертвый_код_3
|
||||
короткий_переход проверка_4
|
||||
|
||||
; --- МЕРТВЫЙ КОД 2 ---
|
||||
; Этот код НЕ должен выполниться из-за прыжка выше
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, msg_dead_2
|
||||
переместить_имм рдикс, len_msg_dead_2
|
||||
вызов_системы
|
||||
; ---------------------
|
||||
|
||||
мертвый_код_3:
|
||||
; ЖИВОЙ КОД 3: Этот код выполнится благодаря прыжку "назад"
|
||||
; Выведем сообщение, чтобы убедиться, что он выполнился
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, msg_live_from_3
|
||||
переместить_имм рдикс, len_msg_live_from_3
|
||||
вызов_системы
|
||||
; ДОПОЛНИТЕЛЬНЫЙ ПЕРЕХОД 3: "Четыре вперед" - переход через мертвый_код_4, 5, 6, 7
|
||||
; Цель слишком далеко для короткого перехода. Используем длинный.
|
||||
; Прыгаем к проверка_8
|
||||
переход проверка_8
|
||||
; ---------------------
|
||||
|
||||
проверка_4:
|
||||
; ЧЕТВЁРТЫЙ ПЕРЕХОД: короткий_переход_если_больше
|
||||
; Сравниваем rax (10) и rbx (5) -> rax > rbx, ZF=0, SF=0, OF=0
|
||||
сравнить раикс, рбикс
|
||||
; Условие jg: ZF=0 (истина) И SF=OF (0=0, истина). jg СРАБОТАЕТ.
|
||||
; Мы хотим прыгнуть МИМО мертвого кода 4, если jg сработает (т.е. если rax > rbx).
|
||||
короткий_переход_если_больше мимо_мертвого_кода_4
|
||||
; --- МЕРТВЫЙ КОД 4 ---
|
||||
; Этот код НЕ должен выполниться (так как jg сработал)
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, msg_dead_4
|
||||
переместить_имм рдикс, len_msg_dead_4
|
||||
вызов_системы
|
||||
; ---------------------
|
||||
мимо_мертвого_кода_4:
|
||||
|
||||
; ДОПОЛНИТЕЛЬНЫЙ ПЕРЕХОД 2: "Один назад" - короткий_переход к мертвому_коду_3 (делая его живым)
|
||||
короткий_переход мертвый_код_3
|
||||
|
||||
; --- МЕРТВЫЙ КОД 5 ---
|
||||
; Этот код НЕ должен выполниться
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, msg_dead_5
|
||||
переместить_имм рдикс, len_msg_dead_5
|
||||
вызов_системы
|
||||
; ---------------------
|
||||
|
||||
; --- МЕРТВЫЙ КОД 6 ---
|
||||
; Этот код НЕ должен выполниться
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, msg_dead_6
|
||||
переместить_имм рдикс, len_msg_dead_6
|
||||
вызов_системы
|
||||
; ---------------------
|
||||
|
||||
; --- МЕРТВЫЙ КОД 7 ---
|
||||
; Этот код НЕ должен выполниться
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, msg_dead_7
|
||||
переместить_имм рдикс, len_msg_dead_7
|
||||
вызов_системы
|
||||
; ---------------------
|
||||
|
||||
проверка_8:
|
||||
; СЕДЬМОЙ ПЕРЕХОД: короткий_переход_если_перенос
|
||||
; Выполним вычитание, которое вызовет перенос: rbx - rax = 5 - 10
|
||||
переместить_имм рбикс, 5 ; rbx = 5
|
||||
переместить_имм раикс, 10 ; rax = 10
|
||||
; rbx - rax = 5 - 10 -> CF=1
|
||||
вычесть рбикс, раикс ; rbx = rbx - rax = 5 - 10. Это вызовет перенос (CF=1).
|
||||
; Условие jc: CF=1. CF=1. jc СРАБОТАЕТ.
|
||||
; Мы хотим прыгнуть МИМО мертвого кода 8, если jc сработает (т.е. если был перенос).
|
||||
короткий_переход_если_перенос мимо_мертвого_кода_8
|
||||
; --- МЕРТВЫЙ КОД 8 ---
|
||||
; Этот код НЕ должен выполниться (так как jc сработал)
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, msg_dead_8
|
||||
переместить_имм рдикс, len_msg_dead_8
|
||||
вызов_системы
|
||||
; ---------------------
|
||||
|
||||
мимо_мертвого_кода_8:
|
||||
|
||||
; ВОСЬМОЙ ПЕРЕХОД: короткий_переход_если_нет_переноса
|
||||
; Убедимся, что CF=0. Выполним операцию, которая сбросит CF.
|
||||
сравнить раикс, раикс ; CF = 0 (так как rax - rax = 0, без переноса)
|
||||
; Условие jnc: CF=0. CF=0. jnc СРАБОТАЕТ.
|
||||
; Мы хотим прыгнуть МИМО мертвого кода 9, если jnc сработает (т.е. если НЕ было переноса).
|
||||
короткий_переход_если_нет_переноса мимо_мертвого_кода_9
|
||||
; --- МЕРТВЫЙ КОД 9 ---
|
||||
; Этот код НЕ должен выполниться (так как jnc сработал)
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, msg_dead_9
|
||||
переместить_имм рдикс, len_msg_dead_9
|
||||
вызов_системы
|
||||
; ---------------------
|
||||
|
||||
мимо_мертвого_кода_9:
|
||||
|
||||
; ДЕВЯТЫЙ ПЕРЕХОД: короткий_переход (безусловный)
|
||||
; Просто прыгаем мимо мертвого кода 10.
|
||||
короткий_переход мимо_мертвого_кода_10
|
||||
; --- МЕРТВЫЙ КОД 10 ---
|
||||
; Этот код НЕ должен выполниться (так как jmp сработал)
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, msg_dead_10
|
||||
переместить_имм рдикс, len_msg_dead_10
|
||||
вызов_системы
|
||||
; ---------------------
|
||||
|
||||
мимо_мертвого_кода_10:
|
||||
|
||||
; --- ВЫВОД ЦЕЛЕВОГО СООБЩЕНИЯ ---
|
||||
вывести_сообщение:
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, msg_success
|
||||
переместить_имм рдикс, len_msg_success
|
||||
вызов_системы
|
||||
|
||||
; --- ЗАВЕРШЕНИЕ ---
|
||||
переместить_имм раикс, 60
|
||||
переместить_имм рдиай, 0
|
||||
вызов_системы
|
||||
|
||||
.данные
|
||||
; Перемешиваем строки и константы
|
||||
; "Живой из 3!\n" = 8 букв * 2 + 1 (!) + 2 (\n) = 16 + 3 = 19 байт на содержимое. len = 19
|
||||
msg_live_from_3: .строка_нуль "Живой из 3!\n"
|
||||
.константа len_msg_live_from_3 = 19
|
||||
; "Успех!\n" = 5 букв * 2 + 1 (!) + 2 (\n) = 13 байт на содержимое. len = 13
|
||||
msg_success: .строка_нуль "Успех!\n"
|
||||
.константа len_msg_success = 13
|
||||
; "Мертвый код 10!" = 7 букв * 2 + 4 символа * 1 = 14 + 4 = 18 байт на содержимое. len = 18
|
||||
msg_dead_10: .строка_нуль "Мертвый код 10!"
|
||||
.константа len_msg_dead_10 = 18
|
||||
; "Мертвый код 9!" = 7 букв * 2 + 4 символа * 1 = 14 + 4 = 18 байт на содержимое. len = 18
|
||||
msg_dead_9: .строка_нуль "Мертвый код 9!"
|
||||
.константа len_msg_dead_9 = 18
|
||||
; "Мертвый код 8!" = 7 букв * 2 + 4 символа * 1 = 14 + 4 = 18 байт на содержимое. len = 18
|
||||
msg_dead_8: .строка_нуль "Мертвый код 8!"
|
||||
.константа len_msg_dead_8 = 18
|
||||
; "Мертвый код 7!" = 7 букв * 2 + 4 символа * 1 = 14 + 4 = 18 байт на содержимое. len = 18
|
||||
msg_dead_7: .строка_нуль "Мертвый код 7!"
|
||||
.константа len_msg_dead_7 = 18
|
||||
; "Мертвый код 6!" = 7 букв * 2 + 4 символа * 1 = 14 + 4 = 18 байт на содержимое. len = 18
|
||||
msg_dead_6: .строка_нуль "Мертвый код 6!"
|
||||
.константа len_msg_dead_6 = 18
|
||||
; "Мертвый код 5!" = 7 букв * 2 + 4 символа * 1 = 14 + 4 = 18 байт на содержимое. len = 18
|
||||
msg_dead_5: .строка_нуль "Мертвый код 5!"
|
||||
.константа len_msg_dead_5 = 18
|
||||
; "Мертвый код 4!" = 7 букв * 2 + 4 символа * 1 = 14 + 4 = 18 байт на содержимое. len = 18
|
||||
msg_dead_4: .строка_нуль "Мертвый код 4!"
|
||||
.константа len_msg_dead_4 = 18
|
||||
; "Мертвый код 3!" = 7 букв * 2 + 4 символа * 1 = 14 + 4 = 18 байт на содержимое. len = 18
|
||||
msg_dead_3: .строка_нуль "Мертвый код 3!"
|
||||
.константа len_msg_dead_3 = 18
|
||||
; "Мертвый код 2!" = 7 букв * 2 + 4 символа * 1 = 14 + 4 = 18 байт на содержимое. len = 18
|
||||
msg_dead_2: .строка_нуль "Мертвый код 2!"
|
||||
.константа len_msg_dead_2 = 18
|
||||
; "Мертвый код 1!" = 7 букв * 2 + 4 символа * 1 = 14 + 4 = 18 байт на содержимое. len = 18
|
||||
msg_dead_1: .строка_нуль "Мертвый код 1!"
|
||||
.константа len_msg_dead_1 = 18
|
||||
66
тесты/т1.квс
66
тесты/т1.квс
|
|
@ -1,66 +0,0 @@
|
|||
.глобал _start
|
||||
.текст
|
||||
|
||||
_start:
|
||||
нет_операции
|
||||
вызов_системы
|
||||
вернуться
|
||||
втолкнуть раикс
|
||||
втолкнуть р8
|
||||
вытолкнуть раикс
|
||||
вытолкнуть р8
|
||||
переместить раикс, рбикс
|
||||
переместить р8, р9
|
||||
сравнить раикс, рбикс
|
||||
сравнить р8, р9
|
||||
проверить раикс, рбикс
|
||||
проверить р8, р9
|
||||
прибавить раикс, рбикс
|
||||
прибавить р8, р9
|
||||
вычесть раикс, рбикс
|
||||
вычесть р8, р9
|
||||
и раикс, рбикс
|
||||
и р8, р9
|
||||
или раикс, рбикс
|
||||
или р8, р9
|
||||
исключающее_или раикс, рбикс
|
||||
исключающее_или р8, р9
|
||||
увеличить раикс
|
||||
увеличить р8
|
||||
увеличить еаикс
|
||||
уменьшить раикс
|
||||
уменьшить р8
|
||||
уменьшить еаикс
|
||||
инвертировать раикс
|
||||
инвертировать еаикс
|
||||
отрицать раикс
|
||||
отрицать еаикс
|
||||
переместить_имм раикс, 10
|
||||
переместить_имм рбикс, 5
|
||||
умножить рбикс
|
||||
переместить_имм раикс, 100
|
||||
переместить_имм рбикс, 7
|
||||
разделить рбикс
|
||||
умножить_знаковое рбикс
|
||||
разделить_знаковое рбикс
|
||||
сдвиг_влево раикс, 2
|
||||
сдвиг_вправо раикс, 2
|
||||
сдвиг_арифметический_вправо раикс, 2
|
||||
вращать_влево раикс, 2
|
||||
вращать_вправо раикс, 2
|
||||
переход метка_длинная
|
||||
короткий_переход метка_короткая
|
||||
цикл метка_короткая
|
||||
вызвать метка_длинная
|
||||
|
||||
метка_длинная:
|
||||
нет_операции
|
||||
нет_операции
|
||||
нет_операции
|
||||
|
||||
метка_короткая:
|
||||
нет_операции
|
||||
|
||||
переместить_имм раикс, 60
|
||||
переместить_имм рдикс, 0
|
||||
вызов_системы
|
||||
112
тесты/т1_.квс
112
тесты/т1_.квс
|
|
@ -1,112 +0,0 @@
|
|||
.глобал _start
|
||||
.текст
|
||||
|
||||
_start:
|
||||
; ===== ГРУППА 1: Без операндов (реализованные) =====
|
||||
нет_операции
|
||||
вызов_системы
|
||||
вернуться
|
||||
|
||||
; ===== ГРУППА 2: PUSH/POP =====
|
||||
втолкнуть раикс
|
||||
втолкнуть р8
|
||||
вытолкнуть раикс
|
||||
вытолкнуть р8
|
||||
|
||||
; ===== ГРУППА 3: Регистр-регистр =====
|
||||
переместить раикс, рбикс
|
||||
переместить р8, р9
|
||||
|
||||
сравнить раикс, рбикс
|
||||
сравнить р8, р9
|
||||
|
||||
проверить раикс, рбикс
|
||||
проверить р8, р9
|
||||
|
||||
прибавить раикс, рбикс
|
||||
прибавить р8, р9
|
||||
|
||||
вычесть раикс, рбикс
|
||||
вычесть р8, р9
|
||||
|
||||
и раикс, рбикс
|
||||
и р8, р9
|
||||
|
||||
или раикс, рбикс
|
||||
или р8, р9
|
||||
|
||||
исключающее_или раикс, рбикс
|
||||
исключающее_или р8, р9
|
||||
|
||||
; ===== ГРУППА 4: INC/DEC =====
|
||||
увеличить раикс
|
||||
увеличить р8
|
||||
увеличить еаикс
|
||||
|
||||
уменьшить раикс
|
||||
уменьшить р8
|
||||
уменьшить еаикс
|
||||
|
||||
; ===== ГРУППА 5: NOT/NEG =====
|
||||
инвертировать раикс
|
||||
инвертировать еаикс
|
||||
отрицать раикс
|
||||
отрицать еаикс
|
||||
|
||||
; ===== ГРУППА 6: MUL/DIV =====
|
||||
переместить_имм раикс, 10
|
||||
переместить_имм рбикс, 5
|
||||
умножить рбикс
|
||||
|
||||
переместить_имм раикс, 100
|
||||
переместить_имм рбикс, 7
|
||||
разделить рбикс
|
||||
|
||||
умножить_знаковое рбикс
|
||||
разделить_знаковое рбикс
|
||||
|
||||
; ===== ГРУППА 7: Битовые операции =====
|
||||
сдвиг_влево раикс, 2
|
||||
сдвиг_вправо раикс, 2
|
||||
сдвиг_арифметический_вправо раикс, 2
|
||||
вращать_влево раикс, 2
|
||||
вращать_вправо раикс, 2
|
||||
|
||||
; ===== ГРУППА 8: Переходы =====
|
||||
переход метка_длинная
|
||||
|
||||
переход_если_равно метка_длинная
|
||||
переход_если_неравно метка_длинная
|
||||
переход_если_меньше метка_длинная
|
||||
переход_если_больше метка_длинная
|
||||
переход_если_меньше_или_равно метка_длинная
|
||||
переход_если_больше_или_равно метка_длинная
|
||||
переход_если_перенос метка_длинная
|
||||
переход_если_нет_переноса метка_длинная
|
||||
|
||||
короткий_переход метка_короткая
|
||||
|
||||
короткий_переход_если_равно метка_короткая
|
||||
короткий_переход_если_неравно метка_короткая
|
||||
короткий_переход_если_меньше метка_короткая
|
||||
короткий_переход_если_больше метка_короткая
|
||||
короткий_переход_если_меньше_или_равно метка_короткая
|
||||
короткий_переход_если_больше_или_равно метка_короткая
|
||||
короткий_переход_если_перенос метка_короткая
|
||||
короткий_переход_если_нет_переноса метка_короткая
|
||||
|
||||
цикл метка_короткая
|
||||
вызвать метка_длинная
|
||||
|
||||
метка_длинная:
|
||||
нет_операции
|
||||
нет_операции
|
||||
нет_операции
|
||||
|
||||
метка_короткая:
|
||||
нет_операции
|
||||
|
||||
; Выход
|
||||
переместить_имм раикс, 60
|
||||
переместить_имм рдикс, 0
|
||||
вызов_системы
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
.текст
|
||||
.глобал _start
|
||||
|
||||
_start:
|
||||
; Счётчик циклов = 5
|
||||
переместить_имм р8, 5
|
||||
|
||||
цикл:
|
||||
; Выводим сообщение
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, msg
|
||||
переместить_имм рдикс, 21
|
||||
вызов_системы
|
||||
|
||||
; Счётчик--
|
||||
уменьшить р8
|
||||
сравнить_с р8, 0
|
||||
короткий_переход_если_неравно цикл
|
||||
|
||||
; exit(0)
|
||||
переместить_имм раикс, 60
|
||||
переместить_имм рдиай, 0
|
||||
вызов_системы
|
||||
|
||||
.данные
|
||||
msg: .строка "Привет мир!\n"
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
.текст
|
||||
.глобал _start
|
||||
|
||||
_start:
|
||||
переместить_имм р9, 1 ; счётчик = 1
|
||||
|
||||
цикл:
|
||||
; Выводим счётчик как цифру
|
||||
переместить раикс, р9
|
||||
прибавить_непосредственно раикс, 0x30
|
||||
сохранить [буфер], раикс
|
||||
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, буфер
|
||||
переместить_имм рдикс, 1
|
||||
вызов_системы
|
||||
|
||||
; Перевод строки
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, nl
|
||||
переместить_имм рдикс, 1
|
||||
вызов_системы
|
||||
|
||||
; Счётчик++
|
||||
увеличить р9
|
||||
сравнить_с р9, 7 ; до 7 (1..6)
|
||||
короткий_переход_если_неравно цикл
|
||||
|
||||
; exit(0)
|
||||
переместить_имм раикс, 60
|
||||
переместить_имм рдиай, 0
|
||||
вызов_системы
|
||||
|
||||
.данные
|
||||
буфер:
|
||||
.байт 0, 0, 0, 0, 0, 0, 0, 0
|
||||
nl:
|
||||
.байт 0x0A
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
.текст
|
||||
.глобал _start
|
||||
|
||||
_start:
|
||||
переместить_имм р9, 6 ; счётчик = 6
|
||||
|
||||
цикл:
|
||||
; Выводим счётчик как цифру
|
||||
переместить раикс, р9
|
||||
прибавить_непосредственно раикс, 0x30
|
||||
сохранить [буфер], раикс
|
||||
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, буфер
|
||||
переместить_имм рдикс, 1
|
||||
вызов_системы
|
||||
|
||||
; Перевод строки
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, nl
|
||||
переместить_имм рдикс, 1
|
||||
вызов_системы
|
||||
|
||||
; Счётчик--
|
||||
уменьшить р9
|
||||
сравнить_с р9, 0 ; до 0
|
||||
короткий_переход_если_неравно цикл
|
||||
|
||||
; exit(0)
|
||||
переместить_имм раикс, 60
|
||||
переместить_имм рдиай, 0
|
||||
вызов_системы
|
||||
|
||||
.данные
|
||||
буфер:
|
||||
.байт 0, 0, 0, 0, 0, 0, 0, 0
|
||||
nl:
|
||||
.байт 0x0A
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
.текст
|
||||
.глобал _start
|
||||
|
||||
_start:
|
||||
переместить_имм р8, 1 ; число = 1
|
||||
|
||||
цикл:
|
||||
; Выводим число
|
||||
переместить раикс, р8
|
||||
прибавить_непосредственно раикс, 0x30
|
||||
сохранить [буфер], раикс
|
||||
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, буфер
|
||||
переместить_имм рдикс, 1
|
||||
вызов_системы
|
||||
|
||||
; Перевод строки
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, nl
|
||||
переместить_имм рдикс, 1
|
||||
вызов_системы
|
||||
|
||||
; Умножаем на 2
|
||||
переместить раикс, р8
|
||||
переместить_имм р9, 2
|
||||
умножить р9
|
||||
переместить р8, раикс
|
||||
|
||||
; Продолжаем пока < 10
|
||||
сравнить_с р8, 10
|
||||
переход_если_меньше цикл ; длинный переход вместо короткого
|
||||
|
||||
; exit(0)
|
||||
переместить_имм раикс, 60
|
||||
переместить_имм рдиай, 0
|
||||
вызов_системы
|
||||
|
||||
.данные
|
||||
буфер:
|
||||
.байт 0, 0, 0, 0, 0, 0, 0, 0
|
||||
nl:
|
||||
.байт 0x0A
|
||||
|
|
@ -1,86 +0,0 @@
|
|||
.текст
|
||||
.глобал _start
|
||||
|
||||
_start:
|
||||
переместить_имм р8, 2 ; число = 2
|
||||
|
||||
цикл:
|
||||
; Если число < 10 — выводим как есть
|
||||
сравнить_с р8, 10
|
||||
переход_если_больше_или_равно двузначное
|
||||
|
||||
; Однозначное: просто цифра
|
||||
переместить раикс, р8
|
||||
прибавить_непосредственно раикс, 0x30
|
||||
сохранить [буфер], раикс
|
||||
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, буфер
|
||||
переместить_имм рдикс, 1
|
||||
вызов_системы
|
||||
|
||||
переход продолжение
|
||||
|
||||
двузначное:
|
||||
; Делим на 10
|
||||
переместить раикс, р8
|
||||
переместить_имм рдикс, 0
|
||||
переместить_имм рсикс, 10
|
||||
разделить рсикс ; rax = десятки, rdx = единицы
|
||||
|
||||
; Сохраняем единицы в .бнд (пока не испортились)
|
||||
сохранить [остаток], рдикс
|
||||
|
||||
; Выводим десятки
|
||||
прибавить_непосредственно раикс, 0x30
|
||||
сохранить [буфер], раикс
|
||||
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, буфер
|
||||
переместить_имм рдикс, 1
|
||||
вызов_системы
|
||||
|
||||
; Загружаем единицы обратно
|
||||
загрузить рдикс, [остаток]
|
||||
|
||||
; Выводим единицы
|
||||
прибавить_непосредственно рдикс, 0x30
|
||||
сохранить [буфер], рдикс
|
||||
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, буфер
|
||||
переместить_имм рдикс, 1
|
||||
вызов_системы
|
||||
|
||||
продолжение:
|
||||
; Перевод строки
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, nl
|
||||
переместить_имм рдикс, 1
|
||||
вызов_системы
|
||||
|
||||
; Прибавляем 2
|
||||
прибавить_непосредственно р8, 2
|
||||
|
||||
; Продолжаем пока <= 99
|
||||
сравнить_с р8, 99
|
||||
переход_если_меньше цикл
|
||||
|
||||
; exit(0)
|
||||
переместить_имм раикс, 60
|
||||
переместить_имм рдиай, 0
|
||||
вызов_системы
|
||||
|
||||
.данные
|
||||
буфер:
|
||||
.байт 0, 0, 0, 0, 0, 0, 0, 0
|
||||
nl:
|
||||
.байт 0x0A
|
||||
|
||||
.бнд
|
||||
остаток:
|
||||
.резб 8
|
||||
|
|
@ -1,81 +0,0 @@
|
|||
.текст
|
||||
.глобал _start
|
||||
|
||||
_start:
|
||||
; Тест: выводим длины чисел от 0 до 20
|
||||
переместить_имм р8, 0 ; число = 0
|
||||
|
||||
цикл:
|
||||
; Считаем длину числа
|
||||
переместить раикс, р8
|
||||
вызвать длина_числа
|
||||
|
||||
; Выводим длину как цифру
|
||||
прибавить_непосредственно раикс, 0x30
|
||||
сохранить [буфер], раикс
|
||||
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, буфер
|
||||
переместить_имм рдикс, 1
|
||||
вызов_системы
|
||||
|
||||
; Перевод строки
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, nl
|
||||
переместить_имм рдикс, 1
|
||||
вызов_системы
|
||||
|
||||
; Число++
|
||||
увеличить р8
|
||||
сравнить_с р8, 21 ; 0..20
|
||||
переход_если_меньше цикл
|
||||
|
||||
; exit(0)
|
||||
переместить_имм раикс, 60
|
||||
переместить_имм рдиай, 0
|
||||
вызов_системы
|
||||
|
||||
; =============================================
|
||||
; длина_числа: количество десятичных цифр в rax
|
||||
; Вход: rax = число
|
||||
; Выход: rax = количество цифр
|
||||
; =============================================
|
||||
длина_числа:
|
||||
втолкнуть р8
|
||||
втолкнуть р9
|
||||
|
||||
переместить р8, раикс ; р8 = число
|
||||
переместить_имм р9, 0 ; счётчик = 0
|
||||
|
||||
сравнить_с р8, 0
|
||||
короткий_переход_если_неравно длина_цикл
|
||||
|
||||
переместить_имм раикс, 1 ; 0 = 1 цифра
|
||||
вытолкнуть р9
|
||||
вытолкнуть р8
|
||||
вернуться
|
||||
|
||||
длина_цикл:
|
||||
увеличить р9
|
||||
|
||||
переместить раикс, р8
|
||||
переместить_имм рдикс, 0
|
||||
переместить_имм рсикс, 10
|
||||
разделить рсикс
|
||||
переместить р8, раикс
|
||||
|
||||
сравнить_с р8, 0
|
||||
короткий_переход_если_неравно длина_цикл
|
||||
|
||||
переместить раикс, р9
|
||||
вытолкнуть р9
|
||||
вытолкнуть р8
|
||||
вернуться
|
||||
|
||||
.данные
|
||||
буфер:
|
||||
.байт 0, 0, 0, 0, 0, 0, 0, 0
|
||||
nl:
|
||||
.байт 0x0A
|
||||
138
тесты/циклы7.квс
138
тесты/циклы7.квс
|
|
@ -1,138 +0,0 @@
|
|||
.текст
|
||||
.глобал _start
|
||||
|
||||
_start:
|
||||
переместить_имм р8, 0 ; число = 0
|
||||
|
||||
цикл:
|
||||
; Выводим число (костыльно: до 99)
|
||||
сравнить_с р8, 10
|
||||
переход_если_больше_или_равно двузначное
|
||||
|
||||
; Однозначное
|
||||
переместить раикс, р8
|
||||
прибавить_непосредственно раикс, 0x30
|
||||
сохранить [буфер], раикс
|
||||
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, буфер
|
||||
переместить_имм рдикс, 1
|
||||
вызов_системы
|
||||
|
||||
переход показать_длину
|
||||
|
||||
двузначное:
|
||||
; Делим на 10
|
||||
переместить раикс, р8
|
||||
переместить_имм рдикс, 0
|
||||
переместить_имм рсикс, 10
|
||||
разделить рсикс
|
||||
|
||||
сохранить [остаток], рдикс
|
||||
|
||||
; Десятки
|
||||
прибавить_непосредственно раикс, 0x30
|
||||
сохранить [буфер], раикс
|
||||
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, буфер
|
||||
переместить_имм рдикс, 1
|
||||
вызов_системы
|
||||
|
||||
; Единицы
|
||||
загрузить рдикс, [остаток]
|
||||
прибавить_непосредственно рдикс, 0x30
|
||||
сохранить [буфер], рдикс
|
||||
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, буфер
|
||||
переместить_имм рдикс, 1
|
||||
вызов_системы
|
||||
|
||||
показать_длину:
|
||||
; Разделитель: " -> "
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, стрелка
|
||||
переместить_имм рдикс, 4
|
||||
вызов_системы
|
||||
|
||||
; Длина числа
|
||||
переместить раикс, р8
|
||||
вызвать длина_числа
|
||||
|
||||
прибавить_непосредственно раикс, 0x30
|
||||
сохранить [буфер], раикс
|
||||
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, буфер
|
||||
переместить_имм рдикс, 1
|
||||
вызов_системы
|
||||
|
||||
; Перевод строки
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, nl
|
||||
переместить_имм рдикс, 1
|
||||
вызов_системы
|
||||
|
||||
; Число++
|
||||
увеличить р8
|
||||
сравнить_с р8, 9199
|
||||
переход_если_меньше цикл
|
||||
|
||||
; exit(0)
|
||||
переместить_имм раикс, 60
|
||||
переместить_имм рдиай, 0
|
||||
вызов_системы
|
||||
|
||||
; =============================================
|
||||
; длина_числа
|
||||
; =============================================
|
||||
длина_числа:
|
||||
втолкнуть р8
|
||||
втолкнуть р9
|
||||
|
||||
переместить р8, раикс
|
||||
переместить_имм р9, 0
|
||||
|
||||
сравнить_с р8, 0
|
||||
короткий_переход_если_неравно длина_цикл
|
||||
|
||||
переместить_имм раикс, 1
|
||||
вытолкнуть р9
|
||||
вытолкнуть р8
|
||||
вернуться
|
||||
|
||||
длина_цикл:
|
||||
увеличить р9
|
||||
|
||||
переместить раикс, р8
|
||||
переместить_имм рдикс, 0
|
||||
переместить_имм рсикс, 10
|
||||
разделить рсикс
|
||||
переместить р8, раикс
|
||||
|
||||
сравнить_с р8, 0
|
||||
короткий_переход_если_неравно длина_цикл
|
||||
|
||||
переместить раикс, р9
|
||||
вытолкнуть р9
|
||||
вытолкнуть р8
|
||||
вернуться
|
||||
|
||||
.данные
|
||||
буфер:
|
||||
.байт 0, 0, 0, 0, 0, 0, 0, 0
|
||||
стрелка:
|
||||
.строка " -> "
|
||||
nl:
|
||||
.байт 0x0A
|
||||
|
||||
.бнд
|
||||
остаток:
|
||||
.резб 8
|
||||
180
тесты/циклы8.квс
180
тесты/циклы8.квс
|
|
@ -1,180 +0,0 @@
|
|||
.текст
|
||||
.глобал _start
|
||||
|
||||
_start:
|
||||
; МЕНЯЙ ЧИСЛО ЗДЕСЬ:
|
||||
переместить_имм р8, 456777
|
||||
|
||||
; Выводим число через itoa3 (до 999!)
|
||||
переместить раикс, р8
|
||||
переместить_имм рдиай, буфер
|
||||
вызвать itoa3
|
||||
|
||||
загрузить рсиай, [указатель]
|
||||
загрузить рдикс, [длина]
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
вызов_системы
|
||||
|
||||
; " -> "
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, стрелка
|
||||
переместить_имм рдикс, 4
|
||||
вызов_системы
|
||||
|
||||
; Длина числа
|
||||
переместить раикс, р8
|
||||
вызвать длина_числа
|
||||
|
||||
; Выводим длину
|
||||
прибавить_непосредственно раикс, 0x30
|
||||
сохранить [буфер], раикс
|
||||
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, буфер
|
||||
переместить_имм рдикс, 1
|
||||
вызов_системы
|
||||
|
||||
; Перевод строки
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, nl
|
||||
переместить_имм рдикс, 1
|
||||
вызов_системы
|
||||
|
||||
; exit(0)
|
||||
переместить_имм раикс, 60
|
||||
переместить_имм рдиай, 0
|
||||
вызов_системы
|
||||
|
||||
; =============================================
|
||||
; itoa3 — работает для чисел до 999
|
||||
; =============================================
|
||||
itoa3:
|
||||
втолкнуть рбикс
|
||||
втолкнуть р8
|
||||
втолкнуть р9
|
||||
|
||||
переместить рбикс, рдиай
|
||||
переместить р8, раикс
|
||||
|
||||
сравнить_с р8, 10
|
||||
переход_если_меньше одна_цифра
|
||||
сравнить_с р8, 100
|
||||
переход_если_меньше две_цифры
|
||||
|
||||
; Три цифры
|
||||
прибавить_непосредственно рбикс, 3
|
||||
|
||||
переместить раикс, р8
|
||||
переместить_имм рдикс, 0
|
||||
переместить_имм р9, 10
|
||||
разделить р9
|
||||
прибавить_непосредственно рдикс, 0x30
|
||||
уменьшить рбикс
|
||||
сохранить [рбикс], рдикс
|
||||
|
||||
переместить р8, раикс
|
||||
переместить раикс, р8
|
||||
переместить_имм рдикс, 0
|
||||
разделить р9
|
||||
прибавить_непосредственно рдикс, 0x30
|
||||
уменьшить рбикс
|
||||
сохранить [рбикс], рдикс
|
||||
|
||||
прибавить_непосредственно раикс, 0x30
|
||||
уменьшить рбикс
|
||||
сохранить [рбикс], раикс
|
||||
|
||||
сохранить [указатель], рбикс
|
||||
переместить_имм раикс, 3
|
||||
сохранить [длина], раикс
|
||||
вытолкнуть р9
|
||||
вытолкнуть р8
|
||||
вытолкнуть рбикс
|
||||
вернуться
|
||||
|
||||
две_цифры:
|
||||
прибавить_непосредственно рбикс, 2
|
||||
|
||||
переместить раикс, р8
|
||||
переместить_имм рдикс, 0
|
||||
переместить_имм р9, 10
|
||||
разделить р9
|
||||
прибавить_непосредственно рдикс, 0x30
|
||||
уменьшить рбикс
|
||||
сохранить [рбикс], рдикс
|
||||
|
||||
прибавить_непосредственно раикс, 0x30
|
||||
уменьшить рбикс
|
||||
сохранить [рбикс], раикс
|
||||
|
||||
сохранить [указатель], рбикс
|
||||
переместить_имм раикс, 2
|
||||
сохранить [длина], раикс
|
||||
вытолкнуть р9
|
||||
вытолкнуть р8
|
||||
вытолкнуть рбикс
|
||||
вернуться
|
||||
|
||||
одна_цифра:
|
||||
прибавить_непосредственно раикс, 0x30
|
||||
сохранить [рбикс], раикс
|
||||
сохранить [указатель], рбикс
|
||||
переместить_имм раикс, 1
|
||||
сохранить [длина], раикс
|
||||
вытолкнуть р9
|
||||
вытолкнуть р8
|
||||
вытолкнуть рбикс
|
||||
вернуться
|
||||
|
||||
; =============================================
|
||||
; длина_числа
|
||||
; =============================================
|
||||
длина_числа:
|
||||
втолкнуть р8
|
||||
втолкнуть р9
|
||||
|
||||
переместить р8, раикс
|
||||
переместить_имм р9, 0
|
||||
|
||||
сравнить_с р8, 0
|
||||
короткий_переход_если_неравно длина_цикл
|
||||
|
||||
переместить_имм раикс, 1
|
||||
вытолкнуть р9
|
||||
вытолкнуть р8
|
||||
вернуться
|
||||
|
||||
длина_цикл:
|
||||
увеличить р9
|
||||
|
||||
переместить раикс, р8
|
||||
переместить_имм рдикс, 0
|
||||
переместить_имм рсикс, 10
|
||||
разделить рсикс
|
||||
переместить р8, раикс
|
||||
|
||||
сравнить_с р8, 0
|
||||
короткий_переход_если_неравно длина_цикл
|
||||
|
||||
переместить раикс, р9
|
||||
вытолкнуть р9
|
||||
вытолкнуть р8
|
||||
вернуться
|
||||
|
||||
.данные
|
||||
буфер:
|
||||
.байт 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
стрелка:
|
||||
.строка " -> "
|
||||
nl:
|
||||
.байт 0x0A
|
||||
|
||||
.бнд
|
||||
указатель:
|
||||
.резб 8
|
||||
длина:
|
||||
.резб 8
|
||||
|
|
@ -1,77 +0,0 @@
|
|||
.текст
|
||||
.глобал _start
|
||||
|
||||
_start:
|
||||
; МЕНЯЙ ЧИСЛО:
|
||||
переместить_имм р8, 750
|
||||
|
||||
; Выводим число (костыльно: делим на 100, потом на 10)
|
||||
сравнить_с р8, 100
|
||||
переход_если_меньше меньше_100
|
||||
|
||||
; >= 100: делим на 100
|
||||
переместить раикс, р8
|
||||
переместить_имм рдикс, 0
|
||||
переместить_имм рсикс, 100
|
||||
разделить рсикс ; rax = сотни, rdx = остаток
|
||||
|
||||
; Выводим сотни
|
||||
прибавить_непосредственно раикс, 0x30
|
||||
сохранить [буфер], раикс
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, буфер
|
||||
переместить_имм рдикс, 1
|
||||
вызов_системы
|
||||
|
||||
; Остаток — продолжаем
|
||||
переместить р8, рдикс
|
||||
|
||||
меньше_100:
|
||||
; Делим на 10
|
||||
сравнить_с р8, 10
|
||||
переход_если_меньше меньше_10
|
||||
|
||||
переместить раикс, р8
|
||||
переместить_имм рдикс, 0
|
||||
переместить_имм рсикс, 10
|
||||
разделить рсикс
|
||||
|
||||
; Выводим десятки
|
||||
прибавить_непосредственно раикс, 0x30
|
||||
сохранить [буфер], раикс
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, буфер
|
||||
переместить_имм рдикс, 1
|
||||
вызов_системы
|
||||
|
||||
переместить р8, рдикс
|
||||
|
||||
меньше_10:
|
||||
; Выводим единицы
|
||||
прибавить_непосредственно р8, 0x30
|
||||
сохранить [буфер], р8
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, буфер
|
||||
переместить_имм рдикс, 1
|
||||
вызов_системы
|
||||
|
||||
; Перевод строки
|
||||
переместить_имм раикс, 1
|
||||
переместить_имм рдиай, 1
|
||||
переместить_имм рсиай, nl
|
||||
переместить_имм рдикс, 1
|
||||
вызов_системы
|
||||
|
||||
; exit(0)
|
||||
переместить_имм раикс, 60
|
||||
переместить_имм рдиай, 0
|
||||
вызов_системы
|
||||
|
||||
.данные
|
||||
буфер:
|
||||
.байт 0, 0, 0, 0, 0, 0, 0, 0
|
||||
nl:
|
||||
.байт 0x0A
|
||||
Loading…
Reference in a new issue