Ассамблея 8086 | Сумма массива, печать многозначных чисел

Я написал довольно простой код в asm x8086, и я столкнулся с ошибкой. Если бы кто-нибудь мог мне помочь с кратким объяснением, я бы очень признателен.

IDEAL
MODEL small
STACK 100h
DATASEG
; --------------------------
    array db 10h, 04h, 04h, 04h, 04h, 04h, 04h, 04h, 04h, 04h
    sum db 0
    ; --------------------------
CODESEG
start:
    mov ax, @data
    mov ds, ax
; --------------------------
    xor cx, cx
    mov al, 0
    mov bx, offset array
StartLoop:
    cmp cx, 10
    jge EndLoop
    add al, [bx]
    add [sum],al
    inc cx
    inc bx
    jmp StartLoop
EndLoop:
    mov ah, 09h
    int 21h

; --------------------------

exit:
    mov ax, 4c00h
    int 21h
END start

Ответ 1

С исправлением для add, которое должно быть заменено на mov, как отмечено в вашем комментарии (обратите внимание, что строка: add al, [bx] - фактически mov al, [bx]), там просто вызов функции в ярлык EndLoop, что неправильно!

Вы хотите отобразить сумму и используете функцию печати DOS. Эта функция 09h ожидает указателя в DS: DX, который вы не предоставляете!
Даже если вы это сделали, вам все равно придется преобразовать номер суммы в его текстовое представление.

Быстрое решение здесь состояло бы в том, чтобы самому конкретизировать себя и просто отобразить результат в виде одного символа ASCII. Жестко закодированная сумма равна 52 и поэтому является отображаемым символом:

EndLoop:
    mov dl, [sum]
    mov ah, 02h    ;Single character output
    int 21h

; --------------------------

exit:
    mov ax, 4c00h
    int 21h

Еще один шаг, и мы можем отобразить "52":

mov al,[sum]
mov ah,0
mov dl,10
div dl        ---> AL=5   AH=2
add ax,3030h  ---> AL="5" AH="2"
mov dh,ah     ;preserve AH
mov dl,al
mov ah,02h
int 21h
mov dl,dh     ;restore
int 21h

Ответ 2

Я вообще не вижу никакой ошибки, код будет суммировать массив, отображать некоторые случайные sh * t и выходить.

Вероятно, вы хотите отобразить результат суммы?

int 21h, ah=9 отобразит '$' завершенную строку из памяти, на которую указывает dx.

Итак, вам нужно две вещи: преобразуйте число в [sum] в строку, завершенную '$' в конце, а затем установите dx в преобразованную строку перед этим int 21h.

Вы можете попробовать извлечь из него процедуру number2string: fooobar.com/info/2523/...

Я лично изменил бы его, чтобы адрес целевого буфера в si был еще одним аргументом вызова (т.е. просто удалите mov si,offset str из тела процедуры). Вот так:

PROC number2string
  ; arguments:
  ;  ax = unsigned number to convert
  ;  si = pointer to string buffer (must have 6+ bytes)
  ; modifies: ax, bx, cx, dx, si
    mov  bx, 10  ; radix 10 (decimal number formatting)
    xor  cx, cx  ; counter of extracted digits set to zero
number2string_divide_by_radix:
  ; calculate single digit
    xor  dx, dx  ; dx = 0 (dx:ax = 32b number to divide)
    div  bx      ; divide dx:ax by radix, remainder will be in dx
  ; store the remainder in stack
    push dx
    inc  cx
  ; loop till number is zero
    test ax, ax
    jnz  number2string_divide_by_radix
  ; now convert stored digits in stack into string
number2string_write_string:
    pop  dx
    add  dl, '0' ; convert 0-9 value into '0'-'9' ASCII character encoding
  ; store character at end of string
    mov  [si], dl
    inc  si
  ; loop till all digits are written
    dec  cx
    jnz  number2string_write_string
  ; store '$' terminator at end
    mov  BYTE PTR [si],'$'
    ret
ENDP

Затем, чтобы вызвать это на вашем EndLoop, вам нужно добавить в сегмент данных numberStr DB 8 DUP (0), чтобы иметь буфер памяти, выделенный для строки, и добавить в код:

    ; load sum as 16b unsigned value into ax
      xor  ax,ax      ; ax = 0
      mov  al,[sum]   ; ax = sum (16b zero extended)
    ; convert it to string
      mov  si,OFFSET numberStr
      call number2string
    ; display the '$' terminated string
      mov  dx,OFFSET numberStr
      mov  ah,9
      int  21h
    ; ... exit ...