мм... все это было замечатально написано, только я забыл что в фасме нет рекурсии макросов, т.к. внутри макроса его имя становится равным имени действовавшим до объявления макроса, именно благодаря этому "macro mov a,b {mov a,b}" не приводит к рекурсии. Т.е. чтобы работала рекурсия нужна следующая конструкция: (развернуто) Code (Text): macro recourse foo { match *bar,foo \{recourse bar\} display "+" } macro recourse foo { match *bar,foo \{recourse bar\} display "+" } ... macro recourse foo { match *bar,foo \{recourse bar\} display "+" } ;test, displays "+++" recourse *** или в свернутом виде - rept 5 { macro recourse foo \{ match *bar,foo \\{recourse bar\\} display "*" \} }
GoldFinch почему бы внутри макроса не обьявлять такой же макрос? то есть у тебя внутри recourse определять следующий макрос recourse.
После нескольких минут попыток написать макрос который объявляет сам себя, я понял что это невозможно, т.к. во 2м макросе надо будет объявить 3й, в 3м 4й и т.д. %) Может можно как-то поиграться с equ, но я не уверен что это что-то даст. Кроме того, если макрос достаточно длинный, то вкладывать в него такой же будет слишком длинно. Пример "рекурсивного" макроса который берет элементы из списка и "обрабатывает" их: Code (Text): macro process X {display `X,13,10} ;some macro processing list items ;recourse rept 10 { macro parse_list list \{ match item/tail ,list/* \\{ process item ;some processing here match _list/* ,tail \\\{parse_list _list \\\} \\} \} } ;test parse_list a/b/c/d
GoldFinch Можно попробовать вызывать рекурсивно макрос с помощью другого макроса синтезируюшего вызов из поданых параметров.
Хм... я понял как сделать макрос объявляющий сам себя. Действительно так гораздо лучше: Code (Text): macro recourse_declare { macro recourse list \{ match item/tail ,list/* \\{ match foo,item \\\{ display \\\`foo,13,10 \\\} ;some processing here match _list/* ,tail \\\{ recourse_declare recourse _list \\\} \\} \} } recourse_declare recourse 1/2/3 ЗЫ: эх.... найти бы где статейку о препроцессоре фасма, а то столько неочевидных нюансов %)
GoldFinch Поискать, поспрошать на форуме фасма? PS хотя я за изменение препроцессора и оставление только ассемблирующего движка. (имхо, в порядке флуда)
GoldFinch на форуме фасма посидеть полистать ихние макросы - очень полезно. Я для фасма ограничился только написанием макроса для апи, что бы вызывать их как в си и всё. Хотел сделать еще присваивания и тому подобное, но оказалось что тогда каждую переменную прийдеться обьявлять как макрос, а это уже много памяти на компиляцию программы. Да и стандартизация - это главная проблема.
В самом деле, обычно и этого хватает. Пока выкладываю "лайт-версию" макросов, только для апи Code (Text): macro IMPORTS [dll,funclist] { common data import forward dd 0,0,0,rva a#dll, rva v#dll common dd 0,0,0,0,0 end data forward v#dll: irp func,funclist \{ p\#func dd rva a\#func macro func [line] \\{common match (arglist),line \\\{ irp arg,arglist \\\\{ reverse pushd arg \\\\} \\\} call [p\\#func] \\} \} dd 0 forward a#dll db `dll#".dll",0 irp func,funclist \{a\#func db 0,0,\`func,0\} } macro pushd arg { if arg eqtype "" call @f local str str db arg,0 str#.len=$-str repeat str#.len-1 load w word from str+%-1 if w="\n" store word 0x0D0A at str+%-1 end if end repeat @@: else pushd arg end if } и пример использования Code (Text): format PE console section 'O_o' code readable executable writeable IMPORTS KERNEL32,<GetStdHandle,WriteFile,ReadFile,ExitProcess>,\ USER32,<wsprintfA> entry $ GetStdHandle(-11) ;STD_OUTPUT_HANDLE mov [stdout],eax GetStdHandle(-10) ;STD_INPUT_HANDLE mov [stdin],eax ;------------------------- ;..... ;------------------------- exit: wsprintfA(gMsgBuf,"Program terminated.\nPress [enter] to close log.\n") add esp,8 WriteFile([stdout],gMsgBuf,eax,0,0) ReadFile([stdin],gMsgBuf,1024,nRead,0) ExitProcess(0) ;_____________________________________ ;Uninitialized data. Must be at end of section nRead dd ? stdout dd ? stdin dd ? gMsgBuf db 1024 dup (?) upd: возможен другой вариант макросов, хз что лучше %) ... match (arglist),line \\\{ push_r arglist \\\} ... macro push_r [arg] { reverse if arg eqtype "" ...
Вот мы и дожили до продолжения... Итак мне надо было написать код который экспортировал бы методы из длл. В процессе его написания были выявлены следующие недостатки существующих макросов: - нет поддержки задания псевдонимов импортируемых функций, для этого надо использовать директиву fix - вызов функций работает только для импортируемых функций, для локальных нужен отдельный макрос PROTO - поддерживется только __stdcall - несовместимость макросов с объявлениями их меток "Say2:", надо использовать "label Say2", по этой же причине несовместимость с некоторыми макросами win32a.inc, в том числе с "proc" Получился код такого вида: Code (Text): L2ParamStack.Create fix ??0L2ParamStack@@QAE@H@Z L2ParamStack.PushBack fix ?PushBack@L2ParamStack@@QAEHPAX@Z L2ParamStack.Top fix ?Top@L2ParamStack@@QAEPAXXZ L2ParamStack.Free fix ??1L2ParamStack@@QAE@XZ IMPORTS KERNEL32,<DisableThreadLibraryCalls,CreateThread>,\ CORE,<L2ParamStack.Create,L2ParamStack.PushBack,L2ParamStack.Top,L2ParamStack.Free>,\ ... PROTO Say2,Say2 ... label Say2 ;(puText,puName) sub esp,16 ;local buf for L2ParamStack mov ecx,esp L2ParamStack.Create(10) ... GetDlgItemTextW([esp+3*4+4+0],ID_INPUT,gInputBuf,sizeof.gInputBuf) Say2(gInputBuf,0) ... Мне этот код не понравился, поэтому было решено полностью переписать макросы, устранив все перечисленные недостатки. Для расширенного объявления прототипов функций был введен макрос 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, импорт реализован через стандартные макросы импорта. Пример использования: Code (Text): PROTO L2ParamStack::Create() name '??0L2ParamStack@@QAE@H@Z' from CORE.DLL PROTO L2ParamStack::PushBack() name '?PushBack@L2ParamStack@@QAEHPAX@Z' from CORE.DLL PROTO L2ParamStack::Top() name '?Top@L2ParamStack@@QAEPAXXZ' from CORE.DLL PROTO L2ParamStack::Free() name '??1L2ParamStack@@QAE@XZ' from CORE.DLL IMPORTS KERNEL32.DLL,<DisableThreadLibraryCalls,CreateThread>,\ USER32.DLL, <wsprintfA,DialogBoxParamA,GetDlgItemTextW,GetDlgItemInt,SetDlgItemTextA,EndDialog> PROTO LogInput() PROTO Say2() ... proc Say2 uses esi, puText,puName,dwType local L2Stack[16]:BYTE lea esi,[L2Stack] L2ParamStack.Create(esi,10) ;stack deep 10 L2ParamStack.PushBack(esi,[dwType]) ... GetDlgItemTextW([hwndDlg],ID_INPUT,gInputBuf,sizeof.gInputBuf) Say2(gInputBuf,0) ... Инклуд hll.inc в аттаче. Также в инклуде есть макрос m2m (push src / pop dst)
GoldFinch смотрю ты не остановился, макросишь дальше Приятно видеть такое, люблю смотреть другие макросы. PROTO L2ParamStack::Free() name '??1L2ParamStack@@QAE@XZ' from CORE.DLL запись прикольная, только вот с именами не сильно удобно. '??1L2ParamStack@@QAE@XZ' - ногу сломишь Кстати глядел на готовящийся формат данных для отладки фасма? Интересно твоё мнение и мнение всех остальных кто смотрел. Все кому интересно сюда: http://board.flatassembler.net/topic.php?p=84549#84549 там в конце выложен в виде аттача.
dead_body Ну макрос формирования манглинга в теории возможен, но это слишком сложно и будет содержать много ошибок имхо. Так и так в экспорте mangled имена, брать их расшифровку из IDA и обратно преобразовать - сомнительная затея.
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;
Помогите плиз делаю Code (Text): PROTO UCanvas::DrawTextTTFToCanvas() name '?DrawTextTTFToCanvas@UCanvas@@QAEHHHPBGPBVFontDrawInfo@@EHHPBV?$TArray@PAVFontDrawInfoSection@@@@@Z' from ENGINE.DLL вызываю Code (Text): proc DrawTextTTFToCanvas xx,yy,style,txt ;mov ecx, [pUCanvas] ;push 0 ;push 0 ;push 0 ;push 0ffh ;push [style] ;push [txt] ;push [yy] ;push [xx] ;call [dwDrawProc] UCanvas.DrawTextTTFToCanvas([xx],[yy],[txt],[style],0ffh,0,0,0) ret endp Пишет Error: underfined Symbol и указывает на строку UCanvas.DrawTextTTFToCanvas([xx],[yy],[txt],[style],0ffh,0,0,0) в Инструктионс пишет call[UCanvas.DrawTextTTFToCanvas]
Пробую написать скрипт. Имеется: код, собирается в секции .data. Задача: пересчитать все внутренние переходы (jmp, call) для другого смещения в образе (конерктно - требуется сделать этот код работоспособным после копирования в секцию .text). baseoffset = 100h macro call proc { newaddr = proc+baseoffset call newaddr } Так - не выходит
Внутренние переходы пересчитывать не нужно. call и jmp в fasm всегда относительные, если специально не указать обратное, либо если целевой адрес находится в другой секции.