(fasm) как создать список адресов меток

Тема в разделе "WASM.ASSEMBLER", создана пользователем gas, 9 июн 2011.

  1. gas

    gas New Member

    Публикаций:
    0
    Регистрация:
    10 апр 2010
    Сообщения:
    52
    Нужно в секции .data создать блок адресов меток, которые я помечу неким макросом- который я никак не могу придумать.

    Хочется чтоб выглядело так:
    метка:
    макрос_заносящий_текущий_адрес_в_список
    какой-то код
    метка:
    макрос_заносящий_текущий_адрес_в_список
    и т.д.

    Как это сделать?
     
  2. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    gas
    Именно адрес в список заносить — не самая удачная идея. Можно, конечно, сделать обычный массив двойных слов с адресами (который в том числе может быть в секции virtual), но его использование накладывает серьёзные ограничения.
    Вариант по-лучше — заносить символы (имена меток), а не адреса (значения меток) в символическую константу. Кроме того отдельный макрос для занесения в список текущего адреса, наверное, тоже не очень удобен. Проще, чтобы желаемая метка сразу и объявлялась, и заносилась в список. Например, можно переопределить директиву label. Тогда макросы будут выглядеть примерно так:
    Код (Text):
    1. struc reequ [val]
    2. {
    3.     common
    4.         tmp equ val
    5.             restore .
    6.             . equ tmp
    7.         restore tmp
    8. }
    9.  
    10. macro label [params]
    11. {
    12.     common
    13.         label params
    14.         define matched -
    15.         match name rest, params
    16.         \{
    17.             all_labels reequ all_labels,name
    18.             restore matched
    19.             define matched +
    20.         \}
    21.         match -,matched \{ all_labels reequ all_labels,params \}
    22.         restore matched
    23. }
    24.  
    25. macro storeLabels labels* { match =, lbls, labels \{ dd lbls \} }
    26.  
    27. all_labels equ
    Ну и блок адресов тогда создаётся вот так:
    Код (Text):
    1. label a
    2. jmp c
    3.  
    4. label b
    5. jmp b
    6.  
    7. label c
    8. jmp a
    9.  
    10. ;вот здесь будет создан массив двойных слов с адресами меток, объявленных через label
    11. storeLabels all_labels
     
  3. gas

    gas New Member

    Публикаций:
    0
    Регистрация:
    10 апр 2010
    Сообщения:
    52
    l_inc
    Спасибо. Но я ничего не понял. Поясни пожалуйста как этим пользоваться.
    Понятно что нужные места надо помечать через label имя_метки. А как задать место где уложится список адресов? Я попытался в секции кода написать storeLabels метка_списка, а в конце программы написал all_labels equ - не угадал.
     
  4. gas

    gas New Member

    Публикаций:
    0
    Регистрация:
    10 апр 2010
    Сообщения:
    52
    Мда... то что я в конце написал all_labels equ - это у меня мозга за мозгу заскочила.
    Надо всего-лишь в том месте где я хочу список - написать storeLabels all_labels
    l_inc, спасибо!

    А как сделать несколько подобных списков? Например, для обработки исключений, мне нужен и список всех меток кода, чтобы узнать на каком участке недопустимая операция, и список адресов ожидаемых исключений ( div, boud и т.п.)
     
  5. gas

    gas New Member

    Публикаций:
    0
    Регистрация:
    10 апр 2010
    Сообщения:
    52
    Думаю, макросы label оставить как есть - ими создавать список адресов всех меток программы. А для ожидаемых исключений сделать так:

    try ; ставится перед командой, которая может вызвать исключение
    bound eax,[указатель_на_границы]
    jmp @f
    exept
    ;код обработчика исключения, исправляющий ситуацию
    ....
    ....
    ret ;конец кода обработчика исключения
    @@: ;продолжение нормального хода программы

    Тоесь, нужно сделать макросы try и exept, совершенно без параметров, чтобы в список заносился текущий адрес без присваивания ему имени
    Можно делать отдельно список адресов try и список адресов exept, а можно и всё в одном - адрес try, следом exept и т.д.
     
  6. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    gas
    Не очень понял, в чём разница между адресом с недопустимой операцией и адресом, где ожидаются исключения.
    Не получится. Препроцессор может имена в символические константы собирать, но адреса на стадии препроцессирования ещё неизвестны. Поэтому имя присваивать надо будет, но можно сделать его локальным для макроса, чтобы препроцессор каждый раз создавал уникальное имя. Тогда собирающая символическая константа будет содержать список имён, доступных, но неизвестных за пределами макроса, которые во время ассемблирования будут раскрыты в адреса.

    P.S. Кстати, следует помнить, что директива label используется в том числе и стандартными макросами fasm, поэтому таблица с адресами меток может содержать значительно больше меток, чем Вы явно объявите. Если это не нужно, то имеет смысл переименовать макрос label.
     
  7. gas

    gas New Member

    Публикаций:
    0
    Регистрация:
    10 апр 2010
    Сообщения:
    52
    Каждому ожидаемому адресу должен соответствовать адрес обработчика, который надо будет вызвать. Обычной метке - ничего не соответствует. Если они будут в одном списке, я не узнаю что это. А так - сначала иду по списку ожидаемых, если ExceptionAddress совпал - вызов по адресу в следующей ячейке (или из другого списка обработчиков по такому же смещению). Если ничего в этом списке нет - иду по списку обычных меток, нахожу между которыми ExceptionAddress и пишу в лог-файл в какой процедуре исключение (там у меня в макросе proc-аналоге рядышком прописывается текст имени).

    Вроде из сказанного вытекает что всётки может получиться? Приписывать самому к каждой div уникальную метку не хочется...


    Да, это обязательно! Мне в списках ничего лишнего не надо.
     
  8. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    gas
    Получится сделать, как хочется, но не получится сделать, как написано. :)
    Т.е. имя присваиваться будет в любом случае (поэтому без присваивания имени не получится), но переложить работу присваивания уникального имени можно и на компилятор, просто вписав внутри макроса строку
    local [имя_которое_при_каждом_проходе_текущего_блока_макроса_будет_заменено_уникальным]
    (поэтому получится сделать, как хочется).

    P.S. Странный у Вас способ обработки исключений. Почему не использовать обычный отдельный SEH-handler для каждого блока, где возможно исключение?
     
  9. gas

    gas New Member

    Публикаций:
    0
    Регистрация:
    10 апр 2010
    Сообщения:
    52
    Наверно я мало что знаю по этому поводу, но и не хочу с этим вопросом сильно заморачиваться. Мне достаточно того что я немного нарыл на эту тему - есть виндовая функция SetUnhandledExceptionFilter - я в самом начале кода указываю один обработчик и он действует на все исключения в моём процессе. По исключению - винда даёт полную информацию, а я делаю что хочу - могу найти место где произошло исключение, или точную команду, перезагрузить регистры и продолжить (если это разрешено, как при арифметических исключениях), могу вывести своё сообщение, что-то записать в лог... Что ещё надо? чем SEH-handler лучше?
     
  10. gas

    gas New Member

    Публикаций:
    0
    Регистрация:
    10 апр 2010
    Сообщения:
    52
    Изначальный вопрос решён. Я научился делать метки, заносимые в списки и с заданием имён и без, сделал безымянные try - exept - end_exept, уже проверил всё работает, обработка исключений попадает в нужные точки, через создаваемые списки адресов, большое спасибо l_inc!
    Но я практически ничего не понял как это работает... где бы почитать по русски как работает этот самый препроцессор? (англицкий читаю туго, пока врублюсь - голова болеть начинает)
    Мне для "полного счастья" остался один вопрос - как определять данные (и неинициализируемые) прямо в том инклуде где пишется процедура?
     
  11. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    gas
    Тем, что не надо свой менеджер обработчиков со сбором адресов меток делать. В любом месте кода ставите:
    Код (Text):
    1. push exHandler
    2. push dword[fs:0]
    3. mov [fs:0],esp
    4.  
    5. ;Здесь что-то, что может вызвать исключение
    6.        
    7. pop dword[fs:0]
    8. pop eax
    , после чего в случае исключения процедура exHandler получит управление со всей необходимой информацией. Например, в указанный seh-фрейм можно добавлять адрес except-блока (т.е. push except_addr перед push exHandler) и вызывать его из общей для всех исключений процедуры exHandler.
    Я где-то когда-то видел перевод документации в виде pdf (может даже здесь выкладывали), но сейчас найти не могу, поэтому из пыльных закромов приаттачиваю к посту. Но прилагаемой к компилятору документации будет маловато для полного понимания (да и перевод достаточно старый, не содержащий описания некоторых полезных нововведений). На сайте и форуме автор постил дополнительную информацию, которая, разумеется, существует только в английском варианте.
    Не понимаю вопрос. Данные можно определять где угодно с помощью db,dw,dd и т.д.

    Файл великоват для вложения. Оставил тута.
     
  12. gas

    gas New Member

    Публикаций:
    0
    Регистрация:
    10 апр 2010
    Сообщения:
    52
    Надо этот вопрос поизучать. Но уже навскидку видно - что каждый div обрамлять этим кодом как-то нехорошо (для ожидаемых исключений). А ещё мне, в отладочных целях, нужно знать где произошло неожиданное исключение. Можно конечно обрамлять каждую процедуру и для каждой - отдельный обработчик (общий не сможет без списка адресов узнать имя процедуры). Единственный плюс вижу в том что минуется виндовс, но для большой программы - всётки гиморно. Куда проще как я задумал: о непланируемых исключениях не думать вообще - обрамил код макросами Proc Имя ..... End_Proc - это уже значит что её адрес попал в список, и в случае чего в логе окажется текстовое имя процедуры. А ожидаемые - очень элегантно как в ВУ языках try - инструкция - exept - код обработчика - end_exept.
    Кстати, непойму почему такое низкоуровневое дело назвают SEH-handler? Структурированная обработка исключений - как раз то что делают ВУ языки (хотя я их не знаю кроме васика, но хочу сделать наподобие), а mov [fs:0],esp - это - делай что хочешь и как хочешь, т.е. никакой структурности и в помине.

    Немного не так выразился - надо именованные ячейки под переменные и константы определять в секциях данных, но в любом месте где пишется код. Делать секцию кода райтибл - нехорошо.
     
  13. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    gas
    Что мешает засунуть этот код в макросы try/except? В си как раз он и генерируется этими директивами.
    Я ведь написал: "exHandler получит управление со всей необходимой информацией". Адрес исключения, тип, контекст потока, указатель на seh-frame.
    Это не обязательно. И я написал в #11, как сделать только один общий обработчик.
    Сможет. См. пост 11.
    Этого вообще не понял. SEH - это механизм, предоставляемый windows. Что ещё минуется?
    Как я уже сказал выше, через SEH всё то же самое, только не надо самому хранить метки и управлять ими.
    И второй раз тоже, видимо, не так. Шестое чувство подсказывает, что имеются в виду локальные переменные. Они описаны в разделе Windows programming -> Basic headers -> Procedures оригинальной сопроводительной документации.
     
  14. gas

    gas New Member

    Публикаций:
    0
    Регистрация:
    10 апр 2010
    Сообщения:
    52
    l_inc, я не вижу смысла в "защите" каких-то блоков кода. Если там где-то глюк - уже ничего не сделаешь, можно только записать в лог имя процедуры, или вывести сообщение. Если каждый участок кода (процедуру) таким образом "защищать" - для каждого нужен свой обработчик, он конешно безо всяких вопросов и поисков по спискам сразу знает имя процедуры... но это всё накладно - ради быстроты определения аварийной процедуры городить множество таких "защищаемых" блоков (а кому эта быстрота в случае аварии нужна?). Куда лучше иметь один обработчик на всё. Да, этот единственный, наверно, можно поставить таким образом, как Вы показали - только mov [fs:0],esp сделать один раз в начале проги, а pop dword[fs:0] - в конце. Так я наверно и сделаю, надо только разобраться где там откуда какую инфу брать ( где почитать?).
    А смысл в защите я вижу только для конкретной инструкции, при выполнение которой вероятно исключение. При стандартном подходе - каждую такую инструкцию нужно обрамлять кодом установки обработчика. Абсолютно каждое прохождение этой инструкции отнимет кучу тактов на push и pop. А при единственной на всё точке входа в обработку исключения - к исключительной инструкции добавляется только короткий jmp на перепрыг конечного обработчика (который будет найден и вызван из общей части). Небольшая задержка бутет только при исключении, в номальных случаях - пролёт со свистом.

    А я подумал что это какое-то хаккерское шаманство... Только сёравно непонятно в чём тут структурированность, и шестое чувтво мне подсказывает что она будет иметь место лишь при использовании API, а это - первый раз вижу чтоб какой-то механизм предоставляемый виндой использовался не через API.

    Локальные - это те что в стеке, адресуются по ebp и пропадают по выходу? Нет. Мне нужны локальные - относящиеся к данной процедуре, зарезервированные только ради неё, и существующие пока работает прога. Тоесь мне, пися какую-то процедуру, по каждому возникновению потребности в переменной нужно лесть в инклуд в секции неинициируемых данных. Неудобно. А когда я решу эту процедуру просто исключить из проги - могу и забыть почистить ту секцию, и там навечно останется ненужное.
     
  15. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    gas
    Здесь, например.
    Ага. Значит нужны локальные статические переменные. В стандартной поставке таких макросов нет. Но они есть, например, во freshlib\macros\_globals.inc, который можно найти здесь.
     
  16. gas

    gas New Member

    Публикаций:
    0
    Регистрация:
    10 апр 2010
    Сообщения:
    52
    Ну всё, щастье наступило! ;) А в комментариях автор забыл написать что в секциях данных надо прописать IncludeIGlobals/IncludeUGlobals
     
  17. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    gas
    Ну в комментариях есть упоминание об использовании IncludeAllGlobals. Но он завязан на другие инклуды, поэтому имеет смысл ограничиться только включением iglobal, uglobal, endg, IncludeIGlobals и IncludeUGlobals и не забыть оставить в заголовочном файле первичные вызовы iglobal и uglobal.

    Кроме того, следует помнить, что область действия таких переменных не ограничивается отдельной процедурой (т.е. хоть они и могут объявляться в любом месте, но являются всё-таки глобальными). Поэтому при использовании одинаковых имён таких переменных в разных местах кода возникнет конфликт. Не знаю, как решить эту проблему, кроме как расширением стандартных макросов proc чем-то вроде макроса statics (по аналогии с locals).
     
  18. gas

    gas New Member

    Публикаций:
    0
    Регистрация:
    10 апр 2010
    Сообщения:
    52
    Врят ли меня это сильно напряжёт. У меня своя объектно-ориентированная технология. Похожих процедур, где захотелось бы иметь одинаковые имена статических переменных - нет. А набор "методов" каждого "класса" для адресации переменных экземпляра использует ebx+смещения, сформированные макросом перед каждым кодом "класса" (набором "методов") (в кавычках пишу потому что я эту терминологию не признаю, и у меня своя другая). Так что этих имён смещений, по сути являющихся именами переменных, может быть сколько угодно одинаковых у разных "классов". Локальные переменные в стеке тоже организуются своим макросом типа locals [имена_смещений] Причём я умышленно не стал скрывать в определениях имён переменных ebp+ или ebx+, меня не напрягает писать типа mov eax,[ebx+_буфер], или mov eax,[ebp+_wparam] - так лучше ориентируешься в коде, эти "ebx+", "ebp+" воспринимаются как префиксы говорящие от том что эта переменная - статическая, а эта стековая.

    Так что меня щас в FASMе всё устраивает. Хотя... вот - было бы неплохо что б в директиве include можно было б указывать только папку, и подключалось бы все *.inc, включая вложенные папки. В алфавитном порядке. Если порядок нужен другой - не проблема задать циферьками в именах.
     
  19. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    gas
    Ну это как раз несложно: в каждой папке создать all.inc, подключающий все *.inc в текущей папке и все all.inc в папках, непосредственно содержащихся в текущей.
     
  20. gas

    gas New Member

    Публикаций:
    0
    Регистрация:
    10 апр 2010
    Сообщения:
    52
    Так я и делаю, и меня это слегка напрягает. Я часто перетасовываю, переименовываю и инклуды и папки, чтоб была более логичная и понятная структура.