Assembler / P18
.pdf18. Битовые операции
18.1. Булевские команды
Эти команды оперируют с отдельными битами ячейки, независимо от других битов
ячейки. |
|
|
Инвертировать |
not opr |
opr opr |
"ИЛИ" (дизъюнкция) |
or dst,src |
dst dst src |
"И" (конъюнкция) |
and dst,src |
dst dst src |
"Исключающее ИЛИ" |
xor dst,src |
dst dst src |
Логическое сравнение |
test opr1,opr2 |
opr1 opr2 |
Команда not на флаги не действует, остальные команды сбрасывают CF и OF, а флаги SF, ZF, PF изменяют по обычным правилам. Рассмотрим серию примеров, иллюстрирующих работу этих команд.
Пример. Команда инвертирования битов. Операция НЕ применяется к каждому биту.
mov al, 10011101b |
; |
AL = 9Dh |
not al |
; |
AL = 01100010b = 62h |
Остальные команды двухоперандные. Обычно они используются по следующей схеме. В источник src помещается так называемая "маска" — непосредственный операнд. Маска указывает, как изменять биты приемника.
Пример. Установка и сброс битов в соответствии с маской.
1) В регистре DL установить 6-й, 3-й и 1-й биты. Применяем дизъюнкцию с маской, используя правила поглощения
маска |
0 |
1 |
0 |
0 |
1 |
0 |
1 |
0 |
|
||
DL |
b7 |
b6 |
b5 |
b4 |
b3 |
b2 |
b1 |
b0 |
|
||
DL маска |
b7 |
1 |
b5 |
b4 |
1 |
b2 |
1 |
b0 |
|||
Команда имеет вид or dl, 01001010b (или or dl, 4Ah). |
|
|
|
|
|||||||
2) В регистре CH сбросить 4-й и 3-й биты. Применяем конъюнкцию с маской, используя |
|||||||||||
правила поглощения 1 b b, 0 b 0. |
|
|
|
|
|
|
|
|
|||
маска |
1 |
1 |
1 |
0 |
0 |
1 |
1 |
1 |
|
||
CH |
b7 |
b6 |
b5 |
b4 |
b3 |
b2 |
b1 |
b0 |
|
||
CH маска |
b7 |
b6 |
b5 |
0 |
0 |
b2 |
b1 |
b0 |
|||
Команда and ch,11100111b (или and ch,0E7h). |
|
|
|
|
|
|
|||||
3) Инвертировать 4-й и 3-й биты регистра BH. Применяем "исключающее ИЛИ", |
|||||||||||
используя правила 1 b b, 0 b b. |
|
|
|
|
|
|
|
|
|||
маска |
0 |
0 |
0 |
1 |
1 |
0 |
0 |
0 |
|
|
|
CH |
|
b7 b6 b5 |
b4 |
b3 |
b2 b1 b0 |
|
|||||
CH маска |
|
b7 b6 b5 |
b4 |
b3 |
b2 |
b1 |
b0 |
||||
Команда xor ch,11000b (или xor ch,18h). |
|
|
|
|
|
|
|||||
Команда xor применяется для обнуления регистров: |
код xor |
ax,ax короче, чем |
mov ax, 0 (проверьте!).
Пример [The Assembly Gems Pages. http://www.df.lth.se/~john_e/]. Вычисление абсолютной величины для содержимого AX без ветвлений.
cwd
xor ax,dx sub ax,dx
Самостоятельно разберите этот фрагмент.
Вместо команды
cmp ax,0 ; AX = 0 ?
предпочитают использовать более короткие команды and ax,ax или or ax,ax. Они оставляют содержимое AX неизменным, но устанавливают или сбрасывают флаг ZF.
Команду test используют, чтобы проверить, установлен ли определенный бит операнда, и при этом не "испортить" операнд.
Пример. Установлен ли 5-й бит DL? Если ДА, перейти на метку m. test dl,00100000b
jnz m
С помощью этой команды легко проверить делимость числа на степени двойки. Например, если два младших бита числа — нули, то оно делится на 4:
test cx, 11b jz yes
18.2. Команды сдвигов
Эти команды перемещают содержимое ячейки влево или вправо. Одним из операндов этих команд является количество сдвигов cnt. Оно либо равно 1, либо определяется содержимым регистра CL (при этом CL сохраняет свое содержимое после операции). Начиная с 286 процессора количество сдвигов, отличное от единицы, можно указывать как непосредственный операнд.
Естественно, возникает вопрос (для определенности говорим о сдвиге на одну позицию вправо): куда девается младший бит (точнее, его содержимое)? что записывается в старший бит? В командах сдвига эти вопросы решаются по-разному.
18.2.1. Логические и арифметические сдвиги.
Логический/арифметический |
|
|
|
|
|
|
|||||||||
сдвиг влево |
|
|
|
|
shl/sal opr,cnt |
||||||||||
(Shift Logical/Arithmetic Left) |
|
|
|
|
|
|
|||||||||
|
CF |
|
opr |
|
|
|
|
|
|
||||||
|
|
|
|
|
|
|
|
|
|
|
|
0 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
||||||
|
|
|
|
|
|
|
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Логический сдвиг вправо |
|
|
|
|
|
shr opr,cnt |
|||||||||
(Shift Logical Right) |
|
|
|
|
|
||||||||||
|
|
|
|
|
|
|
|
||||||||
|
|
|
|
|
|
|
|
opr |
|
|
|
CF |
|||
0 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Арифметический сдвиг вправо |
|
|
|
sar opr,cnt |
|||||||||||
(Shift Arithmetic Right) |
|
|
|
|
|
||||||||||
|
|
|
|
|
|
|
|
||||||||
|
|
|
|
|
|
|
|
opr |
|
|
|
CF |
|||
|
|
|
|
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Флаг CF устанавливается в соответствии с рисунками. Флаг OF имеет смысл , если cnt
= 1.
Сначала остановимся на формальном синтаксисе команд.
Неправильно |
Правильно |
1) sar ax,2 (в 286 и выше — правильно!) |
1) mov cl,2 |
|
|
|
sar ax,cl |
|
|
2) mov bl,3 |
2) shl ax,1 |
shr dx,bl (количество сдвигов только в CL) |
|
Арифметические сдвиги предназначены для выполнения умножения и деления на степени двойки (табл.6.1).
|
|
Таблица 6.1 |
|
операнд |
умножение |
деление |
|
знаковый |
sal/shl |
sar |
|
беззнаковый |
shr |
||
|
Умножение на 2 — сдвиг влево и приписывание справа нуля. Докажите, что OF = CF
SF.
Деление на 2 — сдвиг вправо, в CF попадает остаток от деления. При арифметическом сдвиге вправо дублируется знаковый бит: поэтому отрицательное число остается отрицательным.
Пример. Пусть AL = –120 = 10001000. sar al,1 дает AL = –60 = 11000100.
Проверьте.
К сожалению, результат деления с помощью команды sar не всегда совпадает с результатом деления, полученным с помощью команды idiv. Сравните результат от деления –5 на 2, полученный с помощью и той и другой команды.
18.2.2. Циклические сдвиги.
Циклический сдвиг влево |
rol opr,cnt |
|
(ROtate Left) |
||
|
CF opr
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Циклический сдвиг вправо |
|
|
ror opr,cnt |
||||
(ROtate Right) |
|
|
|||||
|
|
|
opr CF
Циклический сдвиг влево через перенос |
rcl opr,cnt |
|
(Rotate through Carry Left) |
|
|
|
|
|
CF |
opr |
|
Циклический сдвиг вправо через перенос |
rcr opr,cnt |
|
(Rotate through Carry Right) |
||
|
||
opr |
CF |
Пример. Двойное слово в DX:AX умножить на 4.
shl ax,1 ; Старший бит AX — в CF rcl dx,1 ; CF — в младший бит DX shl ax,1
rcl dx,1
Пример. Сосчитать количество единичных битов в AX. Результат поместить в BX.
xor bx,bx |
; обнулить счетчик единичных битов |
mov cx,16 |
; разрядность слова — в CX |
n: rol ax,1 |
; циклический сдвиг влево, старший бит — в CF |
adc bx,0 |
; добавить величину CF к счетчику |
loop n |
|
После выполнения этого фрагмента в AX будет восстановлено первоначальное содержимое.
Пример. Вращать содержимое AX влево, пока в старшем (15-ом) бите не появится '1', и перейти на метку n1. Если AX = 0, то перейти на метку n0.
Воспользуемся командой rcl (можно и rol) и тем, что OF = CF SF.
cmp ax,0 |
|
|
|
je |
n0 |
; если AX = 0 — на n0 |
|
js |
n1 |
; |
если старший бит установлен — на n1 |
mov cx,16 |
; |
разрядность AX — в CX |
m:rcl ax,1
jo n1 ; если CF = 0 и SF = 1 — на n1 loop m
(метки n0 и n1 не показаны)
18.3. Средства Ассемблера для битовых операций
На этапе ассемблирования над числами возможны следующие логические операции:
NOT, AND, OR, XOR, SHL, SHR. Приведем примеры.
L = 101b |
|
|
|
L = L SHL 2 |
|
; L = 10100b |
|
mov al, NOT 3 |
|
; |
AL = 0FCh |
mov bh, 1100b |
OR 1010b |
; |
BH = 1110b |
Когда требуется плотная упаковка нескольких числовых значений, диапазон изменения которых невелик, их помещают в заранее определенные битовые поля ячейки памяти. Рассмотрим пример, взятый из [5].
Разместим в слове информацию о работнике (табл.6.2).
Таблица 6.2
Биты |
Длина |
Имя |
Назначение |
|
поля |
поля |
|||
|
|
|||
15 |
1 |
sex |
пол (0 — мужчина, 1 — женщина) |
|
14 |
1 |
married |
семейное положение (0 — холост, 1 — женат) |
|
13:10 |
4 |
children |
количество детей (0 — 15) |
|
9 |
1 |
xxx |
зарезервировано |
|
8:2 |
7 |
age |
возраст (0 — 127) |
|
1:0 |
2 |
school |
уровень образования (0 — 3) |
Пусть в программе имеется описание:
Johnson DW 0100100010001011b
Нужно получить количество детей Джонсона (чтобы предоставить ему налоговые льготы). Сначала дадим "лобовое" решение задачи.
mov ax, Johnson |
; поместить данные в AX |
|||
and |
ax, |
0011110000000000b |
; выделить поле children |
|
shr |
ax, |
10 |
; |
прижать поле к правому краю |
|
|
|
; |
(в AX — количество детей) |
Стоит нам ошибиться хотя бы на один бит в маске и количестве сдвигов и мы получим неверный результат. Нельзя ли поручить этот скрупулезный подсчет битов Ассемблеру? Да, TASM предоставляет нам такую возможность. Приведем полный текст программы
.MODEL small
.286
.STACK 100h
.DATA
person RECORD sex:1=0,married:1,children:4,xxx:1, \ age:7,school:2=1
Johnson person <,1,2,,34,3>
.CODE
start:
mov ax,@data mov ds,ax
mov ax, Johnson
and ax, MASK children shr ax, children
mov ax,4c00h int 21h
END start
Прокомментируем текст программы. Директива .286 разрешает использовать инструкции 286-го процессора. Эта директива нужна, чтобы TASM сгенерировал код инструкции shr ax,10 (посмотрите в Turbo Debugger, что получится, если не указать эту директиву). Директива RECORD задает шаблон описания битовых полей. Этот шаблон носит имя person. В шаблоне указаны имя битового поля и его ширина, а не биты, которое занимает поле, — из-за этого пришлось включить в шаблон зарезервированное поле xxx. В двух полях (sex и age) после знака равенства дано значение "по умолчанию", которое может быть переопределено при описании с использованием шаблона. В шаблоне необязательно описывать все биты ячейки: можно было описать, например, только поля age и school. Само описание шаблона памяти не выделяет, зато описание выделяет в памяти слово в соответствии с шаблоном. Использован символ \ для продолжения директивы на следующей строке. В этом описании заданы значения всех полей, кроме xxx (значение которого безразлично), и sex (которое берется по умолчанию из шаблона).
Три строки в программе после загрузки DS полностью эквивалентны трем строкам, приведенным ранее. Операция (выполняемая на этапе ассемблирования) MASK поле_записи возвращает маску, необходимую для выделения поля записи. Значение поля_записи — число битов, на которые нужно осуществить сдвиг вправо, чтобы прижать поле к правому краю ячейки.
Если нужно прижать поле к левому краю слова, можно воспользоваться командой shl ax, 16 – WIDTH children – children.
Здесь в вычислениях участвует ширина поля WIDTH поле.
18.4. Задание D2. Пример программы, включающей битовые операции
18.4.1. Формулировка задания
Общее задание. Написать подпрограмму, обрабатывающую массив, и макрос для ее вызова. Подпрограмма обработки массива вызывает подпрограмму обработки элемента массива. В программе привести примеры вызова макроса. Программу, макрос и подпрограммы разместить в отдельных файлах.
В Turbo Debugger записать в файл протокола окна данных до и после выполнения программы. Записать туда же состояние стека в момент выполнения подпрограммы обработки элемента и интерпретировать его.
Отчет должен содержать:
1)распечатки файлов с программами и макросом,
2)распечатка окон с данными до и после выполнения программы,
3)окно стека с комментариями,
4)адрес подпрограммы обработки массива:
из листингов программ, из карты памяти, из отладчика.
5) размер кода и данных программы.
Задание. Дан массив слов (байтов) указанного размера. Над каждым элементом массива выполнить операцию: если битовое поле 6:4 совпадает с битовым полем 2:0 и с заданным образцом, то установить старший бит элемента, иначе — сбросить его.
18.4.2. Тексты программ
При выполнении задания вам придется как бы раздвоиться: на разработчика программы и ее пользователя. Разработчик пишет подпрограмму обработки массива и макрос, который дает возможность ее удобного использования. Пользователь пишет главную программу и испытывает подпрограмму на различных входных данных.
По условию задачи следует разместить программу и подпрограммы в разных файлах. Сначала напишем подпрограммы. Разместим их в файле sub2v0.asm. Сконструируем шаблон (рис.18.1) для слова и байта одновременно (можно, конечно, использовать и
несколько шаблонов). |
|
|
|
|
|
|
|
|
|
|
|
|
||||
15 |
14 |
13 |
12 |
11 |
10 |
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
b15 |
|
|
|
d2 |
|
|
|
b7 |
|
f6_4 |
|
d1 |
|
f2_0 |
|
Рис.18.1.
Фактически для нас представляют интерес только интерес только поля f6_4 и f2_0, из которых берутся исходные данные, и поля b15 и b7, которые (возможно) претерпевают изменения. Но приходится вводить названия и для неиспользуемых полей d1 и d2, в соответствии с синтаксисом описания RECORD.
sub2v0.asm
JUMPS |
; |
Оптимизация переходов |
.286 |
; |
Разрешены инструкции 286-го процессора |
TypeByte EQU 1
TypeWord EQU 2
GLOBAL treat_array:PROC
.MODEL small
.CODE
;--------------------------------------------------------------------
;Подпрограмма обработки элемента массива
;Вход: AX(AL) — элемент массива
; |
BP — образец |
; |
DX — тип элементов (1 - байты, 2 - слова) |
; Выход: AX(AL) - измененный элемент массива
;--------------------------------------------------------------------
treat_elem PROC
template RECORD b15:1, d2:7, b7:1, f6_4:3, \ d1:1, f2_0:3
push ax bx |
; Сохранить рабочие регистры |
mov bx,ax |
; Дублировать элемент в bx |
and ax,MASK f6_4 |
; Выделить битовое поле 6:4 |
shr ax,f6_4 |
; Прижать его к правому краю |
and bx,MASK f2_0 |
; Выделить битовое поле 2:0 |
cmp ax,bx |
; Сравнить битовые поля |
jne |
clear |
; Если не совпадают, сбросить старший бит |
|
cmp |
ax,bp |
; Сравнить битовое поле с образцом |
|
jne clear |
; Если не совпадают, сбросить старший бит |
||
; Установка старшего бита |
|
|
|
pop bx ax |
; |
Восстановить регистры |
|
cmp dx,TypeWord |
; Если тип операнда слово – |
||
je set_b15 |
; |
на set_b15 |
|
or al, MASK b7 |
; Иначе — установить старший бит байта |
||
jmp ret_elem |
; |
На выход |
|
set_b15: |
|
|
|
or ax, MASK b15 |
; Установить старший бит слова |
||
jmp ret_elem |
|
|
|
; Сброс старшего бита |
|
|
|
clear: pop bx ax |
|
|
|
cmp dx, TypeWord |
|
||
je clear_b15 |
|
|
|
and al, NOT MASK b7 |
; Сбросить старший бит байта |
||
jmp ret_elem |
|
|
|
clear_b15: |
|
|
|
and ax, NOT MASK b15 |
; Сбросить старший бит слова |
||
ret_elem: |
|
|
|
ret |
|
|
|
treat_elem ENDP |
|
|
;-------------------------------------------------------------------
;Подпрограмма обработки массива
;Вход: SI — адрес массива
;CX — количество элементов
;BP — образец
;DX — тип элементов (1 - байты, 2 - слова)
;Выход: CF = 1, если входной массив пуст
;CF = 0, если входной массив непуст
;Результат: измененный массив
;-------------------------------------------------------------------
treat_array PROC
|
jcxz error |
; |
Если массив нулевой длины — на error |
m: |
mov ax,[si] |
; |
Загрузить очередной элемент в AX (в AL) |
|
call treat_elem |
; Обработать элемент |
|
|
mov [si],ax |
; |
Вернуть элемент в массив |
add si,dx |
; Переместить указатель на следующий элемент |
loop m |
|
clc |
; Нормальное завершение |
ret |
|
error: stc; Сообщение об ошибке, если массив пустой ret
treat_array ENDP END
Обратим внимание на следующие моменты. 1) Мы сообщаем компилятору директивой
GLOBAL treat_array:PROC
что treat_array — это глобальное имя, т.е. оно будет использоваться программами, расположенными в других файлах. Спецификатор PROC означает, что это имя некоторой процедуры. Компилятор разместит это имя в таблице глобальных имен. Ей впоследствии воспользуется компоновщик.
2)Директива END не содержит метки стартового адреса, т.к. в файле нет главной программы — только подпрограммы.
3)Вместо того чтобы записывать команды
push ax push bx
мы записываем эти команды одной строкой. Такую возможность предоставляет Turbo
Assembler.
4)В начале каждой процедуры мы помещаем ее краткое описание и перечень входных
ивыходных параметров (если они есть). В нашем примере параметры передаются через регистры.
Файл с макросом для вызова подпрограммы treat_array. macr2v0.inc
TypeByte EQU 1
TypeWord EQU 2
;---------------------------------------------------------------------
;Макрос вызова подпрограммы обработки массива
;array — имя массива
;len_of_array — количество элементов массива
;pattern — образец
;error_label — метка для перехода по ошибке
;---------------------------------------------------------------------
treat MACRO array, len_of_array, pattern, error_label
TA = TYPE array
IF NOT (TA EQ TypeByte OR TA EQ TypeWord)
%OUT На входе должен быть массив слов или байтов! %OUT Массив array этому условию не удовлетворяет!
%OUT EXITM
ENDIF
IF pattern GT 111B
%OUT В образце pattern могут быть установлены %OUT только три младших бита.
%OUT EXITM
ENDIF
mov si, OFFSET array ;; |
В SI — адрес массива |
|
mov cx, len_of_array ;; |
В CX — количество элементов |
|
mov dx, TA |
;; |
В DX — тип элементов |
mov bp, pattern |
;; |
В BP — образец |
call treat_array |
|
|
jc error_label |
|
|
ENDM |
|
|
Директива EXITM используется для досрочного выхода из макроса.
Встроенная функция (времени ассемблирования) TYPE возвращает числовой код, соответствующий типу данных: 1 — для байтов, 2 — для слов, 4 — для двойных слов, остальные значения опустим.
Для комментариев используется повтор точки с запятой. Это делается для того, чтобы комментарии макроса не попадали в листинг и не увеличивали его длину.
Наконец, создадим файл с главной программой. Сначала сконструируем данные, на которых будем проверять правильность работы программы.
Нужно образовать массивы, элементы которых таковы, что они либо удовлетворяют либо не удовлетворяют условию задачи, чтобы проверить правильность работы программы во всех возможных ситуациях.
Будем использовать образец, задаваемый как параметр в макросе, 101b. В нашем примере достаточно сконструировать массив всего из двух элементов: для одного
элемента условие выполняется, а для другого — нет. |
|
|
|
||||||
Первый элемент (рис. 18.2): |
|
|
|
|
|
|
|
||
7 |
6 |
5 |
4 |
3 |
|
2 |
1 |
0 |
|
|
1 |
1 |
0 |
1 |
0 |
|
1 |
0 |
1 |
|
|
|
|
|
|
|
= |
|
|
|
|
|
установить |
|
|
|
|
|
|
||||
|
Рис. 18.2. |
|
|
|
|
|
|
||||
Второй элемент (рис.18.3): |
|
|
|
|
|
|
|
|
|
||
7 |
|
6 |
5 |
4 |
3 |
2 |
1 |
0 |
|
||
|
1 |
|
1 |
|
1 |
1 |
0 |
1 |
0 |
1 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
сбросить |
|
|
|
|
|
|
|
|
||
|
Рис. 18.3. |
|
|
|
|
|
|
||||
Итак, первый элемент 11010101 11010101, т.е. D5h |
D5h, а второй элемент |
||||||||||
11110101 01110101, т.е. F5h |
75h. Аналогичный тест предложим для слов: 00D5h |
||||||||||
80D5h, 00F5h 00F5h. |
|
|
|
|
|
|
|
|
|
main2v0.asm
COMMENT &
0. Иванов И.И. Дан массив байтов (слов) указанного размера.
Над каждым элементом массива выполнить операцию: если битовое поле 6:4 совпадает с битовым полем 2:0 и с заданным образцом, то установить старший бит элемента, иначе — сбросить его.
&
JUMPS |
; |
Оптимизация переходов |
||
.286 |
; |
Разрешены инструкции 286-го процессора |
||
INCLUDE |
macro.inc |
; |
Включить общий файл макросов |
|
INCLUDE macr2v0.inc ; |
Включить специальный файл макросов |
|||
; |
|
|
|
|
GLOBAL treat_array:PROC
.MODEL small
.STACK 100h
.DATA
arrb DB 0D5h,0F5h Len_of_arrb = $ - arrb arrw DW 00D5h,00F5h
Len_of_arrw = ($ - arrw) SHR 1 arrd DD 0FFFFFFFFh
Len_of_arrd = ($ - arrd) SHR 2 msg_err DB "Массив пуст!",CRLFT
.CODE
start:
mov ax,@data mov ds,ax
treat arrb, Len_of_arrb, 101B, error treat arrw, Len_of_arrw, 101B, error treat arrw, Len_of_arrw, 1101B, error treat arrd, Len_of_arrd, 10B, error exit
error: message msg_err exit 1
END start
Содержимое файла macro.inc описано ранее.
18.4.3. Выполнение задания на компьютере.
1) Ввод текстов программ. Можно воспользоваться файлами с излагаемым примером, как шаблоном.
2) Трансляция, компоновка, выполнение. Можно просто вручную набрать команды: c:\tasm\bin\tasm /zi/m/la main2v0
c:\tasm\bin\tasm/zi/m/la sub2v0 c:\tasm\bin\tlink/v/m main2v0 sub2v0, a2v0 c:\tasm\bin\td a2v0.exe
но эти команды наверняка придется набирать многократно, т.к. вряд ли у вас все получится с первого раза. Имеет смысл эти команды записать в командный файл. Но этот путь неэффективен вот по какой причине: предположим, мы уже отладили главную программу (она проще), зачем же каждый раз ее транслировать, хотя она не претерпевает изменений. А если при трансляции возникнет ошибка, то компоновку выполнять не нужно (вообще-то этой ситуации можно избежать, если в командный файл вставить проверку уровня ошибки ERRORLEVEL). Но лучшим решением является использование утилиты
MAKE.
Для того чтобы воспользоваться этой утилитой, представим наглядно в виде дерева (рис. 18.4) зависимость итогового файла a2v0.exe от исходных файлов:
a2v0.exe
|
|
|
|
|
|
|
|
|
main2v0.obj |
|
sub2v0.obj |
||||
|
|
|
|
|
|
|
|
main2v0.asm |
|
macr2v0.inc |
|
sub2v0.asm |
Рис. 18.4.
А теперь запишем это дерево в make-файле. Make-файл имеет следующую структуру:
цель: условие