(fasm) расширение синтаксиса

Тема в разделе "WASM.ASSEMBLER", создана пользователем GoldFinch, 24 сен 2008.

  1. dead_body

    dead_body wasm.ru

    Публикаций:
    0
    Регистрация:
    3 сен 2004
    Сообщения:
    603
    Адрес:
    Украина;г.Харьков;г.Н.Каховка
    GoldFinch
    Хорошее начало, жду продолжения. :)
     
  2. GoldFinch

    GoldFinch New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2008
    Сообщения:
    1.775
    мм... все это было замечатально написано, только я забыл что в фасме нет рекурсии макросов, т.к. внутри макроса его имя становится равным имени действовавшим до объявления макроса, именно благодаря этому "macro mov a,b {mov a,b}" не приводит к рекурсии.
    Т.е. чтобы работала рекурсия нужна следующая конструкция: (развернуто)
    Код (Text):
    1. macro recourse foo {
    2.       match *bar,foo \{recourse bar\}
    3.       display "+" }
    4. macro recourse foo {
    5.       match *bar,foo \{recourse bar\}
    6.       display "+" }
    7. ...
    8. macro recourse foo {
    9.       match *bar,foo \{recourse bar\}
    10.       display "+" }
    11. ;test, displays "+++"
    12. recourse ***
    или в свернутом виде -
    rept 5 { macro recourse foo \{
    match *bar,foo \\{recourse bar\\}
    display "*" \} }
     
  3. dead_body

    dead_body wasm.ru

    Публикаций:
    0
    Регистрация:
    3 сен 2004
    Сообщения:
    603
    Адрес:
    Украина;г.Харьков;г.Н.Каховка
    GoldFinch
    почему бы внутри макроса не обьявлять такой же макрос?

    то есть у тебя внутри recourse определять следующий макрос recourse.
     
  4. GoldFinch

    GoldFinch New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2008
    Сообщения:
    1.775
    После нескольких минут попыток написать макрос который объявляет сам себя, я понял что это невозможно, т.к. во 2м макросе надо будет объявить 3й, в 3м 4й и т.д. %)
    Может можно как-то поиграться с equ, но я не уверен что это что-то даст.
    Кроме того, если макрос достаточно длинный, то вкладывать в него такой же будет слишком длинно.

    Пример "рекурсивного" макроса который берет элементы из списка и "обрабатывает" их:
    Код (Text):
    1. macro process X {display `X,13,10} ;some macro processing list items
    2. ;recourse
    3. rept 10 { macro parse_list list \{
    4.      match item/tail ,list/* \\{
    5.            process item ;some processing here
    6.            match _list/* ,tail \\\{parse_list _list \\\} \\} \} }
    7. ;test
    8. parse_list a/b/c/d
     
  5. _basmp_

    _basmp_ New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2005
    Сообщения:
    2.939
    GoldFinch
    Можно попробовать вызывать рекурсивно макрос с помощью другого макроса синтезируюшего вызов из поданых параметров.
     
  6. GoldFinch

    GoldFinch New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2008
    Сообщения:
    1.775
    Хм... я понял как сделать макрос объявляющий сам себя. Действительно так гораздо лучше:
    Код (Text):
    1. macro recourse_declare {
    2. macro recourse list \{
    3.       match item/tail ,list/* \\{
    4.             match foo,item \\\{ display \\\`foo,13,10 \\\} ;some processing here
    5.             match _list/* ,tail \\\{
    6.                   recourse_declare
    7.                   recourse _list \\\} \\} \} }
    8. recourse_declare
    9. recourse 1/2/3
    ЗЫ: эх.... найти бы где статейку о препроцессоре фасма, а то столько неочевидных нюансов %)
     
  7. _basmp_

    _basmp_ New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2005
    Сообщения:
    2.939
    GoldFinch
    Поискать, поспрошать на форуме фасма?

    PS хотя я за изменение препроцессора и оставление только ассемблирующего движка. (имхо, в порядке флуда)
     
  8. Freeman

    Freeman New Member

    Публикаций:
    0
    Регистрация:
    10 фев 2005
    Сообщения:
    1.385
    Адрес:
    Ukraine
    ты уже и сам можешь напесать
     
  9. dead_body

    dead_body wasm.ru

    Публикаций:
    0
    Регистрация:
    3 сен 2004
    Сообщения:
    603
    Адрес:
    Украина;г.Харьков;г.Н.Каховка
    GoldFinch
    на форуме фасма посидеть полистать ихние макросы - очень полезно.

    Я для фасма ограничился только написанием макроса для апи, что бы вызывать их как в си и всё.
    Хотел сделать еще присваивания и тому подобное, но оказалось что тогда каждую переменную прийдеться обьявлять как макрос, а это уже много памяти на компиляцию программы.

    Да и стандартизация - это главная проблема.
     
  10. GoldFinch

    GoldFinch New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2008
    Сообщения:
    1.775
    В самом деле, обычно и этого хватает.

    Пока выкладываю "лайт-версию" макросов, только для апи
    Код (Text):
    1. macro IMPORTS [dll,funclist] {
    2. common  data import
    3. forward dd 0,0,0,rva a#dll, rva v#dll
    4. common  dd 0,0,0,0,0
    5.         end data
    6. forward v#dll: irp func,funclist \{
    7.                    p\#func dd rva a\#func
    8.                    macro func [line] \\{common
    9.                          match (arglist),line \\\{
    10.                                irp arg,arglist \\\\{ reverse pushd arg \\\\}  \\\}
    11.                          call [p\\#func] \\} \}
    12.         dd 0
    13. forward a#dll db `dll#".dll",0
    14.         irp func,funclist \{a\#func db 0,0,\`func,0\} }
    15. macro pushd arg { if arg eqtype ""
    16.                      call @f
    17.                      local str
    18.                      str db arg,0
    19.                      str#.len=$-str
    20.                      repeat str#.len-1
    21.                             load w word from str+%-1
    22.                             if w="\n"
    23.                                store word 0x0D0A at str+%-1
    24.                             end if
    25.                      end repeat
    26.              @@:  else
    27.                      pushd arg
    28.                   end if }
    и пример использования
    Код (Text):
    1. format PE console
    2. section 'O_o' code readable executable writeable
    3. IMPORTS KERNEL32,<GetStdHandle,WriteFile,ReadFile,ExitProcess>,\
    4.         USER32,<wsprintfA>
    5. entry $
    6. GetStdHandle(-11) ;STD_OUTPUT_HANDLE
    7. mov [stdout],eax
    8. GetStdHandle(-10) ;STD_INPUT_HANDLE
    9. mov [stdin],eax
    10. ;-------------------------
    11. ;.....
    12. ;-------------------------
    13. exit:
    14. wsprintfA(gMsgBuf,"Program terminated.\nPress [enter] to close log.\n")
    15. add esp,8
    16. WriteFile([stdout],gMsgBuf,eax,0,0)
    17. ReadFile([stdin],gMsgBuf,1024,nRead,0)
    18. ExitProcess(0)
    19. ;_____________________________________
    20. ;Uninitialized data. Must be at end of section
    21. nRead dd ?
    22. stdout dd ?
    23. stdin dd ?
    24. gMsgBuf db 1024 dup (?)
    upd: возможен другой вариант макросов, хз что лучше %)
    ... match (arglist),line \\\{ push_r arglist \\\}
    ...
    macro push_r [arg] { reverse
    if arg eqtype "" ...
     
  11. GoldFinch

    GoldFinch New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2008
    Сообщения:
    1.775
    Вот мы и дожили до продолжения...
    Итак мне надо было написать код который экспортировал бы методы из длл. В процессе его написания были выявлены следующие недостатки существующих макросов:
    - нет поддержки задания псевдонимов импортируемых функций, для этого надо использовать директиву fix
    - вызов функций работает только для импортируемых функций, для локальных нужен отдельный макрос PROTO
    - поддерживется только __stdcall
    - несовместимость макросов с объявлениями их меток "Say2:", надо использовать "label Say2",
    по этой же причине несовместимость с некоторыми макросами win32a.inc, в том числе с "proc"

    Получился код такого вида:
    Код (Text):
    1. L2ParamStack.Create     fix ??0L2ParamStack@@QAE@H@Z
    2. L2ParamStack.PushBack   fix ?PushBack@L2ParamStack@@QAEHPAX@Z
    3. L2ParamStack.Top        fix ?Top@L2ParamStack@@QAEPAXXZ
    4. L2ParamStack.Free       fix ??1L2ParamStack@@QAE@XZ
    5. IMPORTS KERNEL32,<DisableThreadLibraryCalls,CreateThread>,\
    6.     CORE,<L2ParamStack.Create,L2ParamStack.PushBack,L2ParamStack.Top,L2ParamStack.Free>,\
    7.     ...
    8. PROTO Say2,Say2
    9.     ...
    10. label Say2 ;(puText,puName)
    11.     sub esp,16 ;local buf for L2ParamStack
    12.     mov ecx,esp
    13.     L2ParamStack.Create(10)
    14.     ...
    15.     GetDlgItemTextW([esp+3*4+4+0],ID_INPUT,gInputBuf,sizeof.gInputBuf)
    16.     Say2(gInputBuf,0)
    17.     ...
    Мне этот код не понравился, поэтому было решено полностью переписать макросы, устранив все перечисленные недостатки.

    Для расширенного объявления прототипов функций был введен макрос PROTO:
    PROTO [USomeObject::]SomeFunc() [[name "_SomeFunc@4"] from file.dll]
    Этот макрос создает макрос для последующего вызова функций и методов:
    SomeFunc(ofs_arg1,[mem_arg1],"textarg1",localvar1,[localvar2]) ;для функций
    USomeObject.SomeFunc(pObject,arg1) ;эквивалентно сишному (USomeObject*)pObject->SomeFunc(arg1)
    Поддерживаются строковые константы (через call .skip / "xxx",0 / .skip: ) и адреса локальных переменных, без ADDR (через lea edx), вызов функций совместим с win32a.inc .
    Для импортируемых функций (методов), функция добавляется во внутренний список импортов, порядок частей [USomeObject::]SomeFunc(), from file.dll, name "_SomeFunc@4" не важен. Вместо символьного имени (name "_SomeFunc@4") можно написать ординал: name 11 .

    Импорт осуществляется макросом IMPORTS:
    IMPORTS kernel32.dll,<ExitProcess,FormatMessageA,GetLastError>,\
    user32.dll,<MessageBoxA,wsprintfA>
    Параметры необязательны, запись
    IMPORTS kernel32.dll,ExitProcess
    эквивалентна записи
    IMPORTS
    PROTO ExitProcess() from kernel32.dll
    Желательно указывать расширение длл на конце ее имени, иначе в импорте будет написано "kernel32" вместо "kernel32.dll" (хотя это тоже работает o_O). Макрос IMPORTS включает в себя data import / end data, импорт реализован через стандартные макросы импорта.

    Пример использования:
    Код (Text):
    1. PROTO L2ParamStack::Create()     name '??0L2ParamStack@@QAE@H@Z'                       from CORE.DLL
    2. PROTO L2ParamStack::PushBack()   name '?PushBack@L2ParamStack@@QAEHPAX@Z'              from CORE.DLL
    3. PROTO L2ParamStack::Top()        name '?Top@L2ParamStack@@QAEPAXXZ'                    from CORE.DLL
    4. PROTO L2ParamStack::Free()       name '??1L2ParamStack@@QAE@XZ'                        from CORE.DLL
    5. IMPORTS KERNEL32.DLL,<DisableThreadLibraryCalls,CreateThread>,\
    6.         USER32.DLL,  <wsprintfA,DialogBoxParamA,GetDlgItemTextW,GetDlgItemInt,SetDlgItemTextA,EndDialog>
    7. PROTO LogInput()
    8. PROTO Say2()
    9.     ...
    10. proc Say2 uses esi, puText,puName,dwType
    11.      local L2Stack[16]:BYTE
    12.     lea esi,[L2Stack]
    13.     L2ParamStack.Create(esi,10) ;stack deep 10
    14.     L2ParamStack.PushBack(esi,[dwType])
    15.     ...
    16.     GetDlgItemTextW([hwndDlg],ID_INPUT,gInputBuf,sizeof.gInputBuf)
    17.     Say2(gInputBuf,0)
    18.     ...
    Инклуд hll.inc в аттаче.
    Также в инклуде есть макрос m2m (push src / pop dst)
     
  12. dead_body

    dead_body wasm.ru

    Публикаций:
    0
    Регистрация:
    3 сен 2004
    Сообщения:
    603
    Адрес:
    Украина;г.Харьков;г.Н.Каховка
    GoldFinch
    смотрю ты не остановился, макросишь дальше :) Приятно видеть такое, люблю смотреть другие макросы.

    PROTO L2ParamStack::Free() name '??1L2ParamStack@@QAE@XZ' from CORE.DLL

    запись прикольная, только вот с именами не сильно удобно. '??1L2ParamStack@@QAE@XZ' - ногу сломишь :dntknw:

    Кстати глядел на готовящийся формат данных для отладки фасма? Интересно твоё мнение и мнение всех остальных кто смотрел. :)

    Все кому интересно сюда: http://board.flatassembler.net/topic.php?p=84549#84549 там в конце выложен в виде аттача.
     
  13. GoldFinch

    GoldFinch New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2008
    Сообщения:
    1.775
    это же манглинг, он копипастится
     
  14. dead_body

    dead_body wasm.ru

    Публикаций:
    0
    Регистрация:
    3 сен 2004
    Сообщения:
    603
    Адрес:
    Украина;г.Харьков;г.Н.Каховка
    GoldFinch
    так неудобно копипастить, нужны макросы что бы поменьше копипастить.
     
  15. GoldFinch

    GoldFinch New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2008
    Сообщения:
    1.775
    dead_body
    Ну макрос формирования манглинга в теории возможен, но это слишком сложно и будет содержать много ошибок имхо. Так и так в экспорте mangled имена, брать их расшифровку из IDA и обратно преобразовать - сомнительная затея.
     
  16. GoldFinch

    GoldFinch New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2008
    Сообщения:
    1.775
    Ммм... хорошо бы чтобы это можно было бы прикрутить к ольке.
     
  17. Aspire

    Aspire New Member

    Публикаций:
    0
    Регистрация:
    19 май 2007
    Сообщения:
    1.028
    GoldFinch
    Вызов функций как в Си - это, конечно, здорово, но для меня, например, более важной кажется возможность вложенного вызова функций, которая, _помоему_, у тебя исключена.
    Что-то типа того, как я пишу на масме:
    inv f(GetProcAddress, f(LoadLibrary, s("Rpcrt4.dll")), s("UuidFromString")), offset Interface, offset RPCBind.InterfaceUUID;

    тут inv, f и s - макросы.

    А также, возможность передавать результат сразу в переменную: mov mem, f(func_name, param, param ...); а то, от количества регистров в исходнике, иногда в глазах рябит...


    [add] В masm32v10 они соорудили таки макрос rv.
    Теперь это будет выглядет проще:
    inv rv(GetProcAddress, rv(LoadLibrary, "Rpcrt4.dll"), "UuidFromString"), offset Interface, offset RPCBind.InterfaceUUID;
     
  18. r2max

    r2max Женя

    Публикаций:
    0
    Регистрация:
    30 мар 2011
    Сообщения:
    40
    Адрес:
    Киев
    Помогите плиз
    делаю
    Код (Text):
    1. PROTO UCanvas::DrawTextTTFToCanvas()     name '?DrawTextTTFToCanvas@UCanvas@@QAEHHHPBGPBVFontDrawInfo@@EHHPBV?$TArray@PAVFontDrawInfoSection@@@@@Z' from ENGINE.DLL
    вызываю
    Код (Text):
    1. proc DrawTextTTFToCanvas xx,yy,style,txt
    2.        ;mov  ecx, [pUCanvas]
    3.        ;push    0                                          
    4.        ;push    0                                      
    5.        ;push    0                                          
    6.        ;push    0ffh                                       
    7.        ;push    [style]                        
    8.        ;push    [txt]                          
    9.        ;push    [yy]                                       
    10.        ;push    [xx]                                       
    11.        ;call    [dwDrawProc]
    12.        UCanvas.DrawTextTTFToCanvas([xx],[yy],[txt],[style],0ffh,0,0,0)
    13.    ret
    14. endp
    Пишет
    Error:
    underfined Symbol
    и указывает на строку
    UCanvas.DrawTextTTFToCanvas([xx],[yy],[txt],[style],0ffh,0,0,0)
    в Инструктионс пишет
    call[UCanvas.DrawTextTTFToCanvas]
     
  19. l0tw

    l0tw New Member

    Публикаций:
    0
    Регистрация:
    6 июн 2011
    Сообщения:
    8
    Пробую написать скрипт.
    Имеется: код, собирается в секции .data.
    Задача: пересчитать все внутренние переходы (jmp, call) для другого смещения в образе (конерктно - требуется сделать этот код работоспособным после копирования в секцию .text).

    baseoffset = 100h

    macro call proc
    {
    newaddr = proc+baseoffset
    call newaddr
    }

    Так - не выходит
     
  20. KIV

    KIV Member

    Публикаций:
    0
    Регистрация:
    16 июл 2009
    Сообщения:
    231
    Внутренние переходы пересчитывать не нужно. call и jmp в fasm всегда относительные, если специально не указать обратное, либо если целевой адрес находится в другой секции.