проблема в понимании инструкций mul & imul языка ассемблера

Я учусь 80386 от сборка ПК paul caurter

  mul source
  • если операнд имеет размер байта, он умножается на байт в AL регистрация и результат сохраняется в 16 бит AX.

хорошо.

  • если источник 16-разрядный, он умножается на слово в AX и 32-разрядный результат хранится в DX: AX.

Вопрос 1: почему DX: AX ? Почему он не может хранить в EAX / EDX?

imul - это действительно сбивает с толку

imul dest, source1
imul dest, source1, source2

alt текст http://img697.imageshack.us/img697/8976/imul.gif

у меня проблемы с пониманием таблицы.

Вопрос 2: во 2-й записи таблицы. Опять же, почему DX: AX. Почему не EAX или EDX?

Теперь рассмотрим следующий код фрагмент:

imul eax ; edx:eax = eax * eax
mov ebx, eax ; save answer in ebx
mov eax, square_msg ; square_msg db "Square of input is ", 0
call print_string ; prints the string eax
mov eax, ebx 
call print_int ;  prints the int stored in eax
call print_nl ; prints new line

Вопрос 3: его previsously сказал, что The notation EDX:EAX means to think of the EDX and EAX registers as one 64 bit register with the upper 32 bits in EDX and the lower bits in EAX. таким образом, ответ также хранится в edx, верно? в приведенном выше коде мы не рассматривали EDX, мы просто ссылаемся на EAX Как это все еще работает?

Q4: у меня проблема с остальными записями в таблице. в худшем случае результат умножения двух N разрядных чисел (n = 8/16/32 бит) составляет 2n бит. Почему его хранение результата двух 16/32 бит умножения приводит к регистру тот же самый размер?

5 ответов


Q1/Q2: набор инструкций x86 сохраняет свою 16-разрядную историю. При выполнении 16-битного умножения ответ сохраняется в DX: AX. Так оно и есть, потому что так было в 16-битной стране.

Q3: код, который вы показали, имеет ошибку, если вы пытаетесь вычислить квадрат числа больше 2^16, потому что код игнорирует высокие 32 бита результата, хранящегося в edx.

Q4: я думаю, вы, возможно, неправильно читаете таблицу. 8-разрядные умножения хранятся в 16-разрядном результат; 16-разрядные умножения хранятся в 32-разрядном результате; 32-разрядные умножения хранятся в 64-разрядном результате. На какую конкретно линию вы ссылаетесь?


да ладно..

существует множество различных вариантов инструкции imul. И что еще хуже, они работают по-разному, если вы пишете 16-битный код против 32-битного кода.

вариант, на который вы наткнулись, - это 16-битное умножение. Он умножает регистр AX на все, что вы передаете в качестве аргумента imul, и сохраняет результат в DX:AX.

один 32-битный вариант работает как 16-битное умножение, но записывает регистр в EDX: EAX. Использовать это вариант все, что вам нужно сделать, это использовать 32-битный аргумент.

например:

  ; a 16 bit multiplication:
  mov ax, factor1
  mov bx, factor2
  imul bx  ; result in DX:AX

  ; a 32 bit multiplication:
  mov eax, factor1
  mov ebx, factor2 
  imul ebx ; result in EDX:EAX

в 32-битном коде вы также можете написать imul в форме трех операндов. Это делает его более гибким и легким в работе. В этом варианте вы можете свободно выбирать регистр назначения и аргументы, но результат будет только 32 бита. Этот вариант imul не существует для 16-битного кода btw...

  mov eax, factor1
  mov ebx, factor2
  imul ecx, eax, ebx  ; result in ecx

Q1/Q2: почему DX: AX ? Почему он не может хранить в EAX / EDX?

как говорили другие, это только для обратной совместимости. Оригинал (i)mul инструкции от 16-битного x86, который пришел долго до появления 32-разрядного набора инструкций x86, поэтому они не могли сохранить результат в eax/edx с не было электронного регистра.

Вопрос 3: в выше кода мы не рассматривали EDX, мы просто ссылаемся на EAX, как это все еще работает?

вы ввели небольшие значения, которые не вызывают переполнения результата, поэтому вы не видели различий. Если вы используете достаточно большие значения (>=16 бит), вы увидите, что EDX != 0 и результат печати будет неверным.

Q4: как получилось, что он хранит результат двух 16/32 бит умножения в регистре одинакового размера себя?

дело не в том, что результат все тот же размер как операнды. умножение двух n-разрядных значений всегда приводит к 2n-разрядному значению. Но в imul r16, r/m16[, imm8/16] и их 32/64-разрядные аналоги высокие N-разрядные результаты отбрасываются. Они используются, когда вам нужно только понизьте 16/32/64 бита результата (т. е. для расширяющегося умножения), или когда вы можете убедиться, что результат не переполнение.

  • форма двух операндов - с этой формой целевой операнд (первый операнд) умножается на исходный операнд (второй операнд). Операнд назначения является регистром общего назначения, а исходный операнд-непосредственным значением, регистром общего назначения или хранилищем памяти. промежуточный продукт (в два раза больше входного операнда) усекается и сохраняется в месте назначения операнда.
  • [... То же самое для формы трех операндов]

https://www.felixcloutier.com/x86/IMUL.html

современные компиляторы в настоящее время почти исключительно используют мульти-операнд imul как для знаковых, так и для беззнаковых умножений, потому что


Q1 / Q2: я думаю, что причина историческая. До 32-разрядный вариант, нет еах или edX. 32-разрядная функциональность была добавлена для обратной совместимости.

Q3: биты низкого порядка будут находиться в eax. Это единственные, о которых вы заботитесь, если нет переполнения в высокие биты.

Q4: определенно нечетная таблица. Но я думаю, ты понимаешь.


A1: mul первоначально присутствовал на процессорах 8086/8088/80186/80286, которые не имели регистров E** (E для расширенных, т. е. 32-разрядных).

А2: См. A1.

поскольку моя работа в качестве программиста ассемблерного языка перешла в семейство Motorola 680x0 до того, как эти 32-битные Intels стали обычным явлением, я остановлюсь на этом : -)