check_bank_calls: ловить адрес ПОЛЯ структуры в аргументах банкового вызова

Проверка 2 искала форму «адрес метки своего банка положен в аргументы вызова в
чужой банк», но регулярка принимала только `ld hl,#_метка` и `#_метка+6`. Адрес
поля структуры SDCC пишет в скобках:

	ld	bc, #(_mstream + 6)
	push	bc
	...
	call	___sdcc_bcall_ehl

Из-за этого целый класс ошибок собирался «чисто». Поймано вживую 2026-09-03 в
порту Loom: mask.c (банк 5, --bank-data 5) отдавал res_copy (банк 11) адрес поля
своей структуры — поток маски читался в чужую страницу, маска выходила «всё
заполнено», тайлов в комнате стало 30 вместо 17. Фон при этом оставался
побайтово верным, потому что его путь идёт из резидентного кода, так что
попиксельная сверка экрана молчала.

Класс проверки не меняется: адрес метки ДАННЫХ своего банка, положенный в стек
как аргумент вызова в ЧУЖОЙ банк, неверен всегда — это по-прежнему
доказательный случай, а не эвристика.

Проверено в трёх режимах: с ошибкой срабатывает, на исправленном коде молчит, и
на всех банковых сборках самого тулчейна (banktest, w3probe, banked, bankedbg,
banklocl, w3bankgfx, roomtest, сборка SprPoP) ложных срабатываний нет.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qxu9rwsmyDyYPxG198nzSR
This commit is contained in:
2026-09-03 11:04:27 +03:00
parent 25abf8ea36
commit 05bcd8197e
+8 -2
View File
@@ -72,9 +72,15 @@ BANK_ASM_RE = re.compile(r'^bank(\d+)_')
IGNORE = {'___sdcc_bcall_ehl', '___sdcc_bcall'}
# `ld hl,#_метка` / `ld de,#___str_3` — материализация адреса.
#
# Скобочную форму принимаем обязательно: адрес ПОЛЯ структуры SDCC пишет как
# `ld bc, #(_mstream + 6)`, и без неё проверка молча пропускала целый класс.
# Поймано вживую 2026-09-03 в порту Loom: `mask.c` (банк 5, --bank-data 5)
# отдавал `res_copy` (банк 11) адрес поля своей структуры — маска читалась как
# «всё заполнено», а сборка при этом была «чистой».
LOADADDR_RE = re.compile(
r'^\s*ld\s+(hl|de|bc|iy|ix)\s*,\s*#(_{1,3}[A-Za-z_0-9]+)'
r'(?:\s*[+-]\s*\w+)?\s*(?:;.*)?$', re.IGNORECASE)
r'^\s*ld\s+(hl|de|bc|iy|ix)\s*,\s*#\(?\s*(_{1,3}[A-Za-z_0-9]+)'
r'(?:\s*[+-]\s*[\w()+\- ]+?)?\s*\)?\s*(?:;.*)?$', re.IGNORECASE)
PUSH_RE = re.compile(r'^\s*push\s+(hl|de|bc|iy|ix)\s*(?:;.*)?$',
re.IGNORECASE)
# `ld e,#b_foo` перед трамплином называет банк цели.