Механизм исключения неиспользуемых процедур из кода

Тема в разделе "WASM.ASSEMBLER", создана пользователем Jin X, 7 янв 2017.

Метки:
  1. Jin X

    Jin X Active Member

    Публикаций:
    0
    Регистрация:
    15 янв 2009
    Сообщения:
    369
    Адрес:
    Кольца Сатурна
    В отличие от языков высокого уровня, в программы на ассемблере включается весь код, который содержится в исходнике, в том числе процедуры и данные, которые реально не используются. В первую очередь, я имею в виду include-файлы, а не библиотеки (*.lib). Поэтому я решил сделать механизм, который будет исключать неиспользуемый код из финального релиза.

    Код (Text):
    1. ############################################
    2. ##                                        ##
    3. ##        -= CALLX for MASM/TASM =-       ##
    4. ##         [ v1.00 :: 07.01.2017 ]        ##
    5. ##                                        ##
    6. ##  (c) 2017 by Jin X (jin.x@sources.ru)  ##
    7. ##           http://xk7.ru/p/a/i          ##
    8. ##                                        ##
    9. ############################################
    10.  
    11. ------------------------------------------------------------------------------------------------------------------------
    12.  
    13. :: ПОДРОБНОЕ ОПИСАНИЕ ::
    14.  
    15. В отличие от языков высокого уровня, в программы на ассемблере включается весь код, который содержится в исходнике,
    16. в том числе процедуры и данные, которые реально не используются. В первую очередь, я имею в виду include-файлы, а не
    17. библиотеки (*.lib). Поэтому я решил сделать механизм, который будет исключать неиспользуемый код из финального релиза.
    18.  
    19. Данный файл callx.inc реализует механизм, который включает в код только используемые процедуры include-файлов.
    20. Для работы данного механизма необходимо включить в начало главного модуля следующие строки:
    21.  
    22.     include    callx.inc    ; механизм исключения неиспользуемых процедур из кода
    23.     usecallx        ; запустить механизм
    24.  
    25. Можно также сделать универсальный вариант, при котором программа будет компилироваться и работать даже при отсутствии
    26. файла callx.inc (если закомментировать первую строку, разумеется), однако в этом случае программа будет включать в себя
    27. все процедуры всех include-файлов. Для этого используйте следующие строки вместо приведённых выше:
    28.  
    29.     include    callx.inc    ; механизм исключения неиспользуемых процедур из кода (в случае отсутствия данного файла просто закомментируйте эту строку)
    30.     ifdef    callx_ver    ; проверка наличия callx.inc
    31.       usecallx        ; запустить механизм
    32.     else
    33.       callx        equ    call
    34.       invokex    equ    invoke
    35.     endif
    36.  
    37. Строку 'invokex equ invoke' имеет смысл добавлять только для MASM.
    38.  
    39. В include-файлы включаются следующие строки:
    40.  
    41.     include    callx.inc    ; в случае отсутствия данного файла просто закомментируйте эту строку
    42.  
    43.     ifdef    ?usecallx    ; проверка использования механизма исключения неиспользуемых процедур из кода
    44.       modulex ИмяМодуля    ; имя модуля
    45.       prelx    ИмяМодуля, Процедура, <Используемые, Процедуры>
    46.       pdefx    ИмяМодуля, <Список, Всех, Процедур>
    47.     else
    48.       pchkx        equ    <?dummy =>
    49.     endif
    50.  
    51. Действительно, данный механизм построен таким образом, что даже при отсутствии файла callx.inc программа будет
    52. компилироваться и работать, однако в этом случае она будет включать в себя все процедуры include-файла.
    53.  
    54. Итак, давайте разберёмся в этих строках...
    55.  
    56. Макрос modulex задаёт имя модуля (идентификатор include-файла ?callx_ИмяМодуля). Это нужно для проверки идентификатора
    57. включения всех процедур модуля (?inclAll_ИмяМодуля, задаваемого макросом inclx_All, см. ниже) и проверки корректности
    58. имени модуля в макросах prelx, pdefx и inclx_All.
    59. В принципе, макрос modulex можно не использовать, а макросам prelx и pdefx вместо имени модуля передать пустую строку
    60. ('prelx, Процедура, <Используемые, Процедуры>' и 'pdefx, <Список, Всех, Процедур>' - обратите внимание на запятую сразу
    61. после названия макроса), однако в этом случае использовать макрос inclx_All можно будет либо без указания имени модуля
    62. (без параметра), либо указав знак вопроса (см. ниже).
    63.  
    64. Макрос prelx создаёт зависимость первой указанной "Процедуры" от других процедур в списке.
    65. Таким образом, если "Процедура" будет включена в код, то вместе с ней будут включены и все остальные процедуры из списка.
    66. Данный макрос должен быть выполнен для каждой такой зависимой процедуры (отдельной строкой), но может и отсутствовать
    67. вовсе, если таких процедур нет.
    68.  
    69. Макрос pdefx проверяет созданные ранее идентификаторы и определяет при необходимости идентификатор исключения процедур
    70. из кода (?exclИмяПроцедуры).
    71.  
    72. * Список процедур в макросах prelx и pdefx (а также в inclx и exclx, см. ниже) можно не заключать в <угловые скобки>,
    73. но я рекомендую делать это для наглядности, чтобы отделить список процедур от имени модуля и зависимой процедуры.
    74.  
    75. Определение pchkx (через equ) задано здесь на случай отсутствия файла callx.inc (см. ниже).
    76.  
    77. Далее перед кодом каждой процедурой, для которой требуется использовать данный механизм, необходимо вставить строку:
    78.  
    79.     ifndef    ?exclИмяПроцедуры
    80.     pchkx    ИмяПроцедуры
    81.  
    82. После кода процедуры соответственно:
    83.  
    84.     endif ; ?exclИмяПроцедуры
    85.  
    86. Макрос pchkx в данном случае проверяет - указана ли процедура в списке макроса pdefx.
    87. Это сделано лишь для удобства программиста, чтобы он не забыл включить процедуру в этот список, поэтому при желании
    88. данный макрос (вместе со строками 'else' + 'pchkx equ ...' в заголовке include-файла) можно не использовать.
    89.  
    90. Такие же условные директивы ('ifndef ?exclИмяПроцедуры' + 'endif', но без макроса pchkx) можно использовать и для других
    91. необходимых для работы процедуры конструкций (например, для данных).
    92.  
    93. !!! В основном коде такие процедуры должны вызываться не с помощью call или invoke, а через макросы callx или invokex:
    94.  
    95.     callx    ИмяПроцедуры, Параметры
    96.     invokex    ИмяПроцедуры, Параметры
    97.  
    98. Конструкции, содержащие пробелы, должны быть заключены в <угловые скобки> (например, 'callx MyProc, <word ptr [bx]>'),
    99. иначе компилятор заменит пробелы запятыми.
    100.  
    101. При необходимости передачи первого параметра (например, идентификатора языка) через пробел сразу после имени процедуры,
    102. имя процедуры заключается вместе с этим параметром в <угловые скобки> (например, макрос 'callx <MyProc pascal> ax, dx'
    103. будет преобразован в вызов 'call MyProc pascal, ax, dx') !!!
    104.  
    105. Файл callx.inc и прочие указанные выше строки рекомендуется включать в начало исходника (т.е. ДО первого использования
    106. callx/invokex), а include-файлы, использующие данный механизм, должны включаться в конце главного модуля (т.е. ПОСЛЕ
    107. всех вызовов callx/invokex). Если же такой include-файл необходимо включить выше того места, где вызываются описанные
    108. в нём процедуры, то перед его включением (но после строк инициализации, указанных в начале этого текста) должен быть
    109. выполнен макрос 'inclx Список, Включаемых, Процедур, Через, Запятую' либо комбинация макросов 'inclx_All ИмяМодуля'
    110. и 'exclx Список, Исключаемых, Процедур, Через, Запятую'. В этих случаях вызывать процедуры можно стандартным образом
    111. (с помощью call/invoke, а не через макросы callx/invokex).
    112.  
    113. p.s. Макрос inclx_All можно использовать без указания имени модуля (т.е. без параметра) - в этом случае в код будут
    114. включены все процедуры всех модулей. Также можно передать макросу в качестве параметра знак вопроса ('inclx_All ?') -
    115. в этом случае в код включатся все процедуры всех безымянных модулей (не использующих modulex, см. выше).
    116.  
    117. При необходимости реализации механизма исключения неиспользуемых процедур _главного_модуля_ (а не стороннего include-
    118. файла) помимо строк 'include callx.inc' + 'usecallx' также необходимо включить следующие строки:
    119.  
    120.     modulex ИмяМодуля    ; имя модуля
    121.     prelx    ИмяМодуля, Процедура, <Используемые, Процедуры>
    122.     pdefx    ИмяМодуля, <Список, Всех, Процедур>
    123.  
    124. При этом использовать проверку 'ifdef ?usecallx' (как в include-файлах) нет никакого смысла. Если же нужно сделать
    125. универсальный вариант, при котором программа будет компилироваться и работать даже при отсутствии файла callx.inc,
    126. эти строки должны быть дополнены соответствующими проверками (похожими на те, что были приведены в начале):
    127.  
    128.     ifdef    callx_ver    ; проверка наличия callx.inc
    129.       modulex ИмяМодуля    ; имя модуля
    130.       prelx    ИмяМодуля, Процедура, <Используемые, Процедуры>
    131.       pdefx    ИмяМодуля, <Список, Всех, Процедур>
    132.     else
    133.       pchkx        equ    <?dummy =>
    134.     endif
    135.  
    136. Если макрос pchkx в главном модуле не используется, строки 'else' + 'pchkx' следует исключить.
    137.  
    138. Важно также отметить, что вызов макроса modulex может располагаться как в самом начале (вместе с usecallx), так и
    139. непосредственно перед prelx и pdefx, сами же вызовы макросов prelx и pdefx должны располагаться ПОСЛЕ всех вызовов
    140. callx/invokex, но ДО кода процедур, в которых используется данный механизм.
    141.  
    142. Для наглядной демонстрации к файлу callx.inc прилагаются примеры в папке examples (как для DOS, так и для Windows).
    143. Примеры использования механизма исключения для процедур главного модуля смотрите в папке examples\Windows (1,2,B,C,Y,Z).
    144.  
    145. ------------------------------------------------------------------------------------------------------------------------
    146.  
    147. :: ИСТОРИЯ ВЕРСИЙ ::
    148.  
    149. v1.00 (07.01.2017)
    150. [!] Самая первая версия.
    151.     Поддерживается возможность написания кода, который компилируется и работает даже при отсутствии файла callx.inc.
    152.  
    153. ------------------------------------------------------------------------------------------------------------------------
    154.  
    155. :: СВЯЗЬ С АВТОРОМ ::
    156.  
    157. Данный include-файл написан Евгением Красниковым в 2017 году.
    158. Замечания и предложения присылайте на e-mail: jin.x@sources.ru.
    159. Самую свежую версию можно скачать на сайте: http://xk7.ru/p/a/i.
    Пользуйтесь на здоровье (см. аттач)!!! :grin:
     

    Вложения:

    • callx_1.00.zip
      Размер файла:
      36,6 КБ
      Просмотров:
      391
    Mikl___, rococo795 и Alexey нравится это.
  2. Alexey

    Alexey Инициативный

    Публикаций:
    1
    Регистрация:
    28 сен 2002
    Сообщения:
    271
    Очень интересно! Скорей бы время появилось протестировать в деле) спасибо
     
  3. Jin X

    Jin X Active Member

    Публикаций:
    0
    Регистрация:
    15 янв 2009
    Сообщения:
    369
    Адрес:
    Кольца Сатурна
    Версия 1.01. Добавил пару нюансов [​IMG]
    p.s. А вот теперь думаю: а не зря ли я перевёл из кодировки Win в DOS... :blush:
     

    Вложения:

    • callx_1.01.zip
      Размер файла:
      37,2 КБ
      Просмотров:
      477
    Последнее редактирование: 10 янв 2017
  4. galenkane

    galenkane Active Member

    Публикаций:
    0
    Регистрация:
    13 янв 2017
    Сообщения:
    269
  5. Indy_

    Indy_ Well-Known Member

    Публикаций:
    4
    Регистрация:
    29 апр 2011
    Сообщения:
    4.775
    Нормально выполняется ребилд кода, он выделяется конструктором, потом пересобирается, он не должен содержать статик данных (код не отличим от данных, нельзя выделить это автоматикой и как следствие пересобрать такую смесь). Что интересно перед релизом констуктора он был сам собой пересобран в целях оптимизации.
     
  6. RET

    RET Well-Known Member

    Публикаций:
    17
    Регистрация:
    5 янв 2008
    Сообщения:
    789
    Адрес:
    Jabber: darksys@sj.ms
    Клерыч, я согласен но не полностью: "код не отличим от данных, нельзя выделить это автоматикой", а как быть с трейсом?
     
  7. Jin X

    Jin X Active Member

    Публикаций:
    0
    Регистрация:
    15 янв 2009
    Сообщения:
    369
    Адрес:
    Кольца Сатурна
    Indy_, не очень понял, про что ты говоришь, про какой конструктор.
    Насчёт применимости в отдельных случаях (если это в тему будет :popcorm1:)... вообще, программер сам должен понимать – где это можно это использовать, а где нет. Да и там есть макрос, который определяет зависимости одних идентификаторов от других: prelx. Туда можно не только процедуры записывать, но и любые другие идентификаторы (в т.ч. несуществующие, как и в pdefx), чтобы потом писать ifndef ?exclSomething...
    Главное – не запутаться, где эти макросы разместить...

    galenkane, там кодировка DOS, поэтому так всё выглядит (и ты смотришь не callx, а xmacro). Скачай просто и всё (можно из папки .all_zips).
     
    Последнее редактирование: 28 янв 2017
  8. Indy_

    Indy_ Well-Known Member

    Публикаций:
    4
    Регистрация:
    29 апр 2011
    Сообщения:
    4.775
    RET,

    Статика. Этой проблеме я очень много времени потратил, приемлемого решения нет. Есть критерии, которые позволяют с некоторой вероятностью получить результат, причём с косвенной поддержкой(фиксапы, cfg списки етц) и на длинных графах.