7.
The stack is an area of memory reserved for temporary storage of program data. Many x86 instructions use the stack area implicitly during their operation. If a subroutine needs memory for temporary storage, the memory should be allocated from the stack area.
Understand:
A. The need and use of the stack and the stack memory segment
B. Procedures
C. Allocating data on the stack via ENTER, LEAVE
The stack is an area of memory reserved for temporary storage of program data and subroutine return addresses. The stack utilizes Last-In-First-Out memory organization. There are two common instructions associated with the stack, PUSH and POP.
Use the Register command on DEBUG or MASM to display the contents of the internal registers for the processor. If you use DEBUG, you must include a breakpoint (INT 3) after each instruction or trace through the code. If using MASM set the breakpoint and step through the code,
What are the values for SP, BX, and CX?
Assemble the instruction MOV SP,1000 then add a breakpoint and view the registers again , what is the address of the stack pointer now? Dump the contents of memory at that address. Did any of the registers change content? If so, which ones and to what?
Assemble the instruction PUSH BX and add a breakpoint. List the contents of the internal registers again. What is SP? What are the contents of memory at that address?
Assemble PUSH CX again list the contents of the internal registers. What is SP? What are the contents of memory at that address? What are the effects of the PUSH instructions to SP? to memory at that location?
The registers should be removed from the stack in the reverse order that they were placed. Assemble the instruction POP CX. What is SP? What are the contents of memory at that address? Assemble the instruction POP BX . What is SP? What are the contents of memory at that address? What are the effects of the POP instructions to SP? to memory at that location?
main main dummy dummy
Other instructions that access the stack segment include CALL and RET. The address of the subroutine is saved (pushed) onto the stack with the CALL and then popped off with the RET. This enables the program to continue where it left off. Similarly, INT and IRET pushes an address onto the stack prior to the interrupt routine and IRET pops it off in order to resume the program.
Assemble and trace the program below:
Example 7.1
.model medium
.stack 100h
.data db 100h dup (?)
.code
proc near call dummy mov ah,4ch int 21h int 20h
endp proc near nop ret endp end main ; entry point of program
Look at value of the SP before the 'call', and while in the 'dummy' procedure. Justify the values that get stored on the stack.
Change the line "dummy proc near" to "dummy proc far". Reassemble and trace the program.
Look at value of the SP before the 'call', and while in the 'dummy' procedure. Justify the values that get stored on the stack. How did the 'far' procedure call effect the stack contents? Why?
Other instructions that access the stack segment include ENTER, LEAVE. The ENTER instruction has two arguments - the first is a constant that specifies the number of bytes to reserve on the stack, the other specifies the procedure's nesting level (will always be '0' in our case). The space allocated on the stack vial
ENTER is known as a stack frame . The BP register is used to point to this data area. An example of
ENTER/LEAVE is shown below:
;; allow PENTIUM instructions
Asub
.586 proc near
ENTER 8, 0
;;; other instructions
LEAVE ret
This is equivalent to:
Asub proc near
PUSH BP ;save BP (old frame pointer)
MOV BP,SP ; save beginning of stack space for this sub
SUB SP,8 ;allocate space on stack
;;;; other instructions
MOV SP,BP ; free space on stack
POP BP
RET
; restore old BP
The ENTER/LEAVE instructions were first added with the x286 processor. The ".586" assembler directive above is needed to tell the assembler to allow all non-priviledged Pentium instructions (this will also allow all instructions from previous versions of the x86 architecture such as the 186, 286, 386 and 486).
Modify the 'dummy' procedure in Example 7.1 to include the instruction "ENTER 8,0" before the
NOP instruction, and the "LEAVE" instruction before the RET (also add the .586 assembler directive). Verify that the SS, BP are modified as expected. If the LEAVE statement was left off by mistake, and the subroutine was called in a repeated loop, what problems would you expect?
Well designed subroutines should use the stack area for any temporary storage needed, and also save any registers that are affected during subroutine operation. The standalone program called 'exam2.asm' (linked to the web page for this lab) prompts the user for an unsigned decimal number in the range 0-65535, inputs the number, then prints this number as a 4-digit hex number. Study this program, assemble it, and execute it. Test it out with a few numbers. Note that you can enter up to 5 decimal digits (0 to 99999). Also note that the exam2.asm uses some memory space labled 'inbuf' for accepting the digit string from the user.
What happens if you enter a number greater than 65535? Why??
We would like to have this functionality encapsulated as a subroutine called get_16bit . The subroutine get_16bit would be passed the address of the prompt string on the stack; print the prompt string to the console, input the digits from the user, convert these digits to a 16-bit number, and then return the 16-bit number in register AX. Additionally, the subroutine should set the C flag if a number greater than 65535 is entered by the user, and set the Z flag if the user enters no number at all (just hits the 'enter' key).
Look at the program called 'skel.asm' linked to the web page. This program calls the get_16bit subroutine, and duplicates the functionality of the 'exam2.asm' program. However, the body of the get_16bit subroutine has been left empty. You need to complete the body of the get_16bit subroutine implementing the functionality as described. Use the exam2.asm
program as a guide for implementing the decimal to hex conversion functionality. ANY memory storage needed by the get_16bit subroutine MUST BE
ALLOCATED ON THE STACK. You CANNOT simply allocate a static data storage for the input digits as was done in the exam2.asm program via the inbuf space.
Answer the Think About it Questions. Include in your report stack diagrams for the instructions in section
A, B, C.
Complete program described in section D, and include a listing file in your report. You also need to demonstrate correct operation to the TA. Show a stack diagram for your get_16bit subroutine that shows how the stack is used by your subroutine.