Версия для печати
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум на Исходниках.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
Цитата kin01 @
реально или нет максимально приблизить синтаксис Delphi к masm с помощью макросов
Наверное, имеется в виду приблизить синтаксис 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
Цитата Jin X @
Qraizer, что за фреймворк? Есть ссылка?
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, на перехвате портов которая. Фреймворк очень крут.

Powered by Invision Power Board (https://www.invisionboard.com)
© Invision Power Services (https://www.invisionpower.com)