gudleifr писал(а):
Проблема только в непонимании простоты процесса.
я представляю процесс
а вот как обойти проблему без переделывания кода винды не представляю, увы.
gudleifr писал(а):
Работа коллбэка отличается
для меня в первую очередь тем, что Си вызывает Форт, и Си не сохраняет необходимые мне регистры-указатели на пользовательскую область памяти, вершины стеков и начала стеков. Из-за этого приходится городить воот-такой код:
Код:
\ поддержка callback вызовов
\ Ф-ция не снимает со стека параметры!!! то есть Си-ное соглашение вызова
util/ envir.fts
os/ import.fts
vocs/ vocadd.fts
ALSO IMPORT
WINAPI: GlobalAlloc KERNEL32.DLL
WINAPI: GlobalFree KERNEL32.DLL
WINAPI: SetLastError KERNEL32.DLL
WINAPI: SetLastError KERNEL32.DLL
ALSO ENVIRONMENT \ нужно знать настройки системы
ALSO HIDDEN DEFINITIONS
\ выход из callback
\ в случае возникновения ошибки попадаем сюда же
: (BACK) ( --> )
[ \ 0xCD B, 0x03 B, \ INT3 только для отладки
\! сначала восстанавливается указатель стека возвратов
0x64 B, 0x8B B, 0x25 B, 0 , \ MOV ESP , FS:[0]
\! вернуть верхнее значение со стека данных в EAX
0x89 B, 0x44 B, 0x24 B, 48 B, \ MOV [ESP][16], EAX
\! вернуть старый обработчик исключений на место
0x64 B, 0x8F B, 0x05 B, 0 , \ POP d,FS:[0]
0x58 B, \ POP EAX = drop
\! память уже выделена?
0x64 B, 0xA1 B, 8 , \ MOV EAX , FS:[8]
0x0B B, 0xC0 B, \ OR EAX, EAX \ если пусто
0x0F B, 0x84 B, 9 , \ jz skipFree \ если память не выделялась
\! освободить память!
0x50 B, \ PUSH EAX
0xA1 B, Origin GlobalFree , \ free memory
0xFF B, 0xD0 B, \ CALL EAX \ GlobalFree
\! метка $skipFree
\! восстановление регистров и переменных
0x64 B, 0x8F B, 0x05 B, 0xE10 , \ POP d,FS[E10]
0x64 B, 0x8F B, 0x05 B, 8 , \ POP d,FS[8]
0x64 B, 0x8F B, 0x05 B, 4 , \ POP d,FS[4]
0x61 B, \ POPAD
0x8D B, 0x64 B, 0x24 B, 0x04 B, \ LEA ESP, [ESP][-4] = drop
] ; unfeasible
\ вход в callback
: (CALLBACK) ( --> addr )
[ \ 0xCD B, 0x03 B, \ INT3 только для отладки
\! сохранение регистров и важных переменных
0x60 B, \ PUSHAD \ все регистры сохранили
0x64 B, 0xFF B, 0x35 B, 4 , \ PUSH d,FS:[4]
0x64 B, 0xFF B, 0x35 B, 8 , \ PUSH d,FS:[8]
0x64 B, 0xC7 B, 0x05 B, 8 , 0 , \ MOV fs:[8], 0
0x64 B, 0xFF B, 0x35 B, 0xE10 , \ PUSH tls
\! дальше надо установить собственный обработчик исключений
0x64 B, 0xA1 B, 0 , \ MOV EAX , FS:[0]
0x68 B, ' (BACK) , \ PUSH CbError
0x50 B, \ PUSH EAX
0x64 B, 0x89 B, 0x25 B, 0 , \ MOV FS:[0] , ESP
\! дальше надо выделить память под стеки и пользовательскую область
0xA1 B, Origin GlobalAlloc ,
0xFF B, 0x35 B, IMAGE-BASE 0xE0 + , \ PUSH [StackSize]
0x68 B, 0x0040 , \ PUSH GMEM_ZEROINIT
0xFF B, 0xD0 B, \ CALL EAX \ выделить память для стеков
0x0B B, 0xC0 B, \ OR EAX, EAX \ если ошибка
0x0F B, 0x84 B, ' (BACK) atod , \ JZ CbError \ переход на обработчик
\! | .. <rstack| <dstack| <lstack|1024| user> |
0x64 B, 0xA3 B, 8 , \ MOV fs:[8], EAX \ новый указатель начала стека
0x03 B, 0x05 B, IMAGE-BASE 0xE0 + , \ ADD EAX, [IMAGE-BASE+0xE0]
0x64 B, 0xA3 B, 4 , \ MOV fs:[8], EAX \ новый указатель конца стековой области
\! дальше размещаются стеки и пользовательская область
\! <return| <data| <local|1024|user|H
0x8B B, 0xF8 B, \ MOV tls , EAX
0x2B B, 0x3D B, FROM TLS# , \ SUB tls , [ TLS# ]
0x64 B, 0x89 B, 0x3D B, 0xE10 , \ MOV fs:[E10], tls
0x8D B, 0x87 B, -1024 , \ LEA EAX, [tls][-1024] \ user area
0x8B B, 0xF0 B, \ MOV ltop , EAX \ local stack
0x8B B, 0xEE B, \ MOV TOP , ltop \ ESI>EBP
0x81 B, 0xED B, LocalStack# , \ SUB top , LocalStack#
0x8B B, 0xE5 B, \ MOV rtop, top
0x81 B, 0xEC B, DataStack# , \ SUB rtop , # DataStack#
\! вытащить адрес перехода на ф-цию за (call)
0x68 B, ' (BACK) , \ PUSH ' (BACK) \ для любителей делать EXIT
0x64 B, 0xA1 B, 0 , \ MOV EAX , FS:[0]
0xFF B, 0x70 B, 52 B, \ PUSH d,[EAX+0x34] \ адрес кода за скомпилированным (CALL)
0xFF B, 0x70 B, 32 B, \ PUSH d,[EAX+0x20] \ ESP
]
SP@ S0 !
LP@ L0 !
R>
RP@ R0 !
['] (~EXC) IS <EXC-DUMP> \ если надо получать сообщения об исключениях
prefer @ BASE ! \ без этого не будет форматного преобразования
ISO> INPUT-STREAM \ \-\-\ и нормальной работы со строками
['] (BACK) err-handler ! \ установка обработчика ошибок
8 + \ смещение в начало фрейма данных
R> CATCH SetLastError DROP \ ловля возможных форт-исключений
(BACK) \ автоматом выход из callback
; unfeasible
ALSO FORTH THIS
\ начать определение callback функции
\ определение завершается обычным образом, то есть ';'
: CB: ( / name --> ) :> COMPILE (CALLBACK) ;
RECENT RECENT RECENT