ICS 312 Set 11 Introduction to Subroutines All
ICS 312 Set 11 Introduction to Subroutines
All the combinations in which a subroutine can be written 1. The subroutine may be: a. Internal or b. External 2. The type of CALL employed can be: a. NEAR (pushing the return address and flags onto the stack) b. FAR (as above, but in addition pushing the code segment reg) 3. Arguments can be passed: a. through registers (as used by INT subroutine calls) b. using EXTRN and PUBLIC (global variables) c. using the stack (as used by all compilers) When using the stack to pass arguments: 4. arguments can be pushed onto the stack: a. from left to right (as occur in the source program “call” stmt. ) b. from right to left 5. a. the value of the arguments can be pushed (call by value) b. the offsets of the arguments can be pushed (call by reference) 6. The stack pointer can be restored to its value before the call by: a. the subroutine (as in Visual Basic) b. the calling program (as in C/C++)
Definitions n n If a high-order language implements a call instruction, similar to e. g. “call sub 2(x, y, z)”, by pushing x (i. e. the value of x, or its offset) onto the stack, then y, then z, it is said to push its arguments onto the stack from left to right. If it first pushes z, then y, then x, then it is said to push its arguments onto the stack from right to left.
n n If the high-order language implements a call statement by pushing onto the stack the value of the call statement’s arguments, then it is said to perform a call by value If, instead, it pushes onto the stack the offsets of these arguments, then it is said to perform a call by reference
Assume that a subroutine has e. g. 5 arguments Pushing these arguments onto the stack will reduce the stack pointer SP by 10. We say that the calling program restores the stack (i. e. sets SP to its original value) if the subroutine ends up with the “ret” instruction, and the calling program subsequently executes the instruction ADD SP, 10 We say that the subroutine restores the stack, if it ends up with a “ret 10” instruction
n n A subroutine which is compiled together with its calling program is called an internal subroutine If it is compiled separately, it is called an external subroutine
n There are 2 types of machine-language CALL instructions, the near call and the far call. n n In the near call, at execution time, the computer pushes onto the stack the offset of the address of the instruction following the call instruction itself, and then jumps to the location specified by the call instruction In the far call, the computer in addition pushes onto the stack the no. in the code segment register.
n n There also 2 types of machine return instructions. Subroutines invoked by a near call, need to return using a near return instruction, and those invoked by a far call, need to employ a far return instruction. In Assembler one can specify the near return via “retn”, and the far return via “retf”, or (the usual practice), employ the ambiguous “ret” instruction, and leave it to the Assembler translator to work out which machine-language return instruction to use.
The proc statement of the subroutine indicates whether it is intended to be called by a near call and so requires a near return instruction, or via a far call which requires a far return instrucion. For example: SUB 2 PROC FAR (The default if neither “FAR” nor “NEAR” is specified is near. )
The Assembler translator works out which machine-language call instruction to translate an Assembler call instruction, by whether the subroutine involved is declared as NEAR or FAR in an EXTRN statement in the calling program
FAR calls are needed, for example, in calling library subroutines, where we cannot ensure that the code for the subroutine is in the same code segment as the calling program (We will not employ far calls in this class)
Subroutine in C++ For example, C++ uses: External subroutines Call type NEAR Call by value Passes arguments using the stack Pushes arguments from right to left The calling program restores the stack
In contrast, most other commercial compilers (such as Visual Basic, Pascal, etc) pass their arguments from left to right, and expect the restoration of the stack pointer SP, to its value before the call, to be performed by the stack
Examples Using a subroutine to evaluate X - 2*Y Note: this is a function, since it returns a value. For all commercial compilers, the convention is to put the answer (return value) into AL, AX, EAX or DX: AX, or EDX: EAX
Preserving Registers. Subroutines (of whatever type) should save and restore the values stored in registers, except for registers that will be used to return values to the calling procedure. This convention is needed to make sure that subroutines do not cause unexpected errors after control returns to the calling procedure.
Method 1: Passing Arguments in Registers Passing arguments in registers is a convenient and efficient way to pass values between procedures.
Internal Example TITLE INTERNAL EXAMPLE: X – 2*Y . MODEL SMALL . STACK 100 H . DATA X DW 20 Y DW 3 Z DW ? . CODE MAIN 3 PROC MOV AX, @DATA MOV DS, AX MOV BX, X MOV CX, Y CALL SUB 1 MOV Z, AX MOV AX, 4 C 00 H INT 21 H MAIN 3 ENDP
Internal Example (Cont. ) SUB 1 PROC ; X is BX, Y is in CX SUB BX, CX MOV AX, BX RET SUB 1 ENDP END MAIN 3 Note: in the internal form, the entire program is all in one file.
External Example X Y Z TITLE EXTRN. MODEL. STACK. DATA DW DW DW EXTERNAL EXAMPLE: X – 2*Y SUB 1: NEAR SMALL 100 H 20 3 ? . CODE MAIN 3 PROC MOV AX, @DATA MOV DS, AX MOV BX, X MOV CX, Y CALL SUB 1 MOV Z, AX MOV AX, 4 C 00 H INT 21 H MAIN 3 ENDP END MAIN 3 ; this is the end of MAIN 3. ASM
External Example (Cont. 1) TITLE SUB 1 in a separate file sub 1. asm PUBLIC SUB 1. MODEL SMALL ; no stack segment ; data segment is optional. CODE SUB 1 PROC NEAR SUB BX, CX MOV AX, BX RET SUB 1 ENDP END ; NOTE this is NOT “END SUB 1”
External Example (Cont. 2) To assemble and link the above: ml main 3. asm sub 1. asm will produce: main 3. exe To debug masm link the /zi /co above: main 3; sub 1; main 3 sub 1; This produces main 3. exe, but also allows you to debug using: cv main 3 (From now on, we'll only do external examples. )
Method 2: Using EXTRN and PUBLIC to pass the values of the arguments Variables can be used as global variables in assembler programs by declaring them: as EXTRN (if defined in another module) or as PUBLIC (if defined in the current module - and are then globally available for use by other modules. )
Example of Method 2 TITLE MAIN 3 USING GLOBAL VARIABLES: X – 2*Y ; comments to describe program should go here EXTRN SUB 1: NEAR ; SUB 1 is in another file PUBLIC X, Y ; makes X and Y global. MODEL SMALL. STACK 100 H. DATA X DW 20 Y DW 3 Z DW ?
Example of Method 2 (Cont. 1). CODE MAIN 3 PROC MOV AX, @DATA MOV DS, AX CALL SUB 1 MOV Z, AX MOV AX, 4 C 00 H INT 21 H MAIN 3 ENDP END MAIN 3 ; this is the end of MAIN 3. ASM
Example of Method 2 (Cont. 2) TITLE SUB 1 in a separate file sub 1. asm ; comments to describe SUB 1 module PUBLIC SUB 1 ; SUB 1 can be called by other modules EXTRN X: WORD, Y: WORD ; X & Y must be made public elsewhere. MODEL SMALL ; no stack segment ; data segment is optional. CODE SUB 1 PROC NEAR MOV AX, X SUB AX, Y RET SUB 1 ENDP END ; end of SUB 1. ASM
TERMINOLOGY n n n function - a subroutine that returns a result (usually in AX) subroutine - any block of instructions that can be called (with a return) from another place procedure - same as subroutine
Textbook Reading: Jones, Chapter 6 Homework. Write a programs on the computer to evaluate X + Y – Z employing: an external subroutine and passing arguments via PUBLIC and EXTRN declarations
- Slides: 27