проблема в понимании множества инструкций языка ассемблера - PullRequest
8 голосов
/ 22 декабря 2009

Я учусь 80386 от Сборка ПК Полом Кауртером

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

прекрасный.

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

Q1: Почему DX: AX? Почему нельзя хранить в EAX / EDX?

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

imul dest, source1
imul dest, source1, source2

alt text

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

Q2: во 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

Q3: Предварительно сказано, что 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 ]

7 голосов
/ 22 декабря 2009

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

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

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

6 голосов
/ 22 декабря 2009

Существует множество различных вариаций кода imul инструкция.2 бит.

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

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

например:

  ; a 16 bit multiplication:
  mov ax, [factor1]
  mov bx, [factor2]
  imul bx              ; 32-bit result in DX:AX
  ; or  imul  word [factor2]

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

На 386 или более поздней версии вы также можете написать imul в форме двух операндов. Это делает его более гибким и простым в работе. В этом варианте вы можете свободно выбирать любые 2 регистра в качестве источника и места назначения, и ЦП не будет тратить время на запись результата с половиной. И не разрушит EDX.

  mov   ecx, [factor1]
  imul  ecx, [factor2]    ; result in ecx, no other registers affected
  imul  ecx, ecx          ; and square the result

Или для подписанных 16-битных входов, соответствующих вашему imul. (используйте movzx для входных данных без знака)

  movsx   ecx, word [factor1]
  movsx   eax, word [factor2]  ; sign-extend inputs to 32-bit
  imul    eax, ecx             ; 32-bit multiply, result in EAX
  imul    eax, eax             ; and square the result

Этот вариант imul был введен с 386 и доступен в 16- и 32-битном размере операнда. (И 64-битный размер операнда в 64-битном режиме).

В 32-битном коде вы всегда можете предположить, что доступно 386 инструкций, таких как imul reg, reg/mem, но вы можете использовать его в 16-битном коде, если вам не нужны старые процессоры.

286 ввел 3-операндную немедленную форму.

imul  cx, bx, 123        ; requires 286

imul  ecx, ebx, 123      ; requires 386
3 голосов
/ 05 ноября 2013

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

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

Q3: в вышеприведенном коде мы не рассматривали 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 для умножения как со знаком, так и без знака, потому что

1 голос
/ 22 декабря 2009

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

A2: См. A1.

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

1 голос
/ 22 декабря 2009

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

Q3: младшие биты будут в EAX. Это единственное, что вас волнует, если только нет переполнения в старшие биты.

Q4: Определенно нечетная таблица. Я думаю, что вы поняли, хотя.

...