Локальная переменная в макросе

Тема в разделе "WASM.ASSEMBLER", создана пользователем Tupo, 26 янв 2005.

  1. Tupo

    Tupo New Member

    Публикаций:
    0
    Регистрация:
    21 янв 2005
    Сообщения:
    69
    Адрес:
    Moscow
    Как объявить в макросе "локальную" переменную(та, которая будет размещена в стеке процедуры, использующей данный макрос)?
     
  2. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    Код (Text):
    1.  
    2. @LOCAL  TEXTEQU <LOCAL>
    3.  
    4. MMM macro
    5. @LOCAL l : DWORD
    6. endm
    7.  
    8.  
    9. PPP proc
    10.     MMM
    11.     ret
    12. PPP endp
    13.  
     
  3. Tupo

    Tupo New Member

    Публикаций:
    0
    Регистрация:
    21 янв 2005
    Сообщения:
    69
    Адрес:
    Moscow
    Это, конечно, выглядит идеально, но...



    Перекос в том, что маскрос MMM всегда должен быть в начале процедуры! :dntknw:



    Если процедура будет иметь код:
    Код (Text):
    1.  
    2. PPP proc
    3.     xor eax, eax
    4.     MMM
    5.     ret
    6. PPP endp
    7.  




    то ассемблер глязно ругнётся:

    "error A2012: PROC, MACRO, or macro repeat directive must precede LOCAL"



    В этом, собственно, и подвох в вопросе - если макрос, объявляющий стековую переменную, вызывается не в начале процедуры, то возникает ошибка :dntknw:



    Как быть?
     
  4. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    Возможно кардинальное решение - использовать FASM ?
     
  5. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    Tupo

    значит суть проблемы не в макросах, а в том как объявить локальную переменную не в начале процедуры. Не знаю...

    В MASM IMHO никак.



    Если надо собирать код процедуры из кусков-макросов, каждый из которых может иметь свои локальные переменные, то можно так:


    Код (Text):
    1.  
    2. @LOCAL  TEXTEQU <LOCAL>
    3.  
    4. PROC_CHUNK MACRO defineLocals:=<0>
    5.     IF defineLocals
    6.    
    7. ;   chunk locals using @LOCAL ...
    8.    
    9.     ELSE
    10.    
    11. ;   chunk code
    12.    
    13.     ENDIF
    14.  
    15.     ENDM
    16.  
    17.  
    18.  
    19. PPP proc
    20.     PROC_CHUNK1 <1>
    21.     PROC_CHUNK2 <1>
    22. ;   ...
    23. ;   proc code...
    24.  
    25.     PROC_CHUNK1
    26.  
    27. ;   proc code...
    28.  
    29.     PROC_CHUNK2
    30. ;   ...
    31.  
    32.    
    33. PPP endp
    34.  
    35.  




    Коряво конечно...
     
  6. Tupo

    Tupo New Member

    Публикаций:
    0
    Регистрация:
    21 янв 2005
    Сообщения:
    69
    Адрес:
    Moscow
    S_T_A_S_



    Если это в FASM'е решаемо ;)

    Приведи пример.



    green





    Я решил проблему путем имитации пролога/эпилога - получается что-то вроде "процедура-внутри-макроса".



    Выглядит это так:
    Код (Text):
    1.  
    2. SSS struct
    3.     fld1    DWORD   ?
    4.     fld2    DWORD   ?
    5. SSS ends
    6.  
    7. MMM1    macro
    8.     push    ebp
    9.     mov ebp, esp
    10.     sub esp, sizeof SSS
    11.  
    12.     mov [ebp+SSS.fld1], 1
    13.     mov [ebp+SSS.fld2], 2
    14.     push    2
    15.     push    ebp
    16.     push    1
    17.     call    anyFUNC
    18.  
    19.     mov esp, ebp
    20.     pop ebp
    21.     endm
    22.  


    В MASM макросы пролога/эпилога можно отменять и/или переписывать, а вот имеется ли возможность использовать пролог/эпилог вне proc?



    Вопрос локальных переменных в макросах поднял в надежде мож у кого имеется более "красивое" решение.
     
  7. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    Tupo



    а я думал, что вся соль именно в том, чтобы возложить на транслятор заботы о локальных переменных...
     
  8. Tupo

    Tupo New Member

    Публикаций:
    0
    Регистрация:
    21 янв 2005
    Сообщения:
    69
    Адрес:
    Moscow
    Вот чтобы переложить заботу требуется переназначить макросы эпилога/пролога и вызывать их(если такое возможно) напрямую.



    Тут, в частности эти макросы "поминают":

    http://wasm.ru/forum/index.php?action=vthread&topic=1479&forum=4&page=-1



    Это как вариант, конечно.



    Ведь "процедурный" LOCAL в макросе невозможно использовать, равно как и в любом месте процедуры.



    LOCAL по сути объявляет переменные, то есть вычисляет смещения для ebp (var equ [ebp+offset]) и подсчитывает размер кадра стека под локальные переменные.

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



    Поэтому использование enter/leave - пока что самое оптимальное что я нашел.
     
  9. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    Tupo >




    Да, решаемо (и не только это) - в fasm нужно самостоятельно делать макросы для пролога/эпилога, поэтому можно реализовть всё что угодно :)



    >




    Готового решения вроде нет. Посмотри макросы JohnFound'а - они объявляют "перекрывающиеся" локальные переменные, если нужны "неперекрывающиеся", то imho можно немного доработать.



    Вообще, мне пока не совсем ясно зачем это нужно, но по собственному опыту могу сказать - пытаться реализовать что-то выходящее за рамки стандартных proc/endp в masm на макросах - пустая трата времени.
     
  10. Tupo

    Tupo New Member

    Публикаций:
    0
    Регистрация:
    21 янв 2005
    Сообщения:
    69
    Адрес:
    Moscow
    S_T_A_S_





    Делать макросы для пролога/эпилога можно и в MASM ;)

    Доказательством тому -> MASM32 :P



    А вот пример ты так и не привел ;)





    В том топике обсуждается создание нескольких кадров стека под локальные переменные для процедуры.



    Несколько кадров стека в одной процедуре?

    - А оно надо? Если я могу все локальные переменные объявить в самом начале процедуры.



    Возможность динамически менять размер этого кадра, добавляя новые локальные переменные "на лету"? -

    Сомнительная фишка, так как по окончанию процедуры стек высвобождаяется. Так стоят ли делать все эти манимапуляции со стеком или проще в начале процедуры выделить кадр стека необходимого размера сразу под все локальные переменные? ;)







    Упс, моя вина! Забыл указать причину.



    Исправляю ошибку:

    При написании плагина на асме под API какой-либо программы, часто встречаю способ управления внутренними(экспортируемыми через API) функциями программы - через управляющую структуру.



    То есть одним из аргументов такой функции является "управляющая" структура.



    Бываю, конечно, различные варианты.



    Как пример, формат структуры меняется взависимости от значения одного из аргументов этой функции.

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



    На C реализация такого способа взаимодействия с плагинами выполняется очень просто - определение функции содержит в себе заполнение управляющей структуры плюс вызов "точки входа"(вызов экспортируемой функции).



    Подобный подход очень удобен - нужно лишь позаботиться о наличии данных для функции, а уж о формате/названии служебной стуктуры и значении(пусть даже именованном) "код команды" для экспортируемой функции позаботится само определение функции. От программиста лишь требуется знать название "конечной" функции и необходимые для неё входные параметры.



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



    Так как таких экспортируемых функций обычно больше одной и не каждая из них требует наличия управляющей структуры, то контролировать(объявлять и заполнять самому) такие структуры утомительно :dntknw:



    Вот я и думаю, как подобное можно реализовать на асме.

    Возможно у кого-то есть уже готовое решение. ;)
     
  11. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    Tupo >




    В самом пакете теперь появились примеры что ли? (я давно его не качал)

    А вообще, попробуй сделать стэковый фрейм без ebp - т.е. обращение к локальным переменным через esp :derisive:



    >




    Нет, на самом деле кадр один и размер его не меняется - он равен наибольшему из "локальных" фреймов. Это что-то вроде UNION для локальных переменных. Например, какая-то переменная используется только в начале ф-ции - можно дальше её старое место в стэке объявить для другой локальной переменной (MSVC любит так делать, кстати)



    Вообще, я имел ввиду, что эти макросы можно подправить - UNION'ов не будет, а будет как раз аналог LOCAL, не только в самом начале, а в любом месте ф-ции, но при этом
    будет выделен как обычно, в начале один раз :derisive:





    >




    Гм, что-то я не могу припомнить чего-то кардинально отличающегося от stdcall/fastcall/thiscall (упс, это уже не Си) & co. Вроде всё, на что способен компилятор - положить несколько двордов в стэк, ну может пару в ecx & edx.....





    Так, кажется теперь до меня начинает доходить смысл MMM1 macro

    Но зачем там "mov [ebp+SSS.fld1], 1" ?



    Можно же делать так:
    Код (Text):
    1.  
    2. MMM1    macro
    3.  
    4.         push    2   ;mov    [ebp+SSS.fld2], 2
    5.     push    1   ;mov    [ebp+SSS.fld1], 1
    6.     mov edx, esp
    7.  
    8.     push    2
    9.     push    edx
    10.     push    1
    11.     call    anyFUNC
    12.  
    13.     pop edx
    14.     pop edx
    15.  
    16.     endm
    17.  
    Это меньше по размеру и ничего страшного, что каждый раз выделяется "локальный фрейм" - push однобайтная команда (не считая операнда), а mov на 2-3 байта больше! Если я правильно понял что нужно, то такой способ IMHO лучше (хотя С компиляторы так и не делают - на такое они не способны ;)
     
  12. Tupo

    Tupo New Member

    Публикаций:
    0
    Регистрация:
    21 янв 2005
    Сообщения:
    69
    Адрес:
    Moscow




    Нет, конечно, примеров там нет. Я о другом, сам пакет MASM32 v8 - хороший пример того, что в MASM'e с помощью макросов можно переписать абсолютно всё.



    С каждой новой версией, исходники под MASM32 всё больше напоминают программу на Си... ;)

    ...что нарушает концерцию самого ассемблера. Лично я привык держать всё под контролем(до сих пор пушами передаю параметры виндовым функциям) :)







    Да, будет выделена общая область в стеке, но навигация по этой области будет как по вложенным кадрам стека, а не как по единому кадру или я не правильно понял этот рисунок:
    Код (Text):
    1. Frame structure:
    2. ~~~~~~~~~~~~~~~~
    3. +----+ ---------> [ebp - Frame1 - commsize]
    4. |    | Frame 1
    5. |    |----+ ----------> [ebp-Frame2-commsize]
    6. |    |    | Frame 2
    7. |    |    |----+ ---------> [ebp-Frame3-commsize]
    8. |    |    |    | Frame 3
    9. +--------------+ ---------> [ebp-commsize]
    10. |              | Frame, that is common for
    11. |              | entire procedure.
    12. +--------------+ -------------------> [ebp]
    13. |              | Arguments
    14. +--------------+ ------> [ebp+Arguments]
    15.  




    Хотя... с кем я спорю? ;)

    http://www.wasm.ru/forum/index.php?action=vthread&forum=19&topic=6557









    Это я для наглядности так написал, а сделал именно так как твоём примере.

    Хотя, следует заметить, что push хорош до тех пор, пока размер поля в структуре равен DWORD ;)



    Но... как верно отметил green:



    Похоже, что этого сделать нельзя :\



    И в твоей макробиблиотеке, и в моем решении данной проблемы лежит алгоритм старой доброй команды enter :)
     
  13. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    Tupo >




    IMHO "абсолютно всё" - немного преувеличено :derisive:

    это даже в fasm не возможно :-(



    >




    Вот только результирующий код в последнем случае часто получается лучше, чем после тучи встроенных в masm макрооператоров вроде .if :-(



    >




    "Навигация" будет по единому кадру - всякие "Frame2-commsize" вычисляются на момент компилязии, и ebp меняется только 2 раза - в прологе и эпилоге ф-ции.



    >




    Если размер байт, то всё равно можно push'ить dword, если 2 или 4 байта - объединять их макросом, это в masm даже проще реализуется. Если же нужны какие-нибудь double, тогда... лучше использовать fasm :)



    >




    Всё же до сих пор не совсем понял, какой именно нужен контроль... но уверен что реализуемо в fasm - умеет же он вычислять адресацию к переменным через esp с учётом изменения этого регистра push / pop (в моей мракобиблиотеке как раз нет аналогов enter - ebp вообще не используется при обращении к параметрам и локальным переменным функций)



    Возможно, что эти макросы я и реализую, только мне нужно для начала понять, что они должны делать. Если же будешь разбираться сам, то смотри ещё \fasm\INCLUDE\MACRO\STDCALL.INC , а так же аналогичные из Fresh.

    Мне, кстати, потребовалось некоторое время, что бы понять, как это вообще работает =) основная проблема как раз в том, что голова была забита masm. В fasm на первый взгляд макросы сложнее, но это не так - писАть может быть и больше, зато это вроде "программируемого препроцессора" - возможности очень большие. Только нужно представлять, на какой стадии что обрабатывается. В общем, если будут вопросы по fasm - пиши.
     
  14. Tupo

    Tupo New Member

    Публикаций:
    0
    Регистрация:
    21 янв 2005
    Сообщения:
    69
    Адрес:
    Moscow


    Тут как раз преувеличения нет.

    И доказательство тому есть прямо в пакете MASM - загляни в cmacros.inc ;)



    Проблема в другом - макроязык несколько угловат.

    Пока решаешь задачи типа повторяющихся блоков команд - проблем не возникает. Но стоит копнуть глубже... Этот топик тому пример. :\







    Вот-вот, и я о том же ;)







    Прекрасно.



    Но хочу обратить твоё внимание на один(и пожалуй, главный) нюанс:

    Работа макросов JohnFound'а описывается внутри контекста процедуры! Именно процедуры, а не макроса.



    Я же говорю про локальные(стековые) переменные объявленные в макросе.



    Не факт, что всемогущий FASM такое переварит ;)



    Я подозреваю, что имеется ограничение на такие переменные для макросов из-за одного существенного отличия макроса от процедуры:

    Макросы допускают вложения других макросов, а

    процедуры не допускают вложения других процедур.





    Чтобы были вопросы, нужно для начала начать им пользоваться. :)

    Не так-то легко менять среду программирования. ;)
     
  15. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    Tupo >




    Прицепи сюда, если не сложно (в моём пакете masm32 v8 этого похоже нет)



    >




    _Самый_ главный нюанс такой: в fasm _нет_ процедур :) все эти proc, endp - это всего лишь макросы.

    Поэтому ограничения накладывает их разработчик. Да, proc/endp из стандартной поставки не позволяют делать вложенные процедуры, но никто не мешает реализовать такую возможность.

    А поскольку, с вложением макросов проблем нет (хотя этот механизм работает не так как в masm - нет рекурсивного вызова макросов, зато можно переопределять макрос сколько угодно раз) то можно использовать макросы, объявляющие стэковые переменные внутри других макросов, те внутри третьих и т.п.

    Просто взять макросы JohnFound'а и засунуть их вонутрь других - никаких проблем. Покомпилируй примеры, посмотри под отладчиком что там получается со стэком, мне уже кажется, что их даже переделывать не нужно :)



    >




    Это верно, но чем дальше, тем сложнее это будет сделать :derisive:

    (А потом начнут проявлятья его глюки.....)
    Код (Text):
    1. foo macro   arg
    2. exitm <0>
    3. endm
    4.  
    5. db foo( "LOL, masm is too buggy :-)" )
    6. db foo( ":-(" )
     
  16. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    S_T_A_S_

    я запостил твой пример Микрософту. Может поправят. :)
     
  17. Tupo

    Tupo New Member

    Публикаций:
    0
    Регистрация:
    21 янв 2005
    Сообщения:
    69
    Адрес:
    Moscow
    S_T_A_S_





    А там его и нету. ;)

    Он входит в пакет от Микрософта MASM v6.10



    Вечером прилеплю. Сейчас с работы пишу, а тут у меня усеченная версия - ml(+ml.err), link(+mspdb50.dll), res(+rcdll.dll) и немного lib'ов ;)





    Дык в MASM'е тоже нет процедур :Р

    proc, endp, local и т.д. - это _встроенные_ макросы.



    Вот простейшая программа под Windows:


    Код (Text):
    1. _start: ret
    2. END _start




    В MASM'е встроенные макросы переписать нельзя, но... ничто не мешает добавить "." или "_" или "?" перед названиям этих макросов и написать свои.



    cmacros.inc как раз и содержит эти встроенные макросы на макроязыке.

    Насколько я помню, этот файл использовался для обработки асм-исходников, которые генерировал в те далекие времена С-транслятор. Это ныне С-трансляторы сразу(как минимум) obj-файл выплевывают ;)



    Откуда по-твоему у авторов некоторых статей имеются такие грубокие познания о том как работает, к примеру, @CatStr ;)





    Дык я уж более 12 лет на MASMе пишу :Р









    Это не так легко, когда имеем структуру



    SSS struct

    var1 BYTE ?

    var2 DWORD ?

    var3 WORD ?

    SSS ends



    При этом, var2 и var3 - это структура, входящая в список UNION ;)

    А в том списке имеются:

    BYTE

    WORD

    DWORD

    DWORD+WORD

    WORD+DWORD



    "Дешевле" вычесть длину стуктуры, выровненную до 4 из указателя стека и затем мувами заносить значения.
     
  18. Tupo

    Tupo New Member

    Публикаций:
    0
    Регистрация:
    21 янв 2005
    Сообщения:
    69
    Адрес:
    Moscow
    Вот вся папка INCLUDE из MASM v6.10

    Кроме файла win.inc - он был сделан с помощью утилиты H2INC и интереса не представляет.



    Изучив содержимое этих inc-файлов можно легко создать свой ассемблер и назвать его, к примеру, SASM ;)





    [​IMG] _542984380__INCLUDE.rar
     
  19. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    green >




    Врядли :) На сколько я понимаю, это не баг, а flaw design препроцессора.





    Tupo >




    А, это у меня есть, и я даже сам как-то кидал на Θорум :)))



    >




    IMHO это просто для создания asm кода, который может вызывать/быть вызван из разных HLL (стандартные макросы это только stdcall)



    >




    Что-то структура какая-то неудачно надуманная - Си компилеры выравнивает все данные по границе кратной размеру, так что в реальном мире думаю такого не будет. Лучше покажи HLL вариант.



    >




    Дык это не ассемблер получится, а "парсер" =) Если делать front-end, то явно лучше ориентироваться на fasm, т.к он многопроходный в отличае от masm. front-end мне не очень интересен, если когда-нибудь будет доведён до потребного состояния STASM, то кодогенератор там будет свой =)
     
  20. Tupo

    Tupo New Member

    Публикаций:
    0
    Регистрация:
    21 янв 2005
    Сообщения:
    69
    Адрес:
    Moscow




    Ну зачем мне структуры выдумывать? :)



    Эта структура что ни на есть самая ходовая при работе с БД Миранды ;)



    Вот:
    Код (Text):
    1. typedef struct {
    2.     BYTE type;
    3.     union {
    4.         BYTE bVal; char cVal;
    5.         WORD wVal; short sVal;
    6.         DWORD dVal; long lVal;
    7.         struct {
    8.             char *pszVal;
    9.             WORD cchVal;
    10.         };
    11.         struct {
    12.             WORD cpbVal;
    13.             BYTE *pbVal;
    14.         };
    15.     };
    16. } DBVARIANT;