Собственно, написал я функцию. Она использует переменное число аргументов и ей явно передается их число. Но во-первых, это не удобно; а во вторых, для совместимости с предыдущей реализацией я к ней сделал переходник (т.е заменил код в старой реализации на заглушку и вызов новой): Код (Text): sctx_str proc C mem1:DWORD,mem2:DWORD,argum:VARARG ... xor eax, eax mov ecx, [ebp+4] ;адрес возврата ret or edx, -1 mov eax, [ecx] ; mov ebx, [ecx+2] cmp al, 81h ;81C4xxxxxxxx или 81ECxxxxxxxx jz @@1 and ebx, 0FFh and edx, 0FFh cmp al, 83h ;83C4xx или 83ECxx clc jnz @@100 ; @@1: cmp ah, 0C4h ;add jz @@2 xor ebx, edx inc ebx cmp ah, 0ECh ;sub clc jnz @@100 ; @@2: sub ebx, 2*4 ;это mem1 и mem2 clc js @@100 ... который определяет по коду, следующему за call'ом (add esp, xx) сколько параметров было передано через стек. Хороший ли это вариант? На masm'е все ок, как генерит код fasm? И C++ и Delphi? Нет ли там мусора между call и add esp, xxx ? В принципе, это скриптовый язык для разбора текстов, и мож я его скрещу с дизассемблером, но пока я к этому не готов морально
> C++ и Delphi? Нет ли там мусора между call и add esp, xxx Есть =) По крайней мере современные С++ компиляторы запросто могут слить несколько add esp, xxx после нескольких вызовов функций в один и зызвать его один раз.
а ещё может быть sub esp, вместо add или даже leave\mov esp, ebp так что универсального подхода для подсчёта аргументов cdecl imho нет, даже если считать push'и перед call, всё равно может не работать... для ф-ций типа printf можно вычислять кол-во аргументов по строке-формату. вот пример на fasm, это не cdecl, стэк очищает вызываемая ф-ция, а строка-формат располагается непосредственно за call. ну и бага есть - символ % не напечатаешь =) Код (Text): PROC WriteLn pusha lea esi,[RETADDR];[esp+sizeof._PUSHA] lods dword[esi] ;; address after CALL mov edx,esp dec dh ;; 256 bytes buffer for wvsprintf mov esp,edx push 0A0D0D0Dh ;; new line push esi ;; esi = address of VA_LIST for wvsprintf push eax ;; pFormat for wvsprintf xchg eax,esi push 1 pop edi ;; ardument counter @@: lods byte[esi] or al,al jz .eol cmp al,'%' jnz @b inc edi jmp @b .eol: CALL wvsprintf, edx mov ebx,[SendMessage] mov ebp,[hCanvas] CALL ebx,ebp,EM_SETSEL,-2,-2 CALL ebx,ebp,EM_REPLACESEL,0,esp __STACK__=__STACK__+4*2*SendMessage% pop ecx ;; remove new line DWORD xchg eax,esp inc ah xchg eax,esp mov [RETADDR],esi;[esp+sizeof._PUSHA] ;; we'll return after the string mov [esp+_PUSHA.eax],edi popa lea eax,[esp+eax*4] xchg eax,esp jmp dword[eax] ENDP macro WriteLn form,[arg] { common local args,char,.text args=0 reverse if~arg eq Push arg args=args+1 end if common call WriteLn .text db form,0 repeat $-.text-1 load char word from .text+%-1 if char='\n' store word 0A0Dh at .text+%-1 end if if char and 255='%' args=args-1 end if end repeat if args<>0 display 10,'################################################################## ##',10,\ ' ERROR: "%" mismatch number of arguments.',10,\ '####################################################################' ,10 !BUG end if }
мдя. Короче, сделаю два вызова- один для нормальных людей, из ассемблера; другой- с кол-вом параметров, для HLL. Пусть кто хочет макрос себе какой-нибудь придумает. S_T_A_S_ add и sub это не проблема, в том кусочке что выше проверяется. За printf конечно спасибо, но я как раз тоже самое делаю Но после того, как я решил что несуществующие переменные (а они нумеруются, т.е. %s_5 или %h_1) должны автоматически выделятся, если их нет, да еще постоянная рекурсия... короче не помню сколько мы тогда пива выпили А сейчас парюсь.
Ну дык на зилоге же не было RET N, вот и применялся такой подход повсеместно... я вроде вообще никогда параметры через стэк не кидал, все их ложил за call, так и код меньше получался. на современных процах это тормозить конечно будет.