#assembly #x86 #masm #16-bit #parity
#сборка #x86 #masm #16-разрядный #проверка четности
Вопрос:
Я пытаюсь написать подпроцедуру, которая будет подсчитывать количество ошибок, установленных в 16-битном числе, а затем отправлять это число (набор битов) обратно в основную процедуру в AX. Основной должен отображать количество единиц и определять, является ли число четным или нечетным.
Я пытаюсь подсчитать единицы, сдвигая влево и увеличивая при переносе. Проблема, похоже, в том, что когда я возвращаюсь к «main», исходное входное число по-прежнему находится в AX, а не в количестве, которое я получил в «parity». Я не знаю, почему оно не меняется.
;===================================================================
; MAIN.ASM
;===================================================================
EXTERN GETDEC$:FAR
EXTERN NEWLINE:FAR
EXTERN PUTSTRNG:FAR
EXTERN PUTDEC$:FAR
EXTERN PUTBIN:FAR
EXTERN PARITY:FAR
;===================================================================
.MODEL LARGE
.STACK 512
;===================================================================
; D A T A S E G M E N T D E F I N I T I O N
.DATA
NUMBER DW ?
PROMPT DB 'Enter a number: '
BINDISPLAY DB 'Number in binary: '
ONESDISPLAY DB 'Number of 1s: '
ODDDISPLAY DB 'The number of 1s is odd. '
EVENDISPLAY DB 'The number of 1s is even. '
;===================================================================
; C O D E S E G M E N T D E F I N I T I O N
.CODE
ASSUME DS:DGROUP
;===================================================================
MAIN PROC
MOV AX,DGROUP ;SET DS-REGISTER TO POINT TO
MOV DS,AX ;DATA SEGMENT
MOV ES,AX ;AND ES ALSO
CALL NEWLINE
MOV DI, OFFSET PROMPT
MOV CX, SIZEOF PROMPT
CALL PUTSTRNG
CALL GETDEC$
CALL NEWLINE
MOV DI, OFFSET BINDISPLAY
MOV CX, SIZEOF BINDISPLAY
CALL PUTSTRNG
CALL PUTBIN
PUSH AX
CALL PARITY
CALL NEWLINE
CALL NEWLINE
MOV DI, OFFSET ONESDISPLAY
MOV CX, SIZEOF ONESDISPLAY
CALL PUTSTRNG
POP AX
CALL PUTDEC$
CALL NEWLINE
SUB DX, DX
MOV BX, 2
DIV BX
CMP DX, 0
JNE ODDS
MOV DI, OFFSET EVENDISPLAY
MOV CX, SIZEOF EVENDISPLAY
CALL NEWLINE
CALL PUTSTRNG
JMP EXIT_PROGRAM
ODDS:
MOV DI, OFFSET ODDDISPLAY
MOV CX, SIZEOF ODDDISPLAY
CALL NEWLINE
CALL PUTSTRNG
EXIT_PROGRAM:
.EXIT
MOV AX, 4C00H
INT 21H
MAIN ENDP
END MAIN
;;===================================================================
; Veronica Kaufman
; CISP 310
; PARITY.ASM
;===================================================================
.MODEL LARGE
;===================================================================
; D A T A S E G M E N T D E F I N I T I O N
.DATA
ONES_COUNT DW 0
;===================================================================
; C O D E S E G M E N T D E F I N I T I O N
.CODE
ASSUME DS:DGROUP
;===================================================================
PARITY PROC FAR PUBLIC USES CX DX DS
POP AX
NUM_LOOP:
CMP AX, 0
JE END_PROGRAM
SHL AX, 1
JC INCREMENT
JMP NUM_LOOP
INCREMENT:
INC ONES_COUNT
JMP NUM_LOOP
END_PROGRAM:
MOV AX, ONES_COUNT
PUSH AX
RET
PARITY ENDP
END PARITY
Комментарии:
1. Знаете ли вы, что у x86 есть флаг четности? Она работает только с младшим байтом результата, но это все еще довольно хорошо. В имеющемся у вас коде вы можете использовать
ADC
для уменьшения разветвленности.
Ответ №1:
Я предполагаю, что цель этого заключается в том, что PARITY
примет аргумент в стеке, а затем изменит этот аргумент, оставив его в том же месте в стеке:
; (This does not work, see below)
...
PUSH AX ; input value
CALL PARITY ; want this to change it in-place...
...
POP AX ; ...so that this pops off the output value
CALL PUTDEC$
...
PARITY PROC FAR PUBLIC USES CX DX DS
POP AX ; get argument from stack
...
PUSH AX ; put result back on stack
RET
Это не сработает по двум причинам:
CALL
Помещает адрес возврата в стек.- Код пролога, сгенерированный
PROC
…USES
, помещает больше материала в стек.
Когда вы POP AX
внутри PARITY
, вы на самом деле извлекаете что-то совершенно другое (а затем возвращаете что-то другое на свое место) — вероятно, один из других регистров, сохраненных в прологе.
Варианты правильного выполнения:
-
Если вы понимаете, что здесь используются соглашения о вызовах, вы должны быть в состоянии найти местоположение
AX
, которое было помещено в стек, скорее всего, с небольшим смещением отBP
регистра (я недостаточно знаком с MASM, чтобы точно знать, что в этом случае делаетPROC
сгенерированный код пролога), и загрузить / сохранить его напрямую. -
Или, заставьте
PARITY
принимать его входные данные и возвращать его выходные данные непосредственно вAX
регистре. В этом случае вам нужно будет удалитьPUSH AX
передCALL PARITY
(ввод уже введенAX
) и вместо этого поместить его непосредственно послеCALL
(чтобы сохранить возвращенный результат, который будет выведен позже — я предполагаю, что егоAX
необходимо сохранить, потому что он может быть поврежден другими вызовами); и удалитеPOP AX
иPUSH AX
изPARITY
.