Откат bank-data для pop_trob: указатель на его статику уходил наружу
Симптом: через несколько комнат живого прохода перезагружался DSS. pop_trob_modif() возвращает указатель на room_modif[24][30], а зовут её из банков 2, 3, 7 и резидента. После переноса массив лежит по 0xC000+ в странице банка 6, но разыменовывает указатель ЧУЖОЙ код — когда замаплена его собственная страница. Значит чтение и запись идут поверх кода соседнего банка. Анализ Def/Ref такое не ловит: снаружи нет ссылки на символ, есть ссылка на функцию, которая отдаёт его адрес. Условий для кандидата два, и второе проверяется только чтением кода — ни один указатель на статику не должен уходить наружу. pop_room оба условия проходит (_mobs не читает никто; bake_copy статическая; atlas_load(&pop_env[i]) берёт адрес глобала из резидентного pop_tile.c). Остаётся −1620 Б: данные в W2 6774 -> 5157, свободно 129 -> 1746 Б. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -42,19 +42,45 @@ re.match(r'A\s+(\S+)\s+size\s+([0-9A-Fa-f]+)\s+flags', line)
|
|||||||
глобал, который читает соседний банк или резидент, обязан остаться
|
глобал, который читает соседний банк или резидент, обязан остаться
|
||||||
замапленным всегда, иначе чтение придёт из чужой страницы.
|
замапленным всегда, иначе чтение придёт из чужой страницы.
|
||||||
|
|
||||||
Включено для `pop_room.c` и `pop_trob.c` — единственных модулей, у которых
|
Включено для `pop_room.c`. Результат:
|
||||||
НИ ОДИН символ не Ref снаружи. Результат:
|
|
||||||
|
|
||||||
| | было | стало |
|
| | было | стало |
|
||||||
|---|---:|---:|
|
|---|---:|---:|
|
||||||
| данные в W2 | 6774 | **4228** |
|
| данные в W2 | 6774 | **5157** |
|
||||||
| свободно до стека | 129 | **2675** |
|
| свободно до стека | 129 | **1746** |
|
||||||
| BANK6 | 4199 | 5128 (31 %) |
|
|
||||||
| BANK7 | 12684 | 14301 (87 %) |
|
| BANK7 | 12684 | 14301 (87 %) |
|
||||||
|
|
||||||
**Проверено в MAME**: уровень 1, комнаты 1 и 2 — фон, факелы, решётки,
|
**Проверено в MAME**: уровень 1, комнаты 1 и 2 — фон, факелы, решётки,
|
||||||
проваливающиеся полы и переход между комнатами работают.
|
проваливающиеся полы и переход между комнатами работают.
|
||||||
|
|
||||||
|
## ГЛАВНАЯ ЛОВУШКА: указатель на банковую статику
|
||||||
|
|
||||||
|
Первый заход включал ещё и `pop_trob.c` — по Def/Ref он выглядел ИДЕАЛЬНЫМ
|
||||||
|
кандидатом (экспортируемых данных нет вообще). Через несколько комнат
|
||||||
|
живого прохода **перезагрузился DSS**.
|
||||||
|
|
||||||
|
Причина: `pop_trob_modif()` ВОЗВРАЩАЕТ УКАЗАТЕЛЬ на `room_modif[24][30]`, а
|
||||||
|
зовут её из банков 2, 3, 7 и резидента. После переноса массив лежит по
|
||||||
|
0xC000+ в странице банка 6, но разыменовывает указатель чужой код — когда
|
||||||
|
замаплена ЕГО страница. То есть чтение и запись идут по тем же смещениям
|
||||||
|
поверх кода соседнего банка. Отсюда и уход системы.
|
||||||
|
|
||||||
|
**Анализ Def/Ref этого не видит**: снаружи нет ссылки на символ, есть
|
||||||
|
ссылка на функцию, которая отдаёт его адрес. Поэтому условий для
|
||||||
|
кандидата ДВА, и второе проверяется только чтением кода:
|
||||||
|
|
||||||
|
1. ни один чужой модуль не Ref его глобалы (по `.rel`);
|
||||||
|
2. **ни один указатель на его статику не уходит наружу** — ни возвратом, ни
|
||||||
|
через out-параметр, ни записью в общий глобал.
|
||||||
|
|
||||||
|
У `pop_room` второе выполнено: единственные `&`-выражения наружу —
|
||||||
|
`atlas_load(&pop_env[i])`, но `pop_env` определён в `pop_tile.c`, то есть в
|
||||||
|
резиденте; `bake_copy` статическая.
|
||||||
|
|
||||||
|
Внутри своей страницы указатель безопасен всегда: любой вызов резидентной
|
||||||
|
функции, которая перемапливает W3 (`atlas_load`, `pop_page_read`),
|
||||||
|
восстанавливает окно перед возвратом.
|
||||||
|
|
||||||
### Два условия, без которых это молча ломается
|
### Два условия, без которых это молча ломается
|
||||||
|
|
||||||
1. **Нулевая инициализация.** crt0 зануляет только резидентный `_DATA`, до
|
1. **Нулевая инициализация.** crt0 зануляет только резидентный `_DATA`, до
|
||||||
|
|||||||
@@ -35,14 +35,21 @@ MEMORY ?= huge # small-раскладка + банки кода в W
|
|||||||
# ВАЖНО: любое сравнение занятости банков имеет смысл только при ОДНОМ и том
|
# ВАЖНО: любое сравнение занятости банков имеет смысл только при ОДНОМ и том
|
||||||
# же ALLOCS — иначе сравниваются не правки, а уровни оптимизации.
|
# же ALLOCS — иначе сравниваются не правки, а уровни оптимизации.
|
||||||
ALLOCS ?= 3000
|
ALLOCS ?= 3000
|
||||||
# Писучие данные ЭТИХ банковых модулей живут в их же странице, а не в
|
# Писучие данные ЭТОГО банкового модуля живут в его же странице, а не в
|
||||||
# резиденте W1/W2 — это 2549 Б, которые иначе съедала бы база. Список
|
# резиденте W1/W2 (−1620 Б базы). Список из одного файла — не лень, а
|
||||||
# короткий не по лени: у остальных банковых модулей часть глобалов читают
|
# результат проверки; ДВА условия, и второе стоило перезагрузки DSS:
|
||||||
# соседние банки и резидент (hitp_*, pop_upside, pop_loose_modif, pop_cd),
|
#
|
||||||
# и такие данные ОБЯЗАНЫ остаться замапленными всегда. Проверять новичка в
|
# 1) ни один чужой модуль не ссылается на его глобалы (проверяется по
|
||||||
# списке — по объектным файлам: символ должен быть Def только в своём .rel и
|
# .rel: символ Def только в своём объекте и нигде не Ref);
|
||||||
# нигде не Ref (см. ../docs/resident_budget.md).
|
# 2) НИ ОДИН УКАЗАТЕЛЬ на его статику не уходит наружу. Def/Ref этого не
|
||||||
BANK_DATA := --bank-data=pop_room.c --bank-data=pop_trob.c
|
# видит. Так провалился pop_trob: pop_trob_modif() возвращает указатель
|
||||||
|
# на room_modif[24][30], и его разыменовывают банки 2/3/7 и резидент —
|
||||||
|
# то есть пишут по 0xC000+ в СВОЮ страницу, поверх чужого кода.
|
||||||
|
#
|
||||||
|
# У pop_room оба условия выполнены: _mobs не читает никто, bake_copy
|
||||||
|
# статическая, а atlas_load(&pop_env[i]) берёт адрес глобала из pop_tile.c
|
||||||
|
# (резидент), не своего. Подробности — ../docs/resident_budget.md.
|
||||||
|
BANK_DATA := --bank-data=pop_room.c
|
||||||
|
|
||||||
EXTRA_FLAGS ?= --gfx 256 -I $(CURDIR)/../poc/res/bg --max-allocs $(ALLOCS) --bank 2=pop_bg.c --bank 7=pop_room.c --bank 4=pop_cdraw.c --bank 4=pop_kdraw.c --bank 3=pop_map.c --bank 1=guards.c --bank 5=pop_ctrl.c --bank 6=pop_trob.c --bank 7=pop_redraw.c --bank 8=roomtest_cold.c --bank 8=pop_level_cold.c --bank 8=pop_kboot.c --bank 8=pop_guard_cold.c --bank 8=pop_shadow.c --bank 8=pop_sfx_cold.c $(BANK_DATA) $(PROF_FLAGS)
|
EXTRA_FLAGS ?= --gfx 256 -I $(CURDIR)/../poc/res/bg --max-allocs $(ALLOCS) --bank 2=pop_bg.c --bank 7=pop_room.c --bank 4=pop_cdraw.c --bank 4=pop_kdraw.c --bank 3=pop_map.c --bank 1=guards.c --bank 5=pop_ctrl.c --bank 6=pop_trob.c --bank 7=pop_redraw.c --bank 8=roomtest_cold.c --bank 8=pop_level_cold.c --bank 8=pop_kboot.c --bank 8=pop_guard_cold.c --bank 8=pop_shadow.c --bank 8=pop_sfx_cold.c $(BANK_DATA) $(PROF_FLAGS)
|
||||||
# Профилирование полосами бордюра (см. PROF() в roomtest.c) — ВКЛЮЧЕНО по
|
# Профилирование полосами бордюра (см. PROF() в roomtest.c) — ВКЛЮЧЕНО по
|
||||||
|
|||||||
Reference in New Issue
Block a user