
- •1. Неявная адресация
- •2. Непосредственная адресация
- •3. Абсолютная прямая адресация
- •4. Относительная прямая адресация
- •5. Регистровая адресация
- •6. Косвенная регистровая (базовая) адресация
- •7. Косвенная регистровая (базовая) адресация со смещением
- •8. Косвенная базовая индексная адресация
- •9. Косвенная базовая индексная адресация со смещением
- •2. Альтернативный синтаксис local
- •3. Locals и endl
2. Альтернативный синтаксис local
Альтернативный синтаксис похож на синтаксис размеров параметров. После имени переменной ставится двоеточие и оператор размера. Вместо оператора размера может быть также имя структуры (это удобно при программировании для Windows).
local i:BYTE local j:WORD, k:DWORD |
Инициализация переменных в этом варианте синтаксиса не предусмотрена, её придётся делать вручную. Зато можно легко объявлять массивы — обозначение очень напоминает языки высокого уровня:
local buffer[256]:BYTE ;Локальный буфер размером 256 байт |
3. Locals и endl
Третий вариант — объявление локальных переменных в виде блока locals — endl. Используются обычные директивы объявления данных:
proc myproc c uses ax bx cx dx,\ a:BYTE,b:WORD,c:DWORD locals i db 5 j dw ? k rd 1 endl mov cl,[a] mov bx,[b] mov ax,word[c] mov dx,word[c+2] add cl,[i] mov [j],bx mov word[k],ax mov word[k+2],dx ret endp |
Этот способ хорошо подходит, если в процедуре много локальных переменных.
Макросы для вызова процедур
В файле PROC16.INC объявлены также макросы для удобного вызова процедур. Эти макросы избавляют от необходимости писать несколько команд PUSH для помещения параметров в стек. Вместо этого достаточно написать одну строку, в которой указывается имя процедуры и список параметров через запятую. Например:
stdcall <имя_процедуры>[,<список_параметров>] |
Всего существует 4 разных макроса, они перечислены в таблице. Два последних макроса чаще используются в программировании для Windows. Они выполняют вызов процедуры, адрес которой находится в переменной.
Макрос |
Описание |
stdcall |
Вызов процедуры с соглашениями вызова stdcall |
ccall |
Вызов процедуры с соглашениями вызова c |
invoke |
То же самое, что stdcall [<имя_переменной>] |
cinvoke |
То же самое, что ccall [<имя_переменной>] |
Так как наша процедура использует соглашения вызова c, то вызывать её надо макросом ccall:
ccall myproc,5,0,ax,dx ;3-й параметр находится в DX:AX |
Макрос дополнительно генерирует код для восстановления указателя стека:
Важная особенность
Если вы объявили процедуру, но ни разу не вызывали, то её код не будет добавлен в исполняемый файл! Это позволяет создать свою библиотеку полезных процедур, сохранить их в отдельном файле и добавлять во все проекты, где они нужны. При этом в исполняемом файле окажутся только те процедуры, которые использует ваша программа.
Команды сканирования битов
Сканирование битов выполняется командами BSF и BSR. Эти команды очень похожи. У них 2 операнда. Первый операнд должен быть 16-битным регистром, в него записывается результат. Второй операнд может быть 16-битным регистром или словом в памяти — это обрабатываемое значение.
Команда BSF просматривает биты второго операнда от младшего к старшему и помещает индекс первого единичного бита в регистр. Биты нумеруются, начиная с нуля. Если единичный бит найден, то флаг нуля сбрасывается (ZF=0). Если все биты нулевые, то флаг нуля устанавливается (ZF=1), а значение первого операнда будет неопределённым (на разных процессорах может быть по-разному). Например, мой процессор (Athlon XP) в этом случае не изменяет значение в регистре. Пример кода:
mov ax,01011000b ;AX=58h bsf bx,ax ;BX=3, ZF=0 xor ax,ax ;AX=0 bsf bx,ax ;BX=?, ZF=1 |
Команда BSR отличается тем, что просматривает биты от старшего к младшему. Всё остальное также.
mov ax,01011000b ;AX=58h bsr bx,ax ;BX=6, ZF=0 xor ax,ax ;AX=0 bsr bx,ax ;BX=?, ZF=1 |
Картинка для наглядности:
Команды проверки и модификации битов
Команда BT копирует значение проверяемого бита в флаг CF. Вот и вся проверка! После этого можно выполнить условный переход командами JC или JNC, в зависимости от значения бита. У команды два операнда: слово в регистре или в памяти и номер бита, который может находиться в регистре или быть непосредственным значением. Примеры использования команды:
bt ax,0 ;Проверка младшего бита AX jc m1 ;Переход, если бит равен 1 mov cx,3 ;CX=3 bt ax,cx ;Проверка 3-го бита AX jnc m1 ;Переход, если бит равен 0 |
Ещё 3 команды немного отличаются от BT:
команда BTR проверяет бит и затем сбрасывает его;
команда BTS проверяет бит и затем устанавливает его в 1;
команда BTC проверяет бит и затем инвертирует его.
Эти команды удобны тем, что можно совместить проверку бита и присвоение ему нового значения.