В отличие от языков высокого уровня, в программы на ассемблере включается весь код, который содержится в исходнике, в том числе процедуры и данные, которые реально не используются. В первую очередь, я имею в виду include-файлы, а не библиотеки (*.lib). Поэтому я решил сделать механизм, который будет исключать неиспользуемый код из финального релиза. Код (Text): ############################################ ## ## ## -= CALLX for MASM/TASM =- ## ## [ v1.00 :: 07.01.2017 ] ## ## ## ## (c) 2017 by Jin X (jin.x@sources.ru) ## ## http://xk7.ru/p/a/i ## ## ## ############################################ ------------------------------------------------------------------------------------------------------------------------ :: ПОДРОБНОЕ ОПИСАНИЕ :: В отличие от языков высокого уровня, в программы на ассемблере включается весь код, который содержится в исходнике, в том числе процедуры и данные, которые реально не используются. В первую очередь, я имею в виду include-файлы, а не библиотеки (*.lib). Поэтому я решил сделать механизм, который будет исключать неиспользуемый код из финального релиза. Данный файл callx.inc реализует механизм, который включает в код только используемые процедуры include-файлов. Для работы данного механизма необходимо включить в начало главного модуля следующие строки: include callx.inc ; механизм исключения неиспользуемых процедур из кода usecallx ; запустить механизм Можно также сделать универсальный вариант, при котором программа будет компилироваться и работать даже при отсутствии файла callx.inc (если закомментировать первую строку, разумеется), однако в этом случае программа будет включать в себя все процедуры всех include-файлов. Для этого используйте следующие строки вместо приведённых выше: include callx.inc ; механизм исключения неиспользуемых процедур из кода (в случае отсутствия данного файла просто закомментируйте эту строку) ifdef callx_ver ; проверка наличия callx.inc usecallx ; запустить механизм else callx equ call invokex equ invoke endif Строку 'invokex equ invoke' имеет смысл добавлять только для MASM. В include-файлы включаются следующие строки: include callx.inc ; в случае отсутствия данного файла просто закомментируйте эту строку ifdef ?usecallx ; проверка использования механизма исключения неиспользуемых процедур из кода modulex ИмяМодуля ; имя модуля prelx ИмяМодуля, Процедура, <Используемые, Процедуры> pdefx ИмяМодуля, <Список, Всех, Процедур> else pchkx equ <?dummy => endif Действительно, данный механизм построен таким образом, что даже при отсутствии файла callx.inc программа будет компилироваться и работать, однако в этом случае она будет включать в себя все процедуры include-файла. Итак, давайте разберёмся в этих строках... Макрос modulex задаёт имя модуля (идентификатор include-файла ?callx_ИмяМодуля). Это нужно для проверки идентификатора включения всех процедур модуля (?inclAll_ИмяМодуля, задаваемого макросом inclx_All, см. ниже) и проверки корректности имени модуля в макросах prelx, pdefx и inclx_All. В принципе, макрос modulex можно не использовать, а макросам prelx и pdefx вместо имени модуля передать пустую строку ('prelx, Процедура, <Используемые, Процедуры>' и 'pdefx, <Список, Всех, Процедур>' - обратите внимание на запятую сразу после названия макроса), однако в этом случае использовать макрос inclx_All можно будет либо без указания имени модуля (без параметра), либо указав знак вопроса (см. ниже). Макрос prelx создаёт зависимость первой указанной "Процедуры" от других процедур в списке. Таким образом, если "Процедура" будет включена в код, то вместе с ней будут включены и все остальные процедуры из списка. Данный макрос должен быть выполнен для каждой такой зависимой процедуры (отдельной строкой), но может и отсутствовать вовсе, если таких процедур нет. Макрос pdefx проверяет созданные ранее идентификаторы и определяет при необходимости идентификатор исключения процедур из кода (?exclИмяПроцедуры). * Список процедур в макросах prelx и pdefx (а также в inclx и exclx, см. ниже) можно не заключать в <угловые скобки>, но я рекомендую делать это для наглядности, чтобы отделить список процедур от имени модуля и зависимой процедуры. Определение pchkx (через equ) задано здесь на случай отсутствия файла callx.inc (см. ниже). Далее перед кодом каждой процедурой, для которой требуется использовать данный механизм, необходимо вставить строку: ifndef ?exclИмяПроцедуры pchkx ИмяПроцедуры После кода процедуры соответственно: endif ; ?exclИмяПроцедуры Макрос pchkx в данном случае проверяет - указана ли процедура в списке макроса pdefx. Это сделано лишь для удобства программиста, чтобы он не забыл включить процедуру в этот список, поэтому при желании данный макрос (вместе со строками 'else' + 'pchkx equ ...' в заголовке include-файла) можно не использовать. Такие же условные директивы ('ifndef ?exclИмяПроцедуры' + 'endif', но без макроса pchkx) можно использовать и для других необходимых для работы процедуры конструкций (например, для данных). !!! В основном коде такие процедуры должны вызываться не с помощью call или invoke, а через макросы callx или invokex: callx ИмяПроцедуры, Параметры invokex ИмяПроцедуры, Параметры Конструкции, содержащие пробелы, должны быть заключены в <угловые скобки> (например, 'callx MyProc, <word ptr [bx]>'), иначе компилятор заменит пробелы запятыми. При необходимости передачи первого параметра (например, идентификатора языка) через пробел сразу после имени процедуры, имя процедуры заключается вместе с этим параметром в <угловые скобки> (например, макрос 'callx <MyProc pascal> ax, dx' будет преобразован в вызов 'call MyProc pascal, ax, dx') !!! Файл callx.inc и прочие указанные выше строки рекомендуется включать в начало исходника (т.е. ДО первого использования callx/invokex), а include-файлы, использующие данный механизм, должны включаться в конце главного модуля (т.е. ПОСЛЕ всех вызовов callx/invokex). Если же такой include-файл необходимо включить выше того места, где вызываются описанные в нём процедуры, то перед его включением (но после строк инициализации, указанных в начале этого текста) должен быть выполнен макрос 'inclx Список, Включаемых, Процедур, Через, Запятую' либо комбинация макросов 'inclx_All ИмяМодуля' и 'exclx Список, Исключаемых, Процедур, Через, Запятую'. В этих случаях вызывать процедуры можно стандартным образом (с помощью call/invoke, а не через макросы callx/invokex). p.s. Макрос inclx_All можно использовать без указания имени модуля (т.е. без параметра) - в этом случае в код будут включены все процедуры всех модулей. Также можно передать макросу в качестве параметра знак вопроса ('inclx_All ?') - в этом случае в код включатся все процедуры всех безымянных модулей (не использующих modulex, см. выше). При необходимости реализации механизма исключения неиспользуемых процедур _главного_модуля_ (а не стороннего include- файла) помимо строк 'include callx.inc' + 'usecallx' также необходимо включить следующие строки: modulex ИмяМодуля ; имя модуля prelx ИмяМодуля, Процедура, <Используемые, Процедуры> pdefx ИмяМодуля, <Список, Всех, Процедур> При этом использовать проверку 'ifdef ?usecallx' (как в include-файлах) нет никакого смысла. Если же нужно сделать универсальный вариант, при котором программа будет компилироваться и работать даже при отсутствии файла callx.inc, эти строки должны быть дополнены соответствующими проверками (похожими на те, что были приведены в начале): ifdef callx_ver ; проверка наличия callx.inc modulex ИмяМодуля ; имя модуля prelx ИмяМодуля, Процедура, <Используемые, Процедуры> pdefx ИмяМодуля, <Список, Всех, Процедур> else pchkx equ <?dummy => endif Если макрос pchkx в главном модуле не используется, строки 'else' + 'pchkx' следует исключить. Важно также отметить, что вызов макроса modulex может располагаться как в самом начале (вместе с usecallx), так и непосредственно перед prelx и pdefx, сами же вызовы макросов prelx и pdefx должны располагаться ПОСЛЕ всех вызовов callx/invokex, но ДО кода процедур, в которых используется данный механизм. Для наглядной демонстрации к файлу callx.inc прилагаются примеры в папке examples (как для DOS, так и для Windows). Примеры использования механизма исключения для процедур главного модуля смотрите в папке examples\Windows (1,2,B,C,Y,Z). ------------------------------------------------------------------------------------------------------------------------ :: ИСТОРИЯ ВЕРСИЙ :: v1.00 (07.01.2017) [!] Самая первая версия. Поддерживается возможность написания кода, который компилируется и работает даже при отсутствии файла callx.inc. ------------------------------------------------------------------------------------------------------------------------ :: СВЯЗЬ С АВТОРОМ :: Данный include-файл написан Евгением Красниковым в 2017 году. Замечания и предложения присылайте на e-mail: jin.x@sources.ru. Самую свежую версию можно скачать на сайте: http://xk7.ru/p/a/i. Пользуйтесь на здоровье (см. аттач)!!!
Версия 1.01. Добавил пару нюансов p.s. А вот теперь думаю: а не зря ли я перевёл из кодировки Win в DOS...
Нормально выполняется ребилд кода, он выделяется конструктором, потом пересобирается, он не должен содержать статик данных (код не отличим от данных, нельзя выделить это автоматикой и как следствие пересобрать такую смесь). Что интересно перед релизом констуктора он был сам собой пересобран в целях оптимизации.
Клерыч, я согласен но не полностью: "код не отличим от данных, нельзя выделить это автоматикой", а как быть с трейсом?
Indy_, не очень понял, про что ты говоришь, про какой конструктор. Насчёт применимости в отдельных случаях (если это в тему будет )... вообще, программер сам должен понимать – где это можно это использовать, а где нет. Да и там есть макрос, который определяет зависимости одних идентификаторов от других: prelx. Туда можно не только процедуры записывать, но и любые другие идентификаторы (в т.ч. несуществующие, как и в pdefx), чтобы потом писать ifndef ?exclSomething... Главное – не запутаться, где эти макросы разместить... galenkane, там кодировка DOS, поэтому так всё выглядит (и ты смотришь не callx, а xmacro). Скачай просто и всё (можно из папки .all_zips).
RET, Статика. Этой проблеме я очень много времени потратил, приемлемого решения нет. Есть критерии, которые позволяют с некоторой вероятностью получить результат, причём с косвенной поддержкой(фиксапы, cfg списки етц) и на длинных графах.