Код ассемблера инициализирует массивы A
и B
, вычисляет поэлементную сумму этих массивов и сохраняет результаты в массиве C
. Он также предоставляет процедуру printarray
для печати всего содержимого массива и использует эту процедуру для вывода значений массивов A
, B
и C
на консоль. Код предполагает среду, подобную DOS, и для выполнения требуется x86-совместимая система с соответствующими инструментами сборки.
но это не дало мне никакого результата, и когда я попытался отладить, программа вышла из программы
.model small
.stack 100h
.data
A dw 12, 5, 8, -1, 4
B dw -2, 9, 0, 18, 3
C dw 5 dup (?)
N dw 5
.code
mov ax,@data
mov ds,ax
push offset A
push offset B
push offset C
push N
call arraysum
push offset A
push N
call printarray
mov ah, 2
mov dl, 10
int 21h
push offset B
push N
call printarray
mov ah, 2
mov dl, 10
int 21h
push offset C
push N
call printarray
mov ah, 2
mov dl, 10
int 21h
.exit
sum proc near
push bp
mov bp,sp
mov ax,[bp+4]
add ax,[bp+6]
pop bp
ret 4
sum endp
arraysum proc near
push bp
mov bp, sp
mov cx,[bp+4]
mov di, [bp + 10]
mov si, [bp + 8]
mov bx,[bp+6]
next:
push word ptr [di]
push word ptr [si]
call sum
pop word ptr [di]
pop word ptr [si]
mov [bx], ax
add si, 2
add di, 2
add bx, 2
dec cx
jnz next
pop bp
ret 8
arraysum endp
printnum proc near
push bp
mov bp, sp
mov ax, [bp + 4]
mov bx, 10
mov cx, 0
cmp ax, 0
jge next
neg ax
next1:
mov dx, 0
div bx
add dx, 30h
push dx
inc cx
cmp ax, 0
jne next1
mov ax,[bp+4]
cmp ax, 0
jge sof
push '-'
inc cx
sof:
cmp cx, 0
jz ext
pop dx
mov ah, 2
int 21h
dec cx
jmp sof
ext:
pop bp
ret 2
printnum endp
printarray proc near
push bp
mov bp, sp
mov cx, [bp + 4]
mov si, [bp + 6]
print_loop:
push word ptr [si]
call printnum
add sp, 2
inc si
dec cx
jnz print_loop
pop bp
ret 4
printarray endp
end
Вы не можете использовать ключевые слова в качестве имен переменных. C
— ключевое слово. Если только ты не используешь OPTION NOKEYWORD: <C>
Вот все проблемы в коде:
Проблема с кодом выхода: В коде вы используете прерывание DOS int 21h
с параметром AH, установленным на 4Ch, для выхода из программы. Однако вы не установили код выхода в AL перед вызовом этого прерывания. Вам следует загрузить код выхода в AL перед вызовом этого прерывания. Например, вы можете добавить mov al, 0
перед int 21h
, чтобы установить код выхода на 0.
Обработка отрицательных чисел. Похоже, что код обрабатывает отрицательные числа в процедуре printnum
путем добавления символа «-». Хотя это работает для отображения, фактическое число не изменяется. Если вы собираетесь работать с отрицательными числами в своей программе, вам необходимо учитывать их влияние на вычисления.
Нет обработки ошибок. В коде нет механизмов обработки ошибок. Если во время выполнения вы столкнетесь с ошибками (например, делением на ноль), программа может вести себя непредвиденно или аварийно завершить работу. Вам следует включить код проверки и обработки ошибок, чтобы сделать программу более надежной.
Код, обеспечивающий правильную работу ассемблерного кода.
Код:
.model small
.stack 100h
.data
A dw 12, 5, 8, -1, 4
B dw -2, 9, 0, 18, 3
C dw 5 dup (?)
N dw 5
.code
mov ax, @data
mov ds, ax
push offset A
push offset B
push offset C
push N
call arraysum
push offset A
push N
call printarray
mov ah, 4Ch ; Exit program with code in AL
int 21h
sum proc near
push bp
mov bp, sp
mov ax, [bp + 4]
add ax, [bp + 6]
pop bp
ret 4
sum endp
arraysum proc near
push bp
mov bp, sp
mov cx, [bp + 4]
mov di, [bp + 10]
mov si, [bp + 8]
mov bx, [bp + 6]
next:
push word ptr [di]
push word ptr [si]
call sum
pop word ptr [di]
pop word ptr [si]
mov [bx], ax
add si, 2
add di, 2
add bx, 2
dec cx
jnz next
pop bp
ret 8
arraysum endp
printnum proc near
push bp
mov bp, sp
mov ax, [bp + 4]
mov bx, 10
mov cx, 0
cmp ax, 0
jge next
neg ax
next1:
mov dx, 0
div bx
add dl, '0' ; Convert remainder to ASCII
push dx
inc cx
cmp ax, 0
jne next1
mov ax, [bp + 4]
cmp ax, 0
jge sof
push '-' ; Negative sign
inc cx
sof:
cmp cx, 0
jz ext
pop dx
mov ah, 2
int 21h
dec cx
jmp sof
ext:
pop bp
ret 2
printnum endp
printarray proc near
push bp
mov bp, sp
mov cx, [bp + 4]
mov si, [bp + 6]
print_loop:
push word ptr [si]
call printnum
add sp, 2
add si, 2
dec cx
jnz print_loop
pop bp
ret 4
printarray endp
end
и последний вопрос, ПОЧЕМУ ВЫ ИСПОЛЬЗУЕТЕ СБОРКУ!? хе-хе просто шучу
int 20h
надежно работает (на разных системах) только если CS = PSP. Если вы предлагаете _start
в качестве точки входа и .model small
и используете @data
в качестве ссылки на сегмент, вы предполагаете сегментированный исполняемый файл MZ .EXE, который может иметь CS != PSP. Наконец, чтобы «вернуть соответствующий код выхода», вы не можете использовать int 20h
, поскольку он всегда устанавливает нулевой код выхода. int 21h
с AH = 4Ch полностью заменяет int 20h
, при условии, что системы совместимы с MS-DOS v2+. (Кроме того, в вашем примере фактически не устанавливается AL для вызова функции 4Ch.)
print_loop
(ofprintarray
) полагается на то, что cx
сохраняется во время вызова printnum
; однако printnum
использует cx
так, будто его можно поцарапать, и его можно поцарапать.
Хорошо, я улучшу ответ. Я не эксперт в сборке.
Некоторые пункты вашего списка были верными; ваш ответ был лучше с этим списком исправлений, а не только с блоком кода.
ок, я тоже поставлю баллы
спасибо, что заставил меня это понять 👍
Пункт 2 не имеет смысла. Ничего о div
в целом и его использовании здесь не зависит от CS или CS==DS. div
на ненулевое значение, при dx
=0, ошибка невозможна. И делитель в bx
здесь равен 10, а не 0. Даже если бы произошла ошибка, обработчик исключений загрузил бы новый CS:IP из IVT, независимо от значения CS, пока div
пытался запуститься. Цикл обращается к памяти, но все эти доступы используют одну и ту же базу сегментов, SS, посредством push/pop (и перезагрузки функции arg). Не существует обращений mov cx, [cs: di]
, которые сделали бы CS==DS важным для работы указателей или чего-то еще. .
Хорошо, я понял, спасибо за разъяснения, я думал о другом.
Я изменил/добавил несколько вещей.
OPTION NOKEYWORD:<C>
, компилятор больше не жалуется, что это ключевое слово.push offset A, B or C
работают, когда директивы .186
,.286
,.286c
или.286p
применяются до .model
. В других случаях программа компилируется, но не выводит результат на экран или зависает. Когда .386
стоит после .model
, тоже работает. (https://stackoverflow.com/a/62603303/20889367)sum proc
строка ret 4
должна быть ret
, потому что после sum proc
программа извлекает значения и ret 4
меняет указатель стека на неправильное место.sum proc
должен быть pop word ptr [si], pop word ptr [di]
.printarray proc
, значение cx
уничтожается внутри printnum proc
, поэтому я добавил push cx / pop cx
.printnum proc
я добавил 2 байта для смещения в строках mov ax, [bp + 6]
из-за приведенных выше cx
инструкций и
процедура заканчивается на ret
, а не на ret 2
.ax = 4c00h, int 21h
.' '
между значениями.Результат:
12 5 8 -1 4
-2 9 0 18 3
10 14 8 17 7
Код:
OPTION NOKEYWORD:<C>
.286
.model small
.stack 100h
.data
A dw 12, 5, 8, -1, 4
B dw -2, 9, 0, 18, 3
C dw 5 dup (?)
N dw 5
.code
start:
mov ax,@data
mov ds,ax
; mov dx,offset A
; push dx
; mov dx, offset B
; push dx
; mov dx,offset C
; push dx
push offset A
push offset B
push offset C
push N
call arraysum
; mov dx, offset A
; push dx
push offset A
push N
call printarray
mov ah, 2
mov dl, 10
int 21h
; mov dx, offset B
; push dx
push offset B
push N
call printarray
mov ah, 2
mov dl, 10
int 21h
; mov dx, offset C
; push dx
push offset C
push N
call printarray
mov ah, 2
mov dl, 10
int 21h
exit:
mov ax,4c00h
int 21h
sum proc near
push bp
mov bp,sp
mov ax,[bp+4]
add ax,[bp+6]
pop bp
ret
sum endp
arraysum proc near
push bp
mov bp, sp
mov cx,[bp+4] ;; num rep
mov di, [bp + 10] ;; off array A
mov si, [bp + 8] ;; off array B
mov bx, [bp+6] ;; off array C
next:
push word ptr [di] ;; push elements A[i] and B[i], i = 0 .. 4
push word ptr [si]
call sum
pop word ptr [si]
pop word ptr [di]
mov [bx], ax
add si, 2
add di, 2
add bx, 2
dec cx
jnz next
pop bp
ret 8
arraysum endp
printnum proc near
push bp
mov bp, sp
mov ax, [bp + 6]
mov bx, 10
mov cx, 0
cmp ax, 0
jge next1
neg ax
next1:
mov dx, 0
div bx
add dx, 30h
push dx
inc cx
cmp ax, 0
jne next1
mov ax,[bp + 6]
cmp ax, 0
jge sof
xor ax,ax
mov al,'-'
push ax
inc cx
sof:
cmp cx, 0
jz ext
pop dx
mov ah, 2
int 21h
dec cx
jmp sof
ext:
pop bp
ret ;
printnum endp
printarray proc near
push bp
mov bp, sp
mov cx, [bp + 4]
mov si, [bp + 6]
print_loop:
push word ptr [si]
push cx
call printnum
pop cx
add sp, 2
add si,2
dec cx
mov ah, 2
mov dl, ' '
int 21h
jnz print_loop
pop bp
ret 4
printarray endp
end start
push offset A
(push imm16
) действует на 186 и позже. ОП не сказал, на какую модель процессора они ориентируются, но отметил MASM. По умолчанию MASM имеет значение .model 8086
или что-то в этом роде? Если да, то лучшим решением может быть .model 386
или хотя бы .model 286
, если вас не волнует совместимость с реальными ретро-машинами 8086 или EMU8086.
jge next
вprintnum
должно бытьnext1
. Такжеprintarray
неверно, потому что слова занимают 2 байта, а у вас есть толькоinc si
. Разбейте проблему на части. Сначала проверьте свойprintnum
, затемprintarray
и так далее. Исправьте свой отладчик, чтобы вы могли выполнять код самостоятельно.