assembly - 通过堆栈从过程返回一个值

标签 assembly stack procedure

我正在学习汇编,我必须编写一个过程(函数),它获取一个数字,如果它是偶数则返回 1 ,如果不是偶数则返回 0

我必须不是通过寄存器或标志返回答案,而是通过堆栈返回答案(例如,我无法将答案放入 bxax 并检查它们的主程序中的值)。我怎样才能做到这一点?

最佳答案

下一个程序是使用 EMU8086 Intel 语法制作的(只需复制、粘贴和运行),它的作用是:显示一条消息,从键盘捕获一个数字,将数字从字符串转换为数字,检查数字是否为偶数或odd,将“1”或“0”存储在堆栈中,并根据“1”或“0”显示一条消息。这里有很多评论可以帮助您理解:

.stack 100h
;------------------------------------------
.data
msj1  db 13,10,'Enter the number: $'
msj2  db 13,10,'The number is even$'
msj3  db 13,10,'The number is odd$'
str   db 6 ;MAX NUMBER OF CHARACTERS ALLOWED (5).
      db ? ;LENGTH (NUMBER OF CHARACTERS ENTERED BY USER).
      db 6 dup (?) ;CHARACTERS ENTERED BY USER. 
;------------------------------------------
.code          
;INITIALIZE DATA SEGMENT.
  mov  ax, @data
  mov  ds, ax

;DISPLAY MESSAGE.
  call clear_screen  ;DECLARED AT THE END OF THIS CODE.
  mov  ah, 9
  mov  dx, offset msj1
  int  21h

;CAPTURE NUMBER FROM KEYBOARD AS STRING.
  mov  ah, 0Ah
  mov  dx, offset str
  int  21h

;CONVERT CAPTURED NUMBER FROM STRING TO NUMERIC.
  mov  si, offset str ;PARAMETER FOR STRING2NUMBER.
  call string2number ;NUMBER RETURNS IN BX. 

;CALL PROC TO FIND OUT IF NUMBER IS EVEN OR ODD. THE INSTRUCTION
;"CALL" WILL PUSH IN STACK THE ADDRESS OF THIS INSTRUCTION, THAT'S 
;HOW IT KNOWS HOW TO COME BACK HERE TO CONTINUE EXECUTION.
  call even_or_odd

;GET RESULT FROM STACK.
  pop  ax  

;DISPLAY RESULT.
  cmp  al, '1'
  je   even_number

;IF NO JUMP, AL == '0'.  
  mov  ah, 9
  mov  dx, offset msj3
  int  21h           
  jmp  wait_for_key  ;SKIP "EVEN_NUMBER".
even_number:  
  mov  ah, 9
  mov  dx, offset msj2
  int  21h           

;WAIT FOR USER TO PRESS ANY KEY.
wait_for_key:
  mov  ah,7
  int  21h

;FINISH THE PROGRAM.
  mov  ax, 4c00h
  int  21h           

;------------------------------------------
;THIS PROCEDURE RETURNS '1' IN STACK IF THE NUMBER
;IS EVEN OR '0' IF IT'S ODD.
;ASSUME THE NUMBER COMES IN BX.

proc even_or_odd
;DIVIDE NUMBER BY 2.    
  mov  ax, bx
  mov  bl, 2
  div  bl  ;AX / BL (NUMBER / 2). RESULT : QUOTIENT=AL, REMAINDER=AH.

;IF REMAINDER IS 0 THEN NUMBER IS EVEN, ELSE IT'S ODD.
  cmp  ah, 0
  je   its_even

;IF NO JUMP, IT'S ODD.
  mov  ax, '0'  ;VALUE TO STORE IN STACK.
  jmp  finish   ;SKIP "ITS_EVEN".
its_even:  
  mov  ax, '1'  ;VALUE TO STORE IN STACK.
finish:

;STORE VALUE IN STACK. IMPORTANT: WHEN THIS PROCEDURE
;WAS CALLED, THE RETURN ADDRESS WAS PUSHED IN STACK. TO
;RETURN THE VALUE IN STACK IT'S NECESSARY TO RETRIEVE
;THE RETURN ADDRESS FIRST, PUSH THE VALUE ('0' OR '1')
;AND PUSH THE RETURN ADDRESS BACK.
  pop  bx  ;RETRIEVE RETURN ADDRESS FROM THE CALL.
  push ax  ;VALUE TO RETURN ('0' OR '1').
  push bx  ;PUT RETURN ADDRESS BACK.

  ret  ;THIS "RET" POPS THE RETURN ADDRESS. THIS IS HOW
endp   ;IT KNOWS HOW TO RETURN WHERE THE PROC WAS CALLED.  

;------------------------------------------
;CONVERT STRING TO NUMBER IN BX.
;SI MUST ENTER POINTING TO THE STRING.

proc string2number
;MAKE SI TO POINT TO THE LEAST SIGNIFICANT DIGIT.
  inc  si ;POINTS TO THE NUMBER OF CHARACTERS ENTERED.
  mov  cl, [ si ] ;NUMBER OF CHARACTERS ENTERED.                                         
  mov  ch, 0 ;CLEAR CH, NOW CX==CL.
  add  si, cx ;NOW SI POINTS TO LEAST SIGNIFICANT DIGIT.

;CONVERT STRING.
  mov  bx, 0
  mov  bp, 1 ;MULTIPLE OF 10 TO MULTIPLY EVERY DIGIT.
repeat:
;CONVERT CHARACTER.                    
  mov  al, [ si ] ;CHARACTER TO PROCESS.
  sub  al, 48 ;CONVERT ASCII CHARACTER TO DIGIT.
  mov  ah, 0 ;CLEAR AH, NOW AX==AL.
  mul  bp ;AX*BP = DX:AX.
  add  bx,ax ;ADD RESULT TO BX. 
;INCREASE MULTIPLE OF 10 (1, 10, 100...).
  mov  ax, bp
  mov  bp, 10
  mul  bp ;AX*10 = DX:AX.
  mov  bp, ax ;NEW MULTIPLE OF 10.  
;CHECK IF WE HAVE FINISHED.
  dec  si ;NEXT DIGIT TO PROCESS.
  loop repeat ;COUNTER CX-1, IF NOT ZERO, REPEAT.

  ret 
endp    

;------------------------------------------
proc clear_screen
  mov  ah,0
  mov  al,3
  int  10H
  ret
endp

注意变量“str”,用于从键盘捕获数字,使用 3-DB 格式:第一个 DB 指定最大长度(加一表示结尾 chr(13)),另一个 DB 指定长度用户输入的字符串,第三个 DB 为字符串本身。

Jester's 是该问题的另一种解决方案。甚至还有第三种解决方案:将数字右移(指令SHR),丢弃的位存储在进位标志中,然后我们可以用指令JC或JNC检查进位标志是0还是1。

关于assembly - 通过堆栈从过程返回一个值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29757653/

相关文章:

c# - 堆栈 <> C# 中的实现

function - Inno Setup Could not call proc 错误?

assembly - IBM 5150 - int 21h 损坏段寄存器

assembly - 如何让 gdb 反汇编整个函数?

assembly - 在实模式下使用 x86 程序集处理 HTTP 请求

database - 带有创建和游标的 PL/SQL 过程

mysql - 如何在Mysql过程中使用两个while语法

linux - 汇编 linux 中的 float

python - 是否可以以编程方式构造Python堆栈框架并在代码中的任意点开始执行?

arrays - 在c中使用堆栈对int数组进行排序