Версия для печати
Нажмите сюда для просмотра этой темы в оригинальном формате |
Форум на Исходниках.RU > Assembler > Delphi синтаксис в masm |
Автор: kin01 05.09.18, 07:09 |
Прошу подсказать реально или нет максимально приблизить синтаксис Delphi к masm с помощью макросов. Например: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> include delphi.inc program test; var v: DWORD; begin endpro <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> program macro a1 .386 .model flat,stdcall option casemap:none endm begin macro .code start: endm endpro macro end start endm var macro a1 LOCAL a1 endm Пример простой, препроцессор его обрабатывает. Но не понятно как обрабатывать конструкции if -> .if создавать процедуры <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> procedure test; begin end; <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> test proc endp и т.д. Хватит ли возможностей макросов, чтобы покрыть синтаксис Delphi, хотябы на 90%? Буду рад любой помощи) |
Автор: Jin X 05.09.18, 11:51 |
Наверное, имеется в виду приблизить синтаксис MASM к Delphi всё-таки, т.е. с помощью макросов сделать Delphi-подобный синтаксис в MASM (не наоборот же)? Полноценно - нет, но частично можно. Я бы, скорее, оценил процентов в 10, чем в 90, к тому же это будет извращённо выглядящий Delphi-код Проблема №1. Вызов макроса начинается с идентификатора. Т.е. нельзя написать A := B, если A - это переменная, а не макрос. Создавать макросы внутри макросов можно, но тогда придётся каждую переменную описывать как макрос только лишь ради реализации вещей типа присваивания. Либо писать так: . A := B, где точка - это макрос (его можно назвать @, _ или буквой, к примеру). Аналогично проблематично создать макрос, который будет выполнять операции вида Inc(A). Тут либо, опять же, писать . Inc(A), либо что-то другое выдумывать. Проблема №2. Макросы в MASM реализованы через клоаку макаки. Уверен, что вы изрядно намучаетесь при попытке разбора синтаксиса, отделении и распознавании идентификаторов, переменных и операторов друг от друга. Особенно если вы захотите поддерживать варианты с пробелами и без (например Inc ( A ) и Inc(A) или . A := B, . A:= B и . A:=B). Можно создавать макросы-функции, но это всё равно не насколько сильно упростит задачу. Проблема №3. Даже если вы это реализуете, всё будет нереально жутко тормозить. Про невозможность использования точки с запятой для отделения конструкций я уж не говорю – это и так понятно, я думаю. Поэтому проще написать интерпретатор, который будет конвертировать исходник в asm-код. Можно, конечно, вместо MASM посмотреть в сторону fasmg (именно g!), но эту идею я бы тоже не спешил называть разумной. |
Автор: kin01 05.09.18, 12:32 |
Спасибо за детальное разьяснение. про присваивание тоже потом подумал. Макросы в масм наоборот всегда казались мощным инструментом :-) |
Автор: Jin X 05.09.18, 20:32 |
kin01, они мощные, но не настолько, как в fasm/fasmg или NASM (ИМХО). И там есть немало геморных вещей. Например, может пройти много времени, прежде чем вы начнёте понимать, когда препроцессор интерпретирует параметр макроса как просто идентификатор, а когда как его значение (особенно при использовании вложенных конструкций с irp'ами, процентами). Довольно занятно отлаживать код, который должен соединять имена идентификаторов (к примеру, чтобы макрос при обращении MyMacro ABC, DEF создал идентификатор ABC_DEF). Ну и ещё множество интересных моментов можно придумать. Я намучился с этим, когда делал Полезные макросы (xmacro). И одна из причин, по которой я не доделал следующую версию (хотя новых фишек там очень много). Добавлено Правда, в xmacro я делал так, чтобы макросы работали и в MASM, и в TASM – там тоже есть некоторые "забавные" отличия (например, в TASM параметры можно разделять пробелом). |
Автор: Qraizer 05.09.18, 21:38 |
На MASMовых макросах, однако, был наверчен сумасшедший фреймворк для писанины 386 и VxD под Win3X и Win9x. Тогда было всё грустно с Cями под ядерный программинг, поэтому MS наворотила вокруг ассемблера почти C. |
Автор: Jin X 06.09.18, 05:33 |
Qraizer, что за фреймворк? Есть ссылка? Поскольку MS является автором MASM'а, они, по логике, должны знать его синтаксис досконально. Но я не говорю, что в нём нельзя разобраться, просто это может оказаться сложнее, чем кажется. Хотя, авторы UASM'а всё же разобрались, раз сделали совместимый в MASM ассемблер. Но в любом случае я почти уверен, что проще самому написать анализатор на нормальном языке, чем на языке макросов MASM. И работать это будет быстрее. |
Автор: kin01 06.09.18, 07:31 |
читал такое: Скрытый текст Цитата На самом деле MASM очень плохо документирован, и видно MS совсем не относится к нему как к продукту (что вполне очевидно). Хотя уже в MSDN 2002 был внесён раздел MASM Reference, и всё равно – вы не найдёте лучше описания чем в MASM32 by Hutch. Когда вы прочтете, то воскликните: «Да, зачем мне такой ML?». Есть NASM и FASM – главная надежда мира ассемблерщиков. Однако и теперь ML всё ещё выигрывает у них по удобству эксплуатации, большей частью видимо благодаря Хатчу, и многим замечательным людям, поддерживающим MASM32. Кто знает, может после этой статьи кто-то воскликнет: «Я знаю, какой должен быть компилятор мечты асмовцев!». И напишет новый компилятор. (Автор шутит ?) |
Автор: Qraizer 06.09.18, 14:41 |
Windows 98 DDK или как-то так. В своё время я плотно его использовал, большей частью уже на C/C++, но и ассемблер попадался. Типа того: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> ; Инициализация или переинициализация Declare_Virtual_Device ISA2EPP, 2, 0, ISA2EPP_Control, UNDEFINED_DEVICE_ID,\ UNDEFINED_INIT_ORDER VxD_ICODE_SEG ; Чтение числового параметра из реестра ; esi - строка с именем параметра ; eax - результат ; ZF - 0, если ошибка BeginProc regRead LocalVar typeValue, DWORD LocalVar regData, DWORD LocalVar regDataSize, DWORD EnterProc mov [regDataSize], TYPE [regData] lea eax, [typeValue] lea ecx, [regData] lea edx, [regDataSize] VMMCall _RegQueryValueEx, <hKey, esi, 0, eax, ecx, edx> cmp eax, ERROR_SUCCESS mov eax, 0 jne @F cmp [typeValue], REG_DWORD jne @F cmp [regDataSize], TYPE [regData] jne @F mov eax, [regData] @@: LeaveProc Return EndProc regRead ; ; ... ; VxD_ICODE_ENDS VxD_LOCKED_CODE_SEG BeginProc ISA2EPP_Control Control_Dispatch DEVICE_INIT, ISA2EPP_Static_Init Control_Dispatch SYSTEM_EXIT, ISA2EPP_Static_Done Control_Dispatch SYS_DYNAMIC_DEVICE_INIT, ISA2EPP_Load Control_Dispatch SYS_DYNAMIC_DEVICE_EXIT, ISA2EPP_Unload Control_Dispatch W32_DEVICEIOCONTROL, Win32_Request clc ret EndProc ISA2EPP_Control ; ; ... ; BeginProc ISA2EPP_Init ESP, PCALL ArgVar _ISAbase, DWORD LocalVar _numPort, DWORD LocalVar listPorts, <2*4*32> EnterProc SaveReg <edi, esi> xor edi, edi mov esi, OFFSET32 ISA2EPP_Hook ; адрес обработчика ввода/вывода mov ecx, 4 ; диапазоны ВВ L1: lea eax, [ecx-1] shl eax, 10 ; в 11-10 биты адреса add eax, [_ISAbase] ; плюс база от начала диапазона SaveReg ecx mov ecx, 32 ; 32 порта в диапазоне @@: lea edx, [ecx+eax-1] ; полный адрес порта mov listPorts[edi*2], dx ; запомнить VMMCall Install_IO_Handler ; и поставить хук на порт cmc ; если неуспех, adc edi, 0 ; не запоминать loop @B ; цикл по портам в диапазоне RestoreReg ecx loop L1 ; цикл по диапазонам mov [_numPort], edi ; количество успешно cmp edi, 32*4 ; перехваченных портов RestoreReg <esi, edi> jne @F ; не перехвачен хотя бы один? clc ; нет - всё ок LeaveProc PRESERVE_FLAGS Return @@: lea eax, [listPorts] pCall ISA2EPP_Done, <eax, _numPort> ; иначе освободить stc ; и сообщить об ошибке LeaveProc PRESERVE_FLAGS Return EndProc ISA2EPP_Init VxD_LOCKED_CODE_ENDS VxD_PAGEABLE_CODE_SEG ; ; ... ; ; callback для сообщения об ошибке BeginProc errorReport CCALL ArgVar dwRefData, DWORD ArgVar dwFlags, DWORD, NOTUSED EnterProc VMMCall Get_Cur_VM_Handle mov eax, MB_OK AND MB_ICONHAND AND MB_APPLMODAL mov ecx, [dwRefData] mov edi, OFFSET32 [msgCaption] xor esi, esi VxDCall SHELL_Message LeaveProc Return EndProc errorReport VxD_PAGEABLE_CODE_ENDS Или этого: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> DECLARE_VIRTUAL_DEVICE MIU2, 1, 11, MIU2_Control,, UNDEFINED_INIT_ORDER VXD_LOCKED_CODE_SEG ; Функция реакций на системные уведомления BeginProc MIU2_Control Control_Dispatch SYS_DYNAMIC_DEVICE_INIT, MIU2_Init, sCall Control_Dispatch SYS_DYNAMIC_DEVICE_EXIT, MIU2_Exit, sCall Control_Dispatch DEVICE_INIT, MIU2_Init, sCall Control_Dispatch SYSTEM_EXIT, MIU2_Exit, sCall Control_Dispatch W32_DEVICEIOCONTROL, MIU2_dioc, sCall, <ebx, esi> clc ret EndProc MIU2_Control ; wrap для Signal_Semaphore_No_Switch BeginProc LCODE_Signal_Semaphore_No_Switch SCALL, ESP, HIGH_FREQ, LOCKED, PUBLIC ArgVar hSemaphore, DWORD, NOTUSED EnterProc pop eax xchg eax, [esp] VxDJmp Signal_Semaphore_No_Switch EndProc LCODE_Signal_Semaphore_No_Switch NOCHECK ; wrap для Install_IO_Handler BeginProc LCODE_Install_IO_Handler SCALL, ESP, LOCKED, PUBLIC ArgVar Port, DWORD ArgVar IOCallback, DWORD EnterProc SaveReg <esi> mov edx, [Port] mov esi, [IOCallback] VMMCall Install_IO_Handler cmc sbb eax, eax neg eax RestoreReg <esi> LeaveProc Return EndProc LCODE_Install_IO_Handler VXD_LOCKED_CODE_ENDS VXD_PAGEABLE_CODE_SEG ; wrap для VWIN32_SetWin32Event BeginProc LCODE_VWIN32_SetWin32Event, SCALL, ESP, PUBLIC, PAGEABLE ArgVar hEvent, DWORD, NOTUSED EnterProc pop eax xchg eax, [esp] VxDJmp _VWIN32_SetWin32Event EndProc LCODE_VWIN32_SetWin32Event NOCHECK ; wrap для VWIN32_CloseVxDHandle BeginProc LCODE_VWIN32_CloseVxDHandle, SCALL, ESP, PUBLIC, PAGEABLE ArgVar hEvent, DWORD, NOTUSED EnterProc pop eax xchg eax, [esp] VxDJmp _VWIN32_CloseVxDHandle EndProc LCODE_VWIN32_CloseVxDHandle NOCHECK VXD_PAGEABLE_CODE_ENDS Добавлено А то и вообще: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> DECLARE_VIRTUAL_DEVICE PCITK, PNPDRVS_Major_Ver, PNPDRVS_Minor_Ver,\ PCITK_Control,, UNDEFINED_INIT_ORDER VXD_LOCKED_CODE_SEG ; Функция реакций на системные уведомления BeginProc PCITK_Control Control_Dispatch SYS_DYNAMIC_DEVICE_INIT, PCITK_Init, sCall, <0> Control_Dispatch SYS_DYNAMIC_DEVICE_EXIT, PCITK_Exit, sCall Control_Dispatch DEVICE_INIT, PCITK_Init, sCall, <<OFFSET32 PCITK_DDB>> Control_Dispatch PNP_NEW_DEVNODE, PCITK_NewDevNode, sCall, <ebx, edx> Control_Dispatch W32_DEVICEIOCONTROL, PCITK_Win32DIOC, sCall, <ebx, esi> clc ret EndProc PCITK_Control EXTERN C signal16:near32 ;функция сигнализации в Win16-приложение EXTERN C mtxWin16:dword ;мьютекс критической секции ; callback функция для сигнализации в Win16-приложение ; C-функция, публичная, кадр стека адресуется через ESP, блокирована в памяти BeginProc LCODE_signal2win16, CCALL, PUBLIC, ESP, LOCKED LocalVar npxData, 108 ; контекс FPU EnterProc ; пролог SaveReg <edx, ebp> ; сохранение регистров VMMCall _EnterMutex, <mtxWin16, BLOCK_THREAD_IDLE> ; захват мьютекса RestoreReg <ebp, edx> ; восстановление регистров Push_Client_State ; сохранить клиентские регистры fnsave [npxData] ; сохранить контекст FPU cCall signal16, <EDX, EBP> ; вызвать C-функцию frstor [npxData] ; восстановить контекст FPU Pop_Client_State ; восстановить клиентские регистры VMMCall _LeaveMutex, <mtxWin16> ; освободить мьютекс LeaveProc ; эпилог Return ; возврат EndProc LCODE_signal2win16 VXD_LOCKED_CODE_ENDS <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> if(win16==1) Call_Restricted_Event(RESERVED_HIGH_BOOST, Get_Sys_VM_Handle(), PEF_WAIT_NOT_HW_INT | PEF_WAIT_FOR_STI, (DWORD)curHandler, LCODE_signal2win16, 0); else VWIN32_DIOCCompletionRoutine(curHandler->pOverlap.linAddr); |
Автор: Jin X 06.09.18, 17:39 |
Qraizer, ну это совсем не "почти С" Последний исходник - это уже C, а всё выше – наворочено, конечно, но похоже на FreshLib для fasm. Добавлено Вообще, знаете что я скажу? NASM - хорошая штука, хорошо сделана. Однако у fasm есть много прикольных штук, от которых не хочется отказываться (типа virtual, if used, match, load/store и пр., чего нет у NASM). Тем не менее, в fasm есть тоже много того, что лично мне не нравится (нельзя использовать include или equ в if-конструкциях, только в match; многое чего реализовано макросами, из-за чего возникает множество неудобств; нет встроенных удобных средства для переключения с секции на секцию с автоматической группировкой: .code -> .data -> .code -> .data и т.д.). Хоть реально бери и свой ассемблер пиши |
Автор: Qraizer 06.09.18, 20:09 |
Ну, ты не увидел даже четверти возможности юзаных тут макросов. Там дохрена параметров, включая декларативных. Конечно, полноценной C-грамматики там нет, но её и не надо при наличии такого количества сахара. А так... функции вообще можно на уровне C пользовать, с кучей дополнительных декларативных фишек, оптимизирующих и вызываемый, и вызывающий код, прототипирование, заголовки, параметры, аргументы, прологи, эпилоги, возвраты... В этих примерах ты ещё не видел IF/ELSE, WHILE итп, я их просто не пользовал, как-то не комильфо было, в ассемблере-то. Добавлено Качни и посмотри DDK сам, если интересно. Этим макросным сахаром там столько всего низкоуровневого приправлено... ведь работа идёт ни много ни мало с контекстами виртуальных машин, событийно управляемым исполнительным real-time окружением на приоритетах и далеко не такой дружелюбной, как WDM, ядерной архитектурой VxD. Например, вон те Push_Client_State и Pop_Client_State работают с контекстом пользовательского уровня и фактически исполняют роль монитора виртуального x86. На вот, в довесок в последнему примеру, C-функция, собственно вызывающая пользовательский обработчик события: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> // Сигнализация Win16-приложению void signal16(PIR_LIST curNode, PCRS clientReg) { // Указатель на структуру связи, подготовленную библиотеками PVOID synk= (PVOID )curNode->pOverlap.linAddr; // handle IRQ DWORD hIrq=*(PDWORD)((PBYTE)synk + 1 + sizeof(OVERLAPPED) + sizeof(DWORD)*6); // Адрес FAR-функции в Win16-приложении DWORD func=*(PDWORD)((PBYTE)synk + 1 + sizeof(OVERLAPPED) + sizeof(DWORD)*2); // Параметр для FAR-функции в Win16-приложении DWORD stat=*(PDWORD)curNode->outBuffer.linAddr; Begin_Nest_Exec(); // Начать вложенное исполнение в VM Simulate_Push(stat>>16); // Поместить в стек клиента 32-битный Simulate_Push((WORD)stat); // параметр для Win16-функции Simulate_Push(hIrq>>16); // Поместить в стек клиента 32-битный Simulate_Push((WORD)hIrq); // handle IRQ VMMCall(Disable_VM_Ints); // Запрет прерываний в VM // Установить для Win16-клиента его регистр DS clientReg->Client_DS=*(PWORD)((PBYTE)synk+1+sizeof(OVERLAPPED)+sizeof(DWORD)*3); // "Вызвать" на стеке Win16-функцию как FAR PASCAL Simulate_Far_Call((WORD)(func>>16), (WORD)func); // Возобновить исполнение в VM (с изменённым конекстом) Resume_Exec(); // Функция клиента отработала End_Nest_Exec(); // Закончить вложенное исполнение в VM } Ещё где-то был, не стал искать, виртуализация IO, на перехвате портов которая. Фреймворк очень крут. |