Что такое cdq в ассемблере

Что такое cdq в ассемблере

Базовая команда пересылки данных. Копирует содержимое источника в приемник, источник не изменяется. Команда MOV действует аналогично операторам присваивания из языков высокого уровня, то есть команда

языка С, за исключением того, что команда ассемблера позволяет работать не только с переменными в памяти, но и со всеми регистрами процессора.

В качестве источника для MOV могут использоваться: число (непосредственный операнд), регистр общего назначения, сегментный регистр или переменная (то есть операнд, находящийся в памяти). В качестве приемника — регистр общего назначения, сегментный регистр (кроме CS) или переменная. Оба операнда должны быть одного и того же размера — байт, слово или двойное слово.

Нельзя выполнять пересылку данных с помощью MOV из одной переменной в другую, из одного сегментного регистра в другой и нельзя помещать в сегментный регистр непосредственный операнд — эти операции выполняют двумя командами MOV (из сегментного регистра в обычный и уже из него в другой сегментный) или парой команд PUSH/POP.

Это набор команд, которые копируют содержимое источника в приемник, если удовлетворяется то или иное условие (см. табл. 5). Источником может быть регистр общего назначения или переменная, а приемником — только регистр. Условие, которое должно удовлетворяться, — просто равенство нулю или единице тех или иных флагов из регистра FLAGS, но, если использовать команды CMOVcc сразу после команды СМР (сравнение) с теми же операндами, условия приобретают особый смысл, например:

Слова «выше» и «ниже» в таблице 5 относятся к сравнению чисел без знака, слова «больше» и «меньше» учитывают знак.

Таблица 5. Разновидности команды CMOVcc

Содержимое операнда 2 копируется в операнд 1, а старое содержимое операнда 1 — в операнд 2. XCHG можно выполнять над двумя регистрами или над регистром и переменной.

Обращает порядок байт в 32-битном регистре. Биты 0 – 7 (младший байт младшего слова) меняются местами с битами 24 – 31 (старший байт старшего слова), а биты 8 – 15 (старший байт младшего слова) меняются местами с битами 16 – 23 (младший байт старшего слова).

Чтобы обратить порядок байт в 16-битном регистре, следует использовать команду XCHG:

В процессорах Intel команду BSWAP можно использовать и для обращения порядка байт в 16-битных регистрах, но в некоторых совместимых процессорах других фирм этот вариант BSWAP не реализован.

Помещает содержимое источника в стек. Источником может быть регистр, сегментный регистр, непосредственный операнд или переменная. Фактически эта команда копирует содержимое источника в память по адресу SS:[ESP] и уменьшает ESP на размер источника в байтах (2 или 4). Команда PUSH практически всегда используется в паре с POP (считать данные из стека). Так, например, чтобы скопировать содержимое одного сегментного регистра в другой (что нельзя выполнить одной командой MOV), можно использовать такую последовательность команд:

Другое частое применение команд PUSH/POP — временное хранение переменных, например:

Начиная с 80286, команда PUSH ESP (или SP) помещает в стек значение ESP до того, как эта же команда его уменьшит, в то время как на 8086 SP помещался в стек уже уменьшенным на два.

Помещает в приемник слово или двойное слово, находящееся в вершине стека, увеличивая ESP на 2 или 4 соответственно. POP выполняет действие, полностью обратное PUSH. Приемником может быть регистр общего назначения, сегментный регистр, кроме CS (чтобы загрузить CS из стека, надо воспользоваться командой RET), или переменная. Если в роли приемника выступает операнд, использующий ESP для косвенной адресации, команда POP вычисляет адрес операнда уже после того, как она увеличивает ESP.

PUSHA помещает в стек регистры в следующем порядке: АХ, СХ, DX, ВХ, SP, ВР, SI и DI. PUSHAD помещает в стек ЕАХ, ЕСХ, EDX, ЕВХ, ESP, EBP, ESI и EDI. (В случае SP и ESP используется значение, которое находилось в этом регистре до начала работы команды.) В паре с командами POPA/POPAD, считывающими эти же регистры из стека в обратном порядке, это позволяет писать подпрограммы (обычно обработчики прерываний), которые не должны изменять значения регистров по окончании своей работы. В начале такой подпрограммы вызывают команду PUSHA, а в конце — РОРА.



На самом деле PUSHA и PUSHAD — одна и та же команда с кодом 60h. Ее поведение определяется тем, выполняется ли она в 16- или в 32-битном режиме. Если программист использует команду PUSHAD в 16-битном сегменте или PUSHA в 32-битном, ассемблер просто записывает перед ней префикс изменения размерности операнда (66h).

Эти команды выполняют действия, полностью обратные действиям PUSHA и PUSHAD, за исключением того, что помещенное в стек значение SP или ESP игнорируется. РОРА загружает из стека DI, SI, BP, увеличивает SP на два, загружает ВХ, DX, CX, AX, a POPAD загружает EDI, ESI, ЕВР, увеличивает ESP на 4 и загружает ЕВХ, EDX, ЕСХ, ЕАХ.

Копирует число из порта ввода-вывода, номер которого указан в источнике, в приемник. Приемником может быть только AL, АХ или ЕАХ. Источник — или непосредственный операнд, или DX, причем можно указывать только номера портов не больше 255.

Копирует число из источника (AL, АХ или ЕАХ) в порт ввода-вывода, номер которого указан в приемнике. Приемник может быть либо непосредственным номером порта, либо регистром DX. На командах IN и OUT строится все общение процессора с устройствами ввода-вывода — клавиатурой, жесткими дисками, различными контроллерами, и используются они, в первую очередь, в драйверах устройств. Например, чтобы включить динамик PC, достаточно выполнить команды:

Программирование портов ввода-вывода рассмотрено подробно в главе 5.10.

Команда CWD превращает слово в AХ в двойное слово, младшая половина которого (биты 0 – 15) остается в АХ, а старшая (биты 16 – 31) располагается в DX. Команда CDQ выполняет аналогичное действие по отношению к двойному слову в ЕАХ, расширяя его до учетверенного слова в EDX:EAX. Эти команды всего лишь устанавливают все биты регистра DX или EDX в значение, равное значению старшего бита регистра АХ или ЕАХ, сохраняя таким образом его знак.

CBW расширяет байт, находящийся в регистре AL, до слова в АХ, CWDE расширяет слово в АХ до двойного слова в ЕАХ. CWDE и CWD отличаются тем, что CWDE располагает свой результат в ЕАХ, в то время как CWD, команда, выполняющая точно такое же действие, располагает результат в паре регистров DX:AX. Так же как и команды CWD/CDQ, расширение выполняется путем установки каждого бита старшей половины результата равным старшему биту исходного байта или слова, то есть:



Копирует содержимое источника (регистр или переменная размером в байт или слово) в приемник (16- или 32-битный регистр) и расширяет знак аналогично командам CBW/CWDE.

Копирует содержимое источника (регистр или переменная размером в байт или слово) в приемник (16- или 32-битный регистр) и расширяет нулями, то есть команда

эквивалентна паре команд

Помещает в AL байт из таблицы в памяти по адресу ES:BX (или ES:EBX) со смещением относительно начала таблицы, равным AL. В качестве аргумента для XLAT в ассемблере можно указать имя таблицы, но эта информация никак не используется процессором и служит только как комментарий. Если этот комментарий не нужен, можно применить форму записи XLATB. В качестве примера использования XLAT можно написать следующий вариант преобразования шестнадцатеричного числа в ASCII-код соответствующего ему символа:

если в сегменте данных, на который указывает регистр ES, было записано

то теперь AL содержит не число 0Сh, а ASCII-код буквы «С». Разумеется, это преобразование можно выполнить, используя гораздо более компактный код всего из трех арифметических команд, который будет рассмотрен в описании команды DAS, но с XLAT можно выполнять любые преобразования такого рода.

Вычисляет эффективный адрес источника (переменная) и помещает его в приемник (регистр). С помощью LEA можно вычислить адрес переменной, которая описана сложным методом адресации, например по базе с индексированием. Если адрес 32-битный, а регистр-приемник 16-битный, старшая половина вычисленного адреса теряется, если наоборот, приемник 32-битный, а адресация 16-битная, то вычисленное смещение дополняется нулями.



Команду LEA часто используют для быстрых арифметических вычислений, например умножения:

Источник

FE23 LOOCH DISASM


СПРАВОЧНИК ПО КОМАНДАМ
ПРОЦЕССОРОВ x86




Что такое cdq в ассемблере. Смотреть фото Что такое cdq в ассемблере. Смотреть картинку Что такое cdq в ассемблере. Картинка про Что такое cdq в ассемблере. Фото Что такое cdq в ассемблере
ГлавнаяЗагрузкаИнструкцияКоманды x86Карта сайта

Что такое cdq в ассемблере. Смотреть фото Что такое cdq в ассемблере. Смотреть картинку Что такое cdq в ассемблере. Картинка про Что такое cdq в ассемблере. Фото Что такое cdq в ассемблере
Что такое cdq в ассемблере. Смотреть фото Что такое cdq в ассемблере. Смотреть картинку Что такое cdq в ассемблере. Картинка про Что такое cdq в ассемблере. Фото Что такое cdq в ассемблереЧто такое cdq в ассемблере. Смотреть фото Что такое cdq в ассемблере. Смотреть картинку Что такое cdq в ассемблере. Картинка про Что такое cdq в ассемблере. Фото Что такое cdq в ассемблере

КОМАНДЫ ПЕРЕСЫЛКИ ДАННЫХ


Команда пересылки данных


КомандаОперандыКодФормат
Что такое cdq в ассемблере. Смотреть фото Что такое cdq в ассемблере. Смотреть картинку Что такое cdq в ассемблере. Картинка про Что такое cdq в ассемблере. Фото Что такое cdq в ассемблере
MOV(r/m8), (reg8)88——dw MRM
MOV(r/m16), (reg16)
(r/m32), (reg32)
89——dw MRM
MOV(reg8), (r/m8)8A——dw MRM
MOV(reg16), (r/m16)
(reg32), (r/m32)
8B——dw MRM
Что такое cdq в ассемблере. Смотреть фото Что такое cdq в ассемблере. Смотреть картинку Что такое cdq в ассемблере. Картинка про Что такое cdq в ассемблере. Фото Что такое cdq в ассемблере
MOVAL, (mem8)A0——dw addr(2/4)
MOVAX, (mem16)
EAX, (mem32)
A1——dw addr(2/4)
MOV(mem8), ALA2——dw addr(2/4)
MOV(mem16), AX
(mem32), EAX
A3——dw addr(2/4)

Команда MOV копирует содержимое второго операнда в первый операнд. При этом содержимое второго операнда не изменяется.

Команда MOV не воздействует на флажки, состояние флажков не изменяется.

В командах MOV с кодами A0, A1, A2, A3 обозначение addr(2/4) это задание адреса в оперативной памяти. Задается смещение относительно начала сегмента DS. Байты (два или четыре), задающие адрес, располагаются в самой команде следом за кодом операции. Размер адреса (2 или 4 байта) определяется атрибутом размера адреса команды.

В командах MOV с кодами 89, 8B, A1, A3 размер операнда (2 или 4 байта) определяется атрибутом размера операнда команды.

(Не путайте атрибут размера адреса и атрибут размера операнда, это две разные вещи.)

Команда для засылки констант


КомандаОперандыКодФормат
Что такое cdq в ассемблере. Смотреть фото Что такое cdq в ассемблере. Смотреть картинку Что такое cdq в ассемблере. Картинка про Что такое cdq в ассемблере. Фото Что такое cdq в ассемблере
MOVAL, imm8B0—-wreg data(1)
MOVCL, imm8B1—-wreg data(1)
MOVDL, imm8B2—-wreg data(1)
MOVBL, imm8B3—-wreg data(1)
MOVAH, imm8B4—-wreg data(1)
MOVCH, imm8B5—-wreg data(1)
MOVDH, imm8B6—-wreg data(1)
MOVBH, imm8B7—-wreg data(1)
Что такое cdq в ассемблере. Смотреть фото Что такое cdq в ассемблере. Смотреть картинку Что такое cdq в ассемблере. Картинка про Что такое cdq в ассемблере. Фото Что такое cdq в ассемблере
MOVAX, imm16
EAX, imm32
B8—-wreg data(2/4)
MOVCX, imm16
ECX, imm32
B9—-wreg data(2/4)
MOVDX, imm16
EDX, imm32
BA—-wreg data(2/4)
MOVBX, imm16
EBX, imm32
BB—-wreg data(2/4)
MOVSP, imm16
ESP, imm32
BC—-wreg data(2/4)
MOVBP, imm16
EBP, imm32
BD—-wreg data(2/4)
MOVSI, imm16
ESI, imm32
BE—-wreg data(2/4)
MOVDI, imm16
EDI, imm32
BF—-wreg data(2/4)
Что такое cdq в ассемблере. Смотреть фото Что такое cdq в ассемблере. Смотреть картинку Что такое cdq в ассемблере. Картинка про Что такое cdq в ассемблере. Фото Что такое cdq в ассемблере
MOV(r/m8), imm8C6——-w NNN data(1)
MOV(r/m16), imm16
(r/m32), imm32
C7——-w NNN data(2/4)

Команда MOV с кодами C6, C7 обычно используется только для засылки константы в память и не используются для засылки константы в регистр, потому что для засылки константы в регистр есть более удобные команды с кодами от B0 до BF.

Другие команды MOV


Команды пересылки с расширением операнда


КомандаОперандыКодФормат
Что такое cdq в ассемблере. Смотреть фото Что такое cdq в ассемблере. Смотреть картинку Что такое cdq в ассемблере. Картинка про Что такое cdq в ассемблере. Фото Что такое cdq в ассемблере
MOVSX(reg16), (r/m8)
(reg32), (r/m8)
0F BE——-w MRM
MOVSX(reg32), (r/m16)0F BF——-w MRM
MOVZX(reg16), (r/m8)
(reg32), (r/m8)
0F B6——-w MRM
MOVZX(reg32), (r/m16)0F B7——-w MRM

Первый операнд является приемником (destination), второй операнд источником (source). Обе команды берут содержимое операнда источника, расширяют это значение до величины атрибута размера операнда команды (до 16 бит или до 32 бит) и заносят результат в операнд приемник.

Команды MOVSX и MOVZX не воздействуют на флажки, состояние флажков не изменяется.

Команды расширения операнда


КомандаОперандыРазмер
операнда
КодФормат
Что такое cdq в ассемблере. Смотреть фото Что такое cdq в ассемблере. Смотреть картинку Что такое cdq в ассемблере. Картинка про Что такое cdq в ассемблере. Фото Что такое cdq в ассемблере
CBWAX, AL16 бит98———
CWDEEAX, AX32 бита98———
CWDDX:AX, AX16 бит99———
CDQEDX:EAX, EAX32 бита99———

Например, команда CBW берет знаковый бит из регистра AL (то есть, старший бит из AL) и заносит его во все биты регистра AH. Точно также, команда CWD берет знаковый (старший) бит из AX и заносит его во все биты регистра DX.

При записи на языке ассемблера для этих команд операнды не указываются. Операнды заранее определены по умолчанию и не могут быть изменены. В таблице показаны операнды, действующие по умолчанию.

Команды CBW, CWDE, CWD, CDQ не воздействуют на флажки, состояние флажков не изменяется.

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

Команда обмена данными


КомандаОперандыКодФормат
Что такое cdq в ассемблере. Смотреть фото Что такое cdq в ассемблере. Смотреть картинку Что такое cdq в ассемблере. Картинка про Что такое cdq в ассемблере. Фото Что такое cdq в ассемблере
XCHGEAX, EAX90——reg
XCHGEAX, ECX91——reg
XCHGEAX, EDX92——reg
XCHGEAX, EBX93——reg
XCHGEAX, ESP94——reg
XCHGEAX, EBP95——reg
XCHGEAX, ESI96——reg
XCHGEAX, EDI97——reg
Что такое cdq в ассемблере. Смотреть фото Что такое cdq в ассемблере. Смотреть картинку Что такое cdq в ассемблере. Картинка про Что такое cdq в ассемблере. Фото Что такое cdq в ассемблере
XCHG(reg8), (r/m8)86——-w MRM
XCHG(reg32), (r/m32)87——-w MRM

Команда XCHG обменивает содержимое двух своих операндов. Значение, которое было до выполнения команды в первом операнде, оказывается в результате во втором операнде. А значение, которое было до выполнения команды во втором операнде, оказывается в результате в первом операнде.

Команда XCHG не воздействует на флажки, состояние флажков не изменяется.

Команда XCHG всегда имеет два операнда, причем оба операнда должны иметь одинаковый размер (1 байт, или 2 байта, или 4 байта). Операнды могут быть указаны в команде в любом порядке. Это очевидно из смысла выполняемой операции.

Из всех вариантов команды XCHG только команда с кодом 86 может работать с операндами размером один байт.

Машинные команды с кодами 90-97 и 87 могут работать с операндами, размером два байта или четыре байта. Размер операнда (2 или 4 байта) определяется атрибутом размера операнда команды.

Пустая операция

Известны и еще несколько команд, которые тоже могут применяться, чтобы просто занимать место, причем занимать не один байт, а несколько. Но эти команды не имеют своего отдельного имени на языке ассемблера.

Команда перестановки байтов в 32-битном регистре


КомандаОперандыКодФормат
Что такое cdq в ассемблере. Смотреть фото Что такое cdq в ассемблере. Смотреть картинку Что такое cdq в ассемблере. Картинка про Что такое cdq в ассемблере. Фото Что такое cdq в ассемблере
BSWAPEAX0F C8——reg
BSWAPECX0F C9——reg
BSWAPEDX0F CA——reg
BSWAPEBX0F CB——reg
BSWAPESP0F CC——reg
BSWAPEBP0F CD——reg
BSWAPESI0F CE——reg
BSWAPEDI0F CF——reg

Как известно, в процессорах x86 принят обратный порядок для расположения данных. Иногда возникает потребность показать результат с прямым порядком байтов. Изменить порядок байтов можно одной командой BSWAP, не делая лишних сдвигов и пересылок.

Команда BSWAP не воздействует на флажки, состояние флажков не изменяется.

Использование команды BSWAP для размера операнда «16 бит» не предусмотрено. Результат операции в этом случае не определен.

Источник

12. Команды расширения

В программах довольно часто нужно переслать меньшее по длине значение в большую по длине переменную или регистр. В качестве примера предположим, что нам нужно загрузить 16-разрядное беззнаковое значение, хранящееся в переменной count, в 32-разрядный регистр ЕСХ. Самое простое решение этой задачи заключается в том, что вначале нужно обнулить регистр ЕСХ, а затем загрузить 16-разрядное значение переменной count в регистр СХ:

Для выполнения расширения можно использовать готовые команды:

Команда MOVZX
Команда MOVZX копирует содержимое исходного операнда в больший по размеру регистр получателя данных. При этом оставшиеся неопределенными биты регистра-получателя (как правило, старшие 16 или 24 бита) сбрасываются в ноль. Эта команда используется только при работе с беззнаковыми целыми числами.

Команда MOVSX
Команда MOVSX (Move With Sign-Extend, или Переместить и дополнить знаком) копирует содержимое исходного операнда в больший по размеру регистр получателя данных, также как и команда MOVZX. При этом оставшиеся неопределенными биты регистра- получателя (как правило, старшие 16 или 24 бита) заполняются значением знакового бита исходного операнда. Эта команда используется только при работе со знаковыми целыми числами.

Команды MOVSX и MOVZX применимы к следующим операндам:
MOVSX/MOVZX 16-разрядный регистр (16r), 8-разрядный регистр или поле памяти(8r/8m)
MOVSX/MOVZX 32-разрядный регистр (32r), 8-разрядный регистр или поле памяти(8r/8m)
MOVSX/MOVZX 32-разрядный регистр (32r), 16-разрядный регистр или поле памяти(16r/16m)

Источник

Ассемблер под Windows для чайников. Часть 9

Приветствую постоянных читателей, а также тех, кто только решил влиться в ряды изучающих ассемблер под Windows. Сегодня весьма полезная тема и для первых, и для вторых. Потому что сегодня мы подробно рассмотрим основные команды ассемблера в теории. Обычно я строил наши занятия по большей части с практическим уклоном. Но теперь, когда вы уже получили достаточно примеров использования тех или иных команд ассемблера, пришла пора четко и безо всякой двусмысленности зафиксировать их в вашем понимании.

Обычно ассемблер начинают изучать именно с теории. Но без представления возможностей практического применения тех или иных команд такое обучение, скорее всего, покажется скучным и малопонятным. Добавьте к этому сложность предмета программирования самого по себе, и получите вполне ожидаемый результат — потерю желания изучать ассемблер вообще. Надеюсь, что вы уже имеете определенное положительное мнение об ассемблере и твердо решили идти до конца. Если же вы все еще не верите в свои силы, то попытаюсь вас успокоить: основных команд в ассемблере немногим более сотни, учитывая то, что многие из них — синонимы (близкие или одинаковые по значению) или антонимы (прямо противоположные). Команд, которые необходимо запомнить для каждодневного использования — вообще не более двух-трех десятков. Причем запоминать их все и сразу вам не обязательно. Просто сохраните эту статью, и всегда сможете быстро вспомнить название и назначение той или иной команды. Не забывайте, что данный цикл статей опирается на синтаксис, используемый в компиляторе FASM.

Прежде всего, придется помучить вас маленьким, но очень важным моментом — регистром флагов. По общим правилам изучения ассемблера с этим регистром принято знакомиться на первом или втором занятии, сразу же после знакомства с регистрами общего назначения и сегментными регистрами. Однако, дабы не сильно пугать вас сразу, я отложил знакомство с ним аж до сегодняшнего занятия, а сегментные регистры пока что вообще не трогал. Пишут же люди программы на языках высокого уровня, даже не подозревая о таких «мелочах», так зачем вам, все еще местами сомневающимся в собственных силах касательно освоения ассемблера, изначально забивать голову пугающей теорией? И все же азы надо знать, так что соберитесь: регистр флагов! Регистр флагов в 32-битных процессорах имеет размер 32 бита и называется EFLAGS. Как вы могли заметить, приставка «E» в названии 32-битного регистра обычно свидетельствует о том, что он имеет 16-битное происхождение (64-битные регистры имеют приставку R). Значит, из соображений обратной совместимости со старыми 16-битными программами должен существовать и 16-битный предок — FLAGS. На его примере мы и начнем знакомство с данным регистром:

Регистр FLAGS

Бит

Флаг

Описание

0

CF

Флаг переноса (Carry flag)

1

1

Зарезервирован

2

PF

Флаг четности (Parity flag)

3

0

Зарезервирован

4

AF

Вспомогательный флаг переноса (Auxiliary flag)

5

0

Зарезервирован

6

ZF

Флаг нуля (Zero flag)

7

SF

Флаг знака (Sign flag)

8

TF

Флаг трассировки (Trace flag)

9

IF

Флаг разрешения прерываний (Interrupt enable flag)

10

DF

Флаг направления (Direction flag)

11

OF

Флаг переполнения (Overflow flag)

12,13

IOPL

Уровень приоритета ввода-вывода (I/O privilege level)

14

NT

Флаг вложенной задачи (Nested Task)

15

0

Зарезервирован

На данном этапе вам понадобится запомнить лишь 3-4 флага, поэтому не пугайтесь этой таблицы: ее цель — лишь получение вами общего представления о регистре флагов 16-битного процессора, который, тем не менее, сохранился и в 32-, и в 64-битных потомках.

CF устанавливается (1), если в результате операции из старшего бита происходит перенос при сложении или заем при вычитании, иначе CF сбрасывается (0). Кроме того, CF используется в логических и унарных операциях.

ZF устанавливается (1), если результат операции равен нулю, иначе ZF сбрасывается (0). Главное — впоследствии не запутаться в том, что ZF=0, если результат отличен от ноля, но ZF=1 при нулевом результате.

SF отражает состояние старшего (знакового) бита результата. SF=1, если старший бит результата равен единице, и ZF=0 — если старший бит результата нулевой.

OF фиксирует факт потери старшего (знакового) бита результата при арифметических операциях. OF=1, если произошел перенос в старший бит результата или заем из старшего бита, ZF=0 при отсутствии переноса или заема.

PF устанавливается (1), если младшие 8 битов результата содержат четное число единиц.

Теперь мы можем перейти к знакомству с часто применяемыми командами.

Команды обмена данными: MOV, XCHG.

MOV приемник,источник
Копирует байт(byte)/слово(word)/двойное слово(dword) из операнда источник в операнд приемник. Позволяет копировать данные из одного регистра общего назначения (РОН) в другой, из РОН в память, из памяти в РОН. Командой MOV нельзя напрямую переслать данные из одной области памяти в другую — для этого придется использовать в качестве посредника один из РОН. Копирование данных в таком случае осуществляется за две команды: сначала из исходной области памяти в РОН, а затем — из РОН в целевую область памяти. При помощи команды MOV также можно помещать в регистр или память непосредственное значение, копировать содержимое сегментного регистра в РОН или память, содержимое РОН или памяти в сегментный регистр, содержимое регистра управления или отладки в РОН, содержимое РОН в регистр управления или регистр отладки. Команда MOV может быть обработана компилятором только если размеры источника и приемника совпадают. Ниже следуют примеры возможных вариантов использования команды MOV:

mov bx,ax ;копировать содержимое РОН в РОН
mov [char],al ;РОН в память
mov bl,[char] ;память в РОН
mov dl,32 ;значение в РОН
mov [char],32 ;значение в память
mov ax,ds ;сегментный регистр в РОН
mov [bx],ds ;сегментный регистр в память
mov ds,ax ;РОН в сегментный регистр
mov ds,[bx] ;память в сегментный регистр
mov eax,cr0 ;регистр управления в РОН
mov cr3,ebx ;РОН в регистр управления

XCHG операнд1,операнд2
Используется для двунаправленной пересылки данных между операндами. Размер обоих операндов может быть байтом, словом или двойным словом, но оба операнда должны быть одинакового размера. Команда XCHG помещает содержимое первого операнда во второй, а второго — в первый. Один из операндов всегда должен быть РОН, а другой может быть областью памяти или также РОН.

xchg ax,bx ;обменять содержимое РОН и РОН
xchg al,[char] ;обменять содержимое РОН и памяти

Обмен данными через стек: PUSH, POP.

Стек — область памяти, специально выделяемая каждой программе для временного хранения промежуточных данных. Обычно адреса в памяти растут от ноля к максимальному адресу. В стеке все наоборот: он растет от дна (максимальный адрес сегмента стека) к нолю. Для того, чтобы поместить данные в стек, применяется команда PUSH, ее синтаксис следующий:

PUSH источник
Эта команда уменьшает указатель на текущий кадр стека (регистр ESP) и копирует содержимое операнда-источника по адресу вершины стека, содержащемуся в ESP. В роли операнда может выступать РОН, память, сегментный регистр, значение размером в слово или двойное слово. Если в качестве операнда указано непосредственное значение, то в 16-битном режиме оно по умолчанию воспринимается компилятором как слово, а в 32-битном — как двойное слово. Мнемоники PUSHW и PUSHD указывают компилятору, что значение необходимо сохранить как слово или как двойное слово соответственно независимо от режима, в котором работает компилятор. Если за командой PUSH следуют несколько операндов, разделенных пробелами, то они будут обработаны компилятором как последовательность из нескольких команд PUSH с этими операндами по отдельности. PUSHA сохраняет в стеке содержимое всех восьми регистров общего назначения. Примеры использования команды PUSH:

push ax ;сохранить РОН
push es ;сохранить сегментный регистр
pushw [bx] ;сохранить память
push 1000h ;сохранить значение
push ebx,esi,edi ;сохранить по очереди три регистра
pusha ;сохранить все 8 РОН

POP приемник
Команда POP копирует слово или двойное слово, содержащееся на вершине стека, в указанный операнд-приемник, затем увеличивает ESP так, чтобы он указывал на новую вершину стека. Операндом может быть РОН, память, сегментный регистр. Эта команда предназначена для извлечения из стека данных, сохраненных командой PUSH. Следует помнить, что извлекаются данные в обратном порядке, так что, если вы сохранили в стеке EAX, EBX и потом ECX, то извлекать надо сперва ECX, затем EBX и EAX. Команда POP является полной противоположностью команды PUSH, поэтому мнемоники POPW, POPD и POPA работают по аналогии с описанными выше мнемониками PUSH, но выполняют обратные действия.

Примеры:
pop bx ;восстановить РОН
pop ds ;восстановить сегментный регистр
popw [si] ;восстановить память
pop edi,esi,ebx ;восстановить по очереди три регистра
popa ;восстановить все 8 РОН

INC операнд
Команда увеличивает значение операнда на единицу. Операнд может быть РОН или памятью. Размер операнда — байт, слово или двойное слово. Примеры:
inc ax ;увеличить значение в регистре
inc byte[bx] ;увеличить значение в памяти

ADD приемник,источник
Складывает оба операнда и помещает результат в приемник. Если результат превысил размер приемника, устанавливает флаг переноса (CF). Размером операндов может быть байт, слово или двойное слово. Приемник может быть РОН или памятью. Источник может быть РОН или значением. Источник может также быть памятью при условии, что приемник является регистром. Примеры:
add ax,bx ;прибавить к регистру регистр
add ax,[si] ;прибавить к регистру память
add [di],al ;прибавить к памяти регистр
add al,48 ;прибавить к регистру значение
add [char],48 ;прибавить к памяти значение

ADC приемник,источник
Складывает оба операнда и добавляет единицу в случае, если флаг переноса установлен. Помещает результат в приемник. Правила для операндов те же, что и у ADD. Команда ADD в связке с ADC может использоваться для сложения чисел, не помещающихся целиком в регистр процессора.

DEC операнд
Команда уменьшает значение операнда на единицу. Правила для операнда те же, что и у INC.

SUB приемник,источник
Вычитает источник из приемника, помещает результат в приемник. Если источник был больше приемника, то устанавливается флаг переноса CF. Если источник был равен приемнику (результат 0), то устанавливается флаг ноля ZF. Правила для операндов те же, что и у ADD.

SBB приемник,источник
Вычитает источник из приемника, вычитает единицу в случае, если флаг переноса установлен. Помещает результат в приемник. Правила для операндов те же, что и у ADD. Команда SUB в связке с SBB может использоваться для вычитания чисел, не помещающихся целиком в регистр процессора.

CMP приемник,источник
Команда осуществляет сравнение приемника с источником способом вычитания источника из приемника, но, в отличие от SUB, результат никуда не сохраняет. По установленным командой флагам можно отследить результат такого сравнения и выполнить условный переход (JZ, JO, JC и т.п.).

NEG приемник
Изменяет знак операнда на противоположный, вычитая операнд из нуля. На практике команда применяется не только для смены знака, но и для вычитания из константы. Допустим, нам надо вычесть содержимое AX из 300. Очень хочется написать: sub 300,ax, но команда SUB не допускает возможности вычитания из непосредственного значения, потому что приемник должен являться РОН или памятью. Значит, мы могли бы предварительно поместить значение 300 в какой-то РОН, а затем вычесть из него AX, однако более простым вариантом с точки зрения процессора будет такой:
neg ax
add ax,300

Мы прибавили 300 к отрицательному значению ax, что по законам математики дает такой же результат, что и вычитание ax из 300.

XADD приемник,источник
Еще одна редкая, но иногда очень полезная команда. Она похожа на ADD, только перед тем, как поместить сумму операндов в приемник, производит обмен значениями между операндами (как команда XCHG). Эта команда одним махом выполняет сразу 2 действия, а значит, может помочь сэкономить процессорное время.
Все вышеперечисленные арифметические операции изменяют флаги SF, ZF, PF, OF в соответствии с результатом. Команды MUL(умножение) и DIV(деление) были достаточно подробно описаны в предыдущей статье, поэтому не будем повторяться, и идем дальше.

Размеры операндов арифметических команд должны быть одинаковыми. Поэтому, если необходимо произвести арифметическое действие над операндами, имеющими разные размеры, следует сначала преобразовать один из них так, чтобы оба операнда имели одинаковый размер. Для этого в системе команд процессора предусмотрены команды преобразования типов. Они служат для преобразования байтов в слова, слов — в двойные слова, двойных слов — в учетверенные (qword). Эти преобразования могут выполняться способом знакового расширения — увеличение размера операнда с учетом знака (заполнение старших разрядов увеличенного операнда значением старшего бита исходного операнда) или нулевого расширения (заполнение старших разрядов увеличенного операнда нолями).

Команды преобразования со знаковым расширением без операндов:
CBW преобразовывает байт, содержащийся в регистре AL, в слово, помещаемое в регистр AX.
CWD преобразовывает слово, содержащееся в регистре AX, в двойное слово, помещаемое в регистры DX:AX. Старшая часть значения разместится в DX, а младшая — в AX.
CWDE преобразовывает слово, содержащееся в регистре AX, в двойное слово, помещаемое в регистр EAX.
CDQ преобразовывает двойное слово, содержащееся в EAX, в учетверенное слово, помещаемое в регистры EDX:EAX.
Еще раз напомню, что все перечисленные преобразования по сути своей — лишь распространение значения старшего (знакового) бита исходного операнда на все биты добавляемой части. Эти команды работают с конкретными регистрами и поэтому не имеют операндов.

MOVSX приемник,источник
Преобразовывает с учетом знакового расширения байт в слово или двойное слово; слово — в двойное слово. Операнд-источник может быть памятью или РОН, приемник всегда должен быть РОН.

MOVZX приемник,источник
Работает так же, как и MOVSX, только производит расширение без учета знака, то есть заполняет добавляемую часть нулями, а не знаковым старшим битом источника.

Десятичная арифметика
Десятичные числа могут быть представлены в так называемом двоично-десятичном коде (Binary Coded Decimal — BCD). Этот способ предполагает хранение каждой десятичной цифры в четырех битах. Различают два формата хранения BCD-чисел:

— упакованный, когда каждый байт (8 бит) может содержать две десятичные цифры (по 4 бита каждая). В таком случае каждый байт содержит десятичное число в диапазоне от 00 до 99.

— неупакованный, когда каждый байт содержит лишь одну десятичную цифру в младших четырех битах, а старшие четыре бита имеют нулевое значение. Диапазон представления неупакованного BCD-числа в отдельно взятом байте составляет от 0 до 9.

Десятичная арифметика осуществляется методом комбинирования вышеописанных команд двоичной арифметики с командами, специально предназначенными для десятичных операций. Команды десятичной арифметики используются для приведения результата предыдущих двоичных вычислений к упакованному/неупакованному формату BCD-числа или, наоборот, для подготовки введенных данных к двоичным арифметическим операциям.

DAA корректирует результат сложения двух упакованных BCD-чисел в регистре AL. Эта команда должна следовать за командой сложения (ADD или ADC), если в сложении участвовали два упакованных BCD, и результат находится в AL. Если откорректированный результат превысит 99, то будет установлен флаг CF, а в AL останутся лишь две младшие цифры. Пример:
mov al,49h
mov bl,52h
add al,bl
daa

В данном примере наглядно показано, что упакованные BCD можно записывать просто как шестнадцатеричные числа (буковка h в конце числа означает HEX), только без использования символов ABCDEF. Когда будет произведено сложение 49h и 52h, результат будет неверным. Точнее, он будет верным, но лишь применительно к шестнадцатеричным числам, потому что процессор, складывая эти числа, считает их не упакованными десятичными, а стандартными двоичными или шестнадцатеричными, если хотите. Однако команда DAA все расставляет по своим местам, и в результате в AL получается 01 (две младшие цифры от 101), а установленный флаг CF позволяет определить, что единичка для следующего третьего разряда «в уме».

DAS работает аналогично DAA, только используется для корректировки результата вычитания. У команды также отсутствует операнд, потому что действие производится над регистром AL. Флаг CF (если установлен) указывает на то, что вычитаемое оказалось больше уменьшаемого, и необходимо это дело обработать, например, уменьшением третьего разряда на единицу.

AAA предназначена для корректировки результата сложения НЕупакованных BCD-чисел размером в байт, то есть одноразрядных. Операнды отсутствуют, действие производится над регистром AL. Если результат превышает 9, то в AL помещается лишь младший разряд, а AH увеличивается на единицу, и устанавливается флаг CF.

AAS аналогична AAA за исключением того, что применяется для корректировки вычитания неупакованных одноразрядных BCD-чисел. При необходимости заема устанавливается флаг CF, а содержимое AH уменьшается на единицу.

AAM корректирует результат умножения двух неупакованных BCD, находящийся в AL. Данная команда просто делит содержимое AL на 10 и помещает частное в AH, а остаток — в AL. Таким образом в AX помещается двухразрядное неупакованное BCD. Стандартная версия команды не имеет операндов, однако существует расширенная версия AAM, в которой в роли операнда выступает непосредственное значение — база, на которую будет производиться деление. Так что, выполнив, к примеру, команду AAM 5, вы поделите нацело содержимое AL, получив частное в AH, а остаток — в AL. Очень удобный способ для деления нацело небольших (до 8 бит) чисел.

AAD подготавливает к делению неупакованное BCD-число, находящееся в AX. Команда просто добавляет к AL содержимое AH, умноженное на 10, потом AH обнуляется. Несмотря на свое основное назначение, команда отлично справляется не только с подготовкой к делению, но и с простым преобразованием неупакованного двузначного BCD в двоичный эквивалент. Также команда может оказать неоценимую помощь в преобразовании символьного кода цифр сразу в двоичный код. Например, в таблице ASCII цифра «1» имеет код 31h, цифра «2» — 32h и т.д. Значит, для того, чтобы из символьного кода получить неупакованное BCD, нам достаточно обнулить старший шестнадцатеричный разряд (старшие 4 бита) ASCII-кода. Поместим число 15 в символьном виде в AX и переведем его в двоичное значение:
mov AX,3135h
and AX,0F0Fh ;обнуляем левые половинки байтов
aad

После выполнения этих команд в AX у нас будет 0Fh, то есть число 15 в нормальном двоичном (шестнадцатеричном) виде, привычном для процессора. В расширенном варианте команды AAD есть возможность указать в качестве операнда непосредственное значение, на которое будет умножаться AH, прежде чем прибавиться к AL. Это дает еще один вариант использования команды: быстрое умножение небольших чисел.

Что ж, на сегодня, думаю, с вас достаточно. Очень сложная тема, хотя, надеюсь, и весьма интересная. Примеров программ в газете на этот раз не будет, но вы всегда можете найти их на форуме: сайт

BarMentaLisk, SASecurity gr., q@sa-sec.org

Компьютерная газета. Статья была опубликована в номере 30 за 2008 год в рубрике программирование

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *