Вызов API функций. Достоинства и недостатки...
Новый метод вызова API.
Относится к версии SPF 3.75 (build 089).
Как организуется вызов API-функций в Форте?
Если посмотреть spf_win_api.f, процедуры вызова API-CALL, _WNDPROC-CODE,
то механизм вызова следующий:
Анализ механизма API-CALL:
1) Сохраняем переменные Форт окружения:
PUSH ESI
PUSH EDI
PUSH EBP
2) Выделяем область данных для вызова API:
SUB ESP, # 60
MOV EDI, ESP
MOV ESI, EBP
MOV ECX, # 15
CLD
REP MOVS DWORD
MOV EBP, ESP
Причем полагаем, что передаем в вызывающую процедуру
не более 15 параметров...
3) Вызываем процедуру
POP EAX \ адрес вызываемой процедуры лежал на верхушке стека данных Форта
CALL EAX
4) Восстанавливаем стек возврата и переменные:
MOV EBX, EBP
SUB EBX, ESP
MOV ESP, EBP
ADD ESP, # 60
POP EBP
SUB EBP, EBX
SUB EBP, # 4
MOV [EBP], EAX
POP EDI
POP ESI
Next
Анализ механизма _WNDPROC-CODE:
1) выделяет в области стека блок данных для стека возвратов:
MOV EBP, ESP
SUB ESP, # #ST-RES
2) Фомируется ссылка на адрес возврата
PUSH EBP
MOV EBP, 4 [EAX] ( адрес возврата из CALLBACK )
3) Находится слово для вызова и оно вызывается...
MOV EAX, [EAX] ( адрес адреса форт-процедуры )
MOV EAX, [EAX]
...
CALL EAX
...
4) Стек восстанавливается к исходному варианту и возврат:
MOV ESP, EBP
MOV EBP, 4 [EAX] \ сохраненный EBP
MOV EAX, [EAX] \ адрес возврата из CALLBACK
XCHG EAX, [ESP]
RET
В итоге получаем следующее
Организация памяти:
Стек:
Windows параметры
...
Стек данных (арифметический стек)
<-- вершина стека
...
резерв
Стек возвратов
адрес вовзрата
<-- вершина стека возвратов
...
...
Достоинства:
1) вызов получается простым;
2) на вершине передаваемые параметры;
3) на вершине стека всегда код возврата.
Недостатки:
1) при каждом вызове API-функции приходится копировать параметры.
Это очень долго. Некоторые функции, предоставляемые Windows становятся
не эффективными (например UpperCase).
(решение: нет)
2) Если в какой-либо DLL у одной из функций параметров окажется больше 15,
то такая функция будет работать не верно, и
(решение:) для исправления этой ситуации придется увеличивать кол-во передаваемых
параметров, что существенно увеличит время на вызов ВСЕХ функций Windows.
3) Если я захочу оставить очень большое N чисел в стеке данных, это дело
затрет адрес возврата из процедуры (например передача списком до нуля
каких-нибудь данных).
(решение: установить {#ST-RES} достаточно большим).
Для решения недостатков предлагаю поменять механизм интеграции Форт'а:
Карта памяти:
Стек:
Windows параметры
адрес вовзрата
Стек возвратов
<-- вершина стека возвратов
...
резерв
Стек данных (арифметический стек)
<-- вершина стека
...
...
; Процедура входа в Форт _WNDPROC-CODE_Enter:
pop eax ; адрес адреса вызова слова
push ebp
push esi
push edi
lea ebp, [esp-{#ST-RES}] ; выделяем память под стек возвратов
; и устанавливаем указатель на вершину стека данных
push ebp ; Указатель на вершину стека данных
lea esi, [esp+16]
mov edi, ebp
push 5 ; переносим 5 параметров, навряд ли будет больше 4!!!
; можно увеличить кол-во, все равно делается 1 раз при входе...
pop ecx
rep movsd
call dword ptr [eax]
; Процедура выхода из Форта
mov eax, [ebp] ; возвращаемое значение из стека
pop ebx ; было ebp
sub ebx, ebp ; убрать n байт со стека (отрицательное)
pop edi
pop esi
pop ebp
pop edx ; адрес возврата
sub esp, ebx
jmp edx
Вызов API:
push esi, edi, ... ; еще все что угодно
swap esp, ebp
pop eax ; адрес переменной WINAPI:
call dwp [eax]
push eax ; возвращаем результат
swap esp, ebp
pop ... edi, esi
ret
Достоинства:
1) вызов остается простым;
2) на вершине стека всегда код возврата;
3) вызов значительно быстрее;
4) вызванная процедура может как угодно использовать стек вниз;
5) невозможно отлаживать прогу стандартными отладчиками (затирают стек данных).
Недостатки:
1) невозможно отлаживать прогу стандартными отладчиками - затирают стек данных
(решение: а может пусть так и будет - полезно?).
2) на вершине 5 передаваемых параметров
(решение: их кол-во можно увеличить или ввести дополнительное слово,
возвращающее адрес вершины параметров);
3) уровень вложенности процедур не может быть больше ~{#ST-RES}/4
(решение: установить {#ST-RES} достаточно большим).
Остается непонятным, как Windows организует управление стеком при вызове новых
callback функций (например CALLBACK WindowProc)?
По идее это должно быть что-то типа NewStack:=ESP-Очень_Большое_N, а
может даже создание нового стека в CreateThread????????
В любом случае надо бы все это попробовать, потестировать...
Голосуйте...
P.S. Если чего-то не учел,то VVVVVVVVVVVVV
Гневные пожелания и не очень жду по e-mail: winforth@narod.ru(Ежу)