определение кол-ва параметров при вызове CDECL

Тема в разделе "WASM.A&O", создана пользователем yureckor, 1 авг 2005.

  1. yureckor

    yureckor New Member

    Публикаций:
    0
    Регистрация:
    25 фев 2004
    Сообщения:
    494
    Адрес:
    Russia
    Собственно, написал я функцию.

    Она использует переменное число аргументов и ей явно передается их число. Но во-первых, это не удобно; а во вторых, для совместимости с предыдущей реализацией я к ней сделал переходник (т.е заменил код в старой реализации на заглушку и вызов новой):
    Код (Text):
    1.  
    2. sctx_str proc C mem1:DWORD,mem2:DWORD,argum:VARARG
    3. ...
    4.  xor eax, eax
    5.  mov ecx, [ebp+4] ;адрес возврата ret
    6.  or edx, -1
    7.  mov eax, [ecx]
    8.  ;
    9.  mov ebx, [ecx+2]
    10.  cmp al, 81h ;81C4xxxxxxxx или 81ECxxxxxxxx
    11.  jz @@1
    12.  and ebx, 0FFh
    13.  and edx, 0FFh
    14.  cmp al, 83h ;83C4xx или 83ECxx
    15.  clc
    16.  jnz @@100
    17.  ;
    18.  @@1:
    19.  cmp ah, 0C4h ;add
    20.  jz @@2
    21.  xor ebx, edx
    22.  inc ebx
    23.  cmp ah, 0ECh ;sub
    24.  clc
    25.  jnz @@100
    26.  ;
    27.  @@2:
    28.  sub ebx, 2*4 ;это mem1 и mem2
    29.  clc
    30.  js @@100
    31. ...
    32.  


    который определяет по коду, следующему за call'ом (add esp, xx) сколько параметров было передано через стек.



    Хороший ли это вариант? На masm'е все ок, как генерит код fasm? И C++ и Delphi? Нет ли там мусора между call и add esp, xxx ?



    В принципе, это скриптовый язык для разбора текстов, и мож я его скрещу с дизассемблером, но пока я к этому не готов морально :)
     
  2. Dr.Golova

    Dr.Golova New Member

    Публикаций:
    0
    Регистрация:
    7 сен 2002
    Сообщения:
    348
    > C++ и Delphi? Нет ли там мусора между call и add esp, xxx



    Есть =) По крайней мере современные С++ компиляторы запросто могут слить несколько add esp, xxx после нескольких вызовов функций в один и зызвать его один раз.
     
  3. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    а ещё может быть sub esp, вместо add ;) или даже leave\mov esp, ebp

    так что универсального подхода для подсчёта аргументов cdecl imho нет, даже если считать push'и перед call, всё равно может не работать...





    для ф-ций типа printf можно вычислять кол-во аргументов по строке-формату.

    вот пример на fasm, это не cdecl, стэк очищает вызываемая ф-ция, а строка-формат располагается непосредственно за call. ну и бага есть - символ % не напечатаешь =)
    Код (Text):
    1.  
    2. PROC    WriteLn
    3.  
    4.     pusha
    5.     lea esi,[RETADDR];[esp+sizeof._PUSHA]
    6.     lods    dword[esi]    ;;  address after CALL
    7.                        
    8.     mov edx,esp
    9.     dec dh      ;;  256 bytes buffer for wvsprintf
    10.     mov esp,edx
    11.     push    0A0D0D0Dh   ;;  new line
    12.  
    13.     push    esi     ;;  esi = address of VA_LIST for wvsprintf
    14.     push    eax     ;;  pFormat for wvsprintf
    15.  
    16.     xchg    eax,esi
    17.     push    1
    18.     pop edi     ;; ardument counter
    19.  
    20. @@: lods    byte[esi]
    21.     or  al,al
    22.     jz  .eol
    23.     cmp al,'%'
    24.     jnz @b
    25.     inc edi
    26.     jmp @b
    27.    
    28. .eol:   CALL    wvsprintf, edx
    29.  
    30.     mov ebx,[SendMessage]
    31.     mov ebp,[hCanvas]
    32.     CALL    ebx,ebp,EM_SETSEL,-2,-2
    33.     CALL    ebx,ebp,EM_REPLACESEL,0,esp
    34.     __STACK__=__STACK__+4*2*SendMessage%
    35.  
    36.     pop ecx     ;;  remove new line DWORD
    37.     xchg    eax,esp
    38.     inc ah
    39.     xchg    eax,esp
    40.  
    41.     mov [RETADDR],esi;[esp+sizeof._PUSHA]   ;;  we'll return after the string
    42.     mov [esp+_PUSHA.eax],edi
    43.  
    44.     popa
    45.     lea eax,[esp+eax*4]
    46.     xchg    eax,esp
    47.     jmp dword[eax]
    48. ENDP
    49.  
    50.  
    51. macro  WriteLn  form,[arg]
    52. {
    53.     common  local   args,char,.text
    54.             args=0
    55.     reverse if~arg eq
    56.             Push arg
    57.             args=args+1
    58.         end if
    59.     common  call WriteLn
    60.         .text   db form,0
    61.        
    62.         repeat  $-.text-1
    63.             load    char word from .text+%-1
    64.             if char='\n'
    65.                 store word 0A0Dh at .text+%-1
    66.             end if
    67.             if char and 255='%'
    68.                 args=args-1
    69.             end if
    70.         end repeat
    71.         if args<>0
    72.         display 10,'##################################################################   ##',10,\
    73.         '  ERROR:  "%" mismatch number of arguments.',10,\
    74.         '####################################################################'   ,10
    75.         !BUG
    76.         end if
    77. }
     
  4. yureckor

    yureckor New Member

    Публикаций:
    0
    Регистрация:
    25 фев 2004
    Сообщения:
    494
    Адрес:
    Russia
    мдя.

    Короче, сделаю два вызова- один для нормальных людей, из ассемблера; другой- с кол-вом параметров, для HLL. Пусть кто хочет макрос себе какой-нибудь придумает.



    S_T_A_S_

    add и sub это не проблема, в том кусочке что выше проверяется. За printf конечно спасибо, но я как раз тоже самое делаю :)

    Но после того, как я решил что несуществующие переменные (а они нумеруются, т.е. %s_5 или %h_1) должны автоматически выделятся, если их нет, да еще постоянная рекурсия... короче не помню сколько мы тогда пива выпили :)

    А сейчас парюсь.
     
  5. yureckor

    yureckor New Member

    Публикаций:
    0
    Регистрация:
    25 фев 2004
    Сообщения:
    494
    Адрес:
    Russia
    S_T_A_S_>а строка располагается непосредственно за call...

    Ты тоже Zeus разбирал?
     
  6. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    Ну дык на зилоге же не было RET N, вот и применялся такой подход повсеместно... я вроде вообще никогда параметры через стэк не кидал, все их ложил за call, так и код меньше получался. на современных процах это тормозить конечно будет.