Система команд x86 |
|
Программирование - Архитектура и система команд микропроцессоров x86 |
IMUL
Влияние команды на флаги и форматы команды:
* |
? |
? |
? |
? |
* |
F6 /5 |
IMUL r/m8 |
AX=AL*r/m8 |
8086 |
imul dl |
F7 /5 |
IMUL r/m16 |
DX:AX=AX*r/m16 |
8086 |
imul si |
F7 /5 |
IMUL r/m32 |
EDX:EAX=EAX*r/m32 |
Intel386 |
imul edi |
0F AF /r |
IMUL r16,r/m16 |
r16=r16*r/m16 |
Intel386 |
imul si,[di] |
0F AF /r |
IMUL r32,r/m32 |
r32=r32*r/m32 |
Intel386 |
imul edi,ecx |
6B /r ib |
IMUL r16,r/m16,imm8 |
r16=r/m16*(знакорасширенное imm8) |
Intel186 |
imul ax,dx,4 |
6B /r ib |
IMUL r32,r/m32,imm8 |
r32=r/m32*(знакорасширенное imm8) |
Intel386 |
imul eax,edx,4 |
6B /r ib |
IMUL r16,imm8 |
r16=r16*(знакорасширенное imm8) |
Intel186 |
imul ax,4 |
6B /r ib |
IMUL r32,imm8 |
r32=r32*(знакорасширенное imm8) |
Intel386 |
imul edx,5 |
69 /r iw |
IMUL r16,r/m16,imm16 |
r16=r/m16*(знакорасширенное imm16) |
Intel186 |
imul ax,dx,1 |
69 /r id |
IMUL r32,r/m32,imm16 |
r32=r/m32*(знакорасширенное imm16) |
Intel386 |
imul eax,edx,8 |
69 /r iw |
IMUL r16,imm16 |
r16=r16*imm16 |
Intel186 |
imul ax,8F57h |
69 /r id |
IMUL r32,imm32 |
r32=r32*imm32 |
Intel386 |
imul edx,9000 |
Описание:
Команда IMUL (Signed Multiply) относится к группе команд целочисленной (или двоичной) арифметики (Binary Arithmetic Instructions) и производит умножение двух знаковых целочисленных операндов (DEST и SRC). Существует три формы команды IMUL, которые отличаются прежде всего количеством явно задаваемых операндов.
Форма команды с одним операндом IMUL src в целом аналогична команде MUL. В этой форме операнд-назначение (DEST) задается неявно и является переменной в регистре (или регистровой паре) AX, DX:AX или EDX:EAX в зависимости от кода команды и атрибута размера операнда. Единственный операнд команды — операнд-источник (SRC) — может быть переменной в регистре или в памяти (r/m8, r/m16, r/m32). Команда перемножает содержимое аккумулятора (AL, AX или EAX) и заданный операнд-источник (SRC) и помещает результат умножения в неявно заданный операнд-назначение (DEST). То есть действие команды IMUL с единственным явно заданным операндом-источником (SRC) зависит от размера этого операнда следующим образом:
- однобайтный операнд r/m8 умножается на значение в регистре AL, результат помещается в регистр AX, флаги EFLAGS.CF и EFLAGS.OF сбрасываются, если значащие биты результата в регистре AH равны нулю (точнее — стали бы равны нулю после преобразования из дополнительного кода, см. ниже), иначе — устанавливаются в 1;
- двухбайтный операнд r/m16 умножается на значение в регистре AX, результат помещается в пару регистров DX:AX, регистр DX содержит старшие 16 бит результата, флаги EFLAGS.CF и EFLAGS.OF сбрасываются, если значащие биты результата в регистре DX равны нулю (точнее — стали бы равны нулю после преобразования из дополнительного кода, см. ниже), иначе — устанавливаются в 1.
- четырехбайтный операнд r/m32 умножается на значение в регистре EAX, результат помещается в пару регистров EDX:EAX, регистр EDX содержит старшие 32 бита результата, флаги EFLAGS.CF и EFLAGS.OF сбрасываются, если значащие биты результата в регистре EDX равны нулю (точнее — стали бы равны нулю после преобразования из дополнительного кода, см. ниже), иначе — устанавливаются в 1.
Форма команды с двумя операндами IMUL dest, src появилась в процессорах, начиная с Intel386. Она предполагает, что первый операнд (операнд-назначение, DEST) умножается на второй операнд (операнд-источник, SRC), а результат затем помещается в операнд-назначение (DEST). Операнд-назначение (DEST) может быть переменной в регистре (r8, r16, r32). Операнд-источник (SRC) — непосредственным значением (imm8, imm16, imm32), переменной в регистре или в памяти (r/m8, r/m16, r/m32). При этом только вариант с операндом-источником (SRC) в регистре или памяти являлся именно новой формой команды в процессорах Intel386. Форма команды с непосредственным значением в качестве второго операнда — это вырожденный вариант описываемой далее трехоперандной формы, у которой в качестве операнда-назначения (DEST) и первого операнда-источника (SRC1) задан один и тот же регистр.
Трехоперандная форма команды IMUL dest, src1, src2 была введена в процессорах, начиная с 80186/80188. В этой форме также явно задается операнд-назначение (DEST), который идет первым. Второй и третий операнды команды являются операндами-источниками (SRC1, SRC2). Операнды-источники (SRC1, SRC2) перемножаются и результат помещается в операнд-назначение (DEST). Операнд-назначение может быть только регистром общего назначения (r8, r16, r32), второй операнд (SRC1) может быть регистром и операндом в памяти (r/m8, r/m16, r/m32), а третий операнд (SRC2) — это непосредственное значение (imm8, imm16, imm32).
Во всех формах команды, если в качестве множителя выступает непосредственное значение imm8 или imm16, то перед умножением оно прежде всего знакорасширяется до размера операнда-множимого, и только после этого выполняется умножение.
При использовании формы команды IMUL src с одним операндом (r/m8, r/m16, r/m32) результат умножения получается корректным, даже если будет установлен флаг переполнения (EFLAGS.OF = 1) — ведь для сохранения результата используется в два раза больше разрядов, чем для множимого и множителя. Этого достаточно, чтобы отобразить любой возможный результат. Для форм команды с двумя и тремя операндами возможна потеря старших значащих битов результата из-за переполнения, когда это происходит, флаги EFLAGS.CF и EFLAGS.OF устанавливаются.
Двух и трехоперандные формы команды IMUL могут использоваться как для манипуляции знаковыми, так и беззнаковыми целочисленными значениями. В обоих случаях результат умножения, помещаемый в операнд-назначение (DEST), идентичен и не зависит от наличия/отсутствия знакового разряда в исходных операндах. Следует только учитывать, что флаги EFLAGS.CF и EFLAGS.OF все равно устанавливаются с учетом того, что старший разряд результата предназначается для отображения знака и в случае беззнаковых операндов будут индицировать переполнение при превышении результатом всех значимых разрядов операнда-назначения согласно формата со знаком. Например, при 16-битных операндах, умножая 2 * 20000, мы получим вполне корректный 16-битный результат 40000 (в беззнаковом формате) с единицей в старшем разряде, а флаги будут указывать на переполнение, так как результат не помещается в отведенные для него (согласно формата со знаком) 15 значащих разрядов.
Для получения корректного результата и правильного срабатывания флагов переполнения (именно так, как это описано выше) во всех формах команды IMUL при манипуляции данными в целочисленном формате со знаком целесообразно использовать дополнительный код. Строго говоря, сам процессор не знает того, в каком коде представлены данные для вычислений и получаемый результат целиком зависит от конкретных двоичных значений операндов команды. Но именно при использовании дополнительного кода показания флагов EFLAGS.CF и EFLAGS.OF будут действительно отвечать их смысловому предназначению — отражать факт переполнения (нехватки разрядности операнда-назначения для сохранения результата). Например, вполне возможно использовать и прямой код для знаковых операндов команды IMUL. Но в таком случае, вычисляя 16-битное произведение (-3 * 5 — 0x8003h * 0x0005h), мы получим в операнде-назначении (его младших 16 битах) корректный 16-битный результат в прямом коде (-15 — 0x800Fh), но флаги будут индицировать переполнение.
Для вычисления произведения целочисленных значений со знаком, кроме команды IMUL, могут также использоваться команды FIMUL, PMULLW и некоторые другие. Команда MUL позволяет выполнять умножение целочисленных значений в беззнаковом формате.
Операция:
IF (NumberOfOperands = 1)
THEN
IF (OperandSize = 8)
THEN
AX = AL * SRC (* Знаковое умножение *)
IF ((AH = 0x00h) OR (AH = 0xFFh))
THEN CF = 0; OF = 0;
ELSE CF = 1; OF = 1;
FI;
ELSE
IF (OperandSize = 16)
THEN
DX:AX = AX * SRC (* Знаковое умножение *)
IF ((DX = 0x0000h) OR (DX = 0xFFFFh))
THEN CF = 0; OF = 0;
ELSE CF = 1; OF = 1;
FI;
ELSE (* OperandSize = 32 *)
EDX:EAX = EAX * SRC (* Знаковое умножение *)
IF ((EDX = 0x00000000h) OR (EDX = 0xFFFFFFFFh))
THEN CF = 0; OF = 0;
ELSE CF = 1; OF = 1;
FI;
FI;
FI;
ELSE
IF (NumberOfOperands = 2)
THEN
temp = DEST * SRC (* Знаковое умножение; temp имеет удвоенный размер DEST *)
DEST = DEST * SRC (* Знаковое умножение *)
IF (temp ≠ DEST)
THEN CF = 1; OF = 1;
ELSE CF = 0; OF = 0;
FI;
ELSE (* Число операндов = 3 *)
DEST = SRC1 * SRC2 (* Знаковое умножение *)
temp = SRC1 * SRC2 (* Знаковое умножение; temp имеет удвоенный размер SRC1 *)
IF (temp ≠ DEST)
THEN CF = 1; OF = 1;
ELSE CF = 0; OF = 0;
FI;
FI;
FI;
Особые ситуации защищенного режима:
#GP(0), если операнд-назначение (DEST) находится в памяти в сегменте, запрещенном для записи.
#GP(0), если при обращении к операнду в памяти в сегменте DS, ES, FS или GS используется нулевой селектор.
#GP(0), если любая часть операнда в памяти находится вне допустимого пространства эффективных адресов в сегменте CS, DS, ES, FS или GS.
#SS(0), если любая часть операнда в памяти находится вне допустимого пространства эффективных адресов в стековом сегменте SS.
Intel386 … :
#PF(Код ошибки) при страничной ошибке.
#UD при использовании префикса LOCK.
Intel486 … :
#AC(0) при невыровненной ссылке в память, если активирован контроль выравнивания (CR0.AM = 1, EFLAGS.AC = 1, CPL = 3).
Особые ситуации режима реальной адресации:
#GP, если любая часть операнда в памяти находится вне допустимого для реального режима пространства эффективных адресов в сегменте CS, DS, ES, FS или GS.
#SS, если любая часть операнда в памяти выходит за допустимую для реального режима верхнюю границу стекового сегмента SS.
Особые ситуации режима V86:
#GP(0), если любая часть операнда в памяти находится вне допустимого пространства эффективных адресов в сегменте CS, DS, ES, FS или GS.
#SS(0), если любая часть операнда в памяти находится вне допустимого пространства эффективных адресов в стековом сегменте SS.
Intel386 … :
#PF(Код ошибки) при страничной ошибке.
#UD при использовании префикса LOCK.
Intel486 … :
#AC(0) при невыровненной ссылке в память, если активирован контроль выравнивания (CR0.AM = 1, EFLAGS.AC = 1, CPL = 3).
Замечание:
К командам целочисленной арифметики относятся команды ADD, ADC, SUB, SBB, IMUL, MUL, IDIV, DIV, INC, DEC, NEG, CMP.
В свою очередь, сами названные команды целочисленной арифметики делятся на следующие подгруппы:
Все права защищены © Алексей Ровдо, 1994-2023. Перепечатка возможна только по согласованию с владельцем авторских прав. admin@club155.ru