в разное время патчи, которым нужно хранить свои данные, получали память разными способами 1) от балды. разработчики/портеры сохраняли дамп озу, находили там "свободную" память и использовали её. естественно, это вызывало разнообразные глюки. 2) в чужом объекте BOOK, конкретно в standby. при инициализации буки под неё выделялось больше памяти, туда клался указатель на свои данные. 3) printbuffer (примеры: тотальная смена графики и эльфпак) и heapshift. тут всё просто, адрес/длину некого статического объекта достаточно большого размера меняют, в свободное место кладут свои данные.
про первый способ и говорить нечего, наличие глюков зависит от везения. использовать второй имеет смысл только, если есть какой-то патч, функция из которого используется другими патчами (что-то вроде API от Joker XT), иначе патчи будут просто конфликтовать друг с другом. патча такого, естественно, нет. минусы третьего способа - необходимость установки соответствующего патча, возможные конфликты и необходимость вести учёт занятого места в озу.
я предлагаю забыть про heapshift и использовать другой способ. этот способ, кстати, будет использоваться в эльфпаке (уже используется в тестовой версии).
плюсы: - отсутствие конфликтов (на самом деле это условно, но очень легко использовать уникальное имя переменной для каждого патча. если лень придумывать имя, можно использовать текстовое представление адреса из самого патча, это легко сделать макросом, но портерам нужно знать об этом нюансе) - отсутствие необходимости установки дополнительных патчей
минусы: - чуть сложней использовать - могут быть проблемы, если разные куски патча выполняются в разных процессах/блоках и требуют обращения к одним и тем же данным (очень редкий случай)
теперь суть. хранить данные или указатель на блок данных можно в переменных системного окружения. есть две функции для установки таких переменных и три функции для чтения get_env get_env_list get_envp (описание в вики) set_env set_envp (описание в вики) для тех, кто не знает, что такое переменные системного окружения, вот ссылочка http://ru.wikipedia.org/wiki/Переменные_окружения get_env, get_env_list и set_env работают с текстовыми значениями. но нам интересны get_envp и set_envp, они позволяют использовать значения любого формата. эти функци читают/устанавливают не сами переменные, а указатели на данные. поэтому если у вас используются до 4 байт своих данных, можно их класть в переменные напрямую, а если больше, то выделять память и сохранять в переменных указатель на этот блок памяти. в моём примере использовалось 8 байт данных.
Код:
; читаем указатель, если он существует mov r0,0 adr r1,envname bl get_envp add r4,r0,0 bne .exists ;переход, если данные существуют
; не существует - создаём ; выделяем память mov r0,0 push {r0} push {r0} mov r1,8 ; выделяется 8 байт mov r2,1 mov r3,5 bl memalloc mov r4,r0 add sp,sp,8
; записываем адрес в переменную окружения mov r2,r4 adr r1,envname mov r0,0 bl set_envp
;инициализация данных по адресу R4 ...
.exists: ;работа с нашими данными, лежащими по R4
...
;имя нашей переменной envname: db "superpatch_v1_memorypointer"
если лень придумывать название переменной, можно воспользоваться например таким макросом
Код:
macro stradr { address = $ rept 8 \{ tmp = (address shr 28) and 15 if tmp>9 tmp = tmp + 'A'-10 else tmp = tmp + '0' end if db tmp address = address shl 4 \} db 0 ; конец строки }
а в нужном месте вместо строки поставить его вызов Код:
;имя нашей переменной envname: stradr
в результате в патче по адресу envname будет помещёна текстовая строка со значением envname в hex виде.
Вы не можете начинать темы. Вы не можете редактировать свои сообщения. Вы не можете создавать опросы. Вы не можете вкладывать файлы в сообщения. Вы не можете отвечать на сообщения. Вы не можете удалять свои сообщения. Вы не можете голосовать.