1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
| ############################################
## ##
## -= 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. |