Ответ 1
Вам очень нужно начать использовать пробелы, чтобы отделить ваш код сборки. Этот код делает что-то чрезвычайно простое (разделение одного числа на другое), но его чрезвычайно трудно читать. Это, очевидно, не так: простой код должен быть прост для чтения! Почему трудно читать? Потому что у вас есть весь ваш шаблонный код, застрявший против кода, который фактически выполняет операцию деления, и мои глаза просто глазуруют. Я не могу выделить важные биты из шаблона. Пробелы свободны; не бойтесь этого. Ваш ассемблер не против.
Напиши так:
data segment
num1 dw 0204h
num2 db 02h
quotient db ?
remainder db ?
data ends
code segment
assume cs:code, ds:data
start:
; Initialize Data Segment (DS)
mov ax, data
mov ds, ax
; Do the division and save the results
mov ax, num1
div num2
mov quotient, al
mov remainder, ah
; Terminate process
; (Note that you should also be setting AL to a result code here!)
mov ah, 4ch
int 21h
end start
code ends
Теперь, не намного ли более понятно, что? Кроме того, в то время как MASM/TASM позволят вам избежать неприятностей, не попадайте в плохие привычки. Это еще один способ сделать ваш код нечитаемым и получить неправильные результаты. Существует два разных способа использования символов в коде: один из способов - использовать адрес/смещение этого символа, а другой способ - использовать содержимое/значение этого символа. В MASM/TASM, когда вам нужен адрес/смещение, вам нужно использовать ключевое слово OFFSET
. Когда вы используете содержимое/значение, вам не требуется технически, но вы действительно должны обернуть символ в скобках, указав, что он разыменован. Другими словами, вместо:
mov ax, num1
напишите:
mov ax, [num1]
С этим отрывом от груди, давайте посмотрим, что не так с вашим кодом. Майкл Пётч уже отметил, что это еще один случай, когда MASM/TASM "делают то, что я имею в виду, а не то, что я пишу", это не делает вам никаких выгод. Он выполняет 8-разрядное деление, потому что вы использовали 8-битный операнд (num2
) с инструкцией DIV
. Это означает, что он действительно делает:
AX / [num2]
с коэффициентом в AL
, а остаток в AH
. Если коэффициент больше 8 бит, он не будет вписываться в AL
, и деление будет переполняться.
Обходной путь состоит в том, чтобы выполнить 16-битное деление, и в этом случае фактор будет помещен в AX
, а остаток будет помещен в DX
.
Чтобы получить это, напишите код:
mov ax, [num1] ; AX = [num1]
xor dx, dx ; DX = 0
xor bx, bx ; BX = 0
mov bl, [num2] ; BL = [num2], BH = 0
div bx ; DX:AX / BX
mov [quotient], ax
mov [remainder], dx
(Так как это также clobbering BX
, вы можете сохранить его исходное значение, выполнив push bx
вверху и pop bx
в конце.)
Документация для инструкции DIV
содержит удобную таблицу, в которой показано, как 8-разрядные, 16-разрядные и 32-разрядные подразделения работа:
Operand Size | Dividend | Divisor | Quotient | Remainder | Maximum Quotient
--------------------------------------------------------------------------------------
Word/byte | AX | r/m8 | AL | AH | 2^8 - 1
Doubleword/word | DX:AX | r/m16 | AX | DX | 2^16 - 1
Quadword/doubleword | EDX:EAX | r/m32 | EAX | EDX | 2^32 - 1
"divisor" является единственным операндом для команды DIV
. "Дивиденд" неявный. Обратите внимание, что "r/m" означает либо регистр, либо операнд памяти.