Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Return a value from procedure via the stack

I'm learning assembly and I have to write a procedure (function) which gets a number and returns 1 if it's an even number and 0 if it's not.

I have to return the answer not via a register or flags, but via the stack (e.g. I can't put the answer in bx or ax and check their value in the main program). How can I do that?

like image 936
user3590450 Avatar asked Oct 14 '25 20:10

user3590450


1 Answers

Next program was made with EMU8086 Intel syntax (just copy, paste and run), this is what it does : displays a message, captures a number from keyboard, converts the number from string to numeric, checks if number is even or odd, stores '1' or '0' in stack, and displays a message depending on '1' or '0'. Here it is, plenty of comments to help you understand :

.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

Notice the variable "str", used to capture the number from keyboard, uses the 3-DB format: the first DB specifies the max length (plus one for the ending chr(13)), another DB for the length of the string entered by user, and the third DB for the string itself.

Jester's is another solution for the problem. There's even a third solution : shifting the number to the right (instruction SHR), the dropped bit is stored in carry flag, then we can check if carry flag is 0 or 1 with instructions JC or JNC.

like image 97
Jose Manuel Abarca Rodríguez Avatar answered Oct 17 '25 12:10

Jose Manuel Abarca Rodríguez