270 likes | 373 Views
ICS312 Set 11. Introduction to Subroutines. All the combinations in which a subroutine can be written. 1. The subroutine may be: a. Internal or
E N D
ICS312 Set 11 Introduction to Subroutines
All the combinations in which a subroutine can be written 1. The subroutine may be: a. Internal or b. External2. 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 • If a high-order language implements a call instruction, similar to e.g. “call sub2(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.
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
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
There are 2 types of machine-language CALL instructions, the near call and the far call. • 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.
There are 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: SUB2 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 subroutine (via its RET .. instruction)
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.
TITLE INTERNAL EXAMPLE: X – 2*Y .MODEL SMALL .STACK 100H .DATA X DW 20 Y DW 3 Z DW ? .CODE MAIN3 PROC MOV AX, @DATA MOV DS, AX MOV BX, X MOV CX, Y CALL SUB1 MOV Z, AX MOV AX, 4C00H INT 21H MAIN3 ENDP Internal Example
Internal Example (Cont.) SUB1 PROC ; X is BX, Y is in CX SUB BX, CX SUB BX, CX MOV AX, BX RET SUB1 ENDP END MAIN3 Note: in the internal form, the entire program is all in one file.
TITLE EXTERNAL EXAMPLE: X – 2*Y EXTRN SUB1:NEAR .MODEL SMALL .STACK 100H .DATA X DW 20 Y DW 3 Z DW ? .CODE MAIN3 PROC MOV AX, @DATA MOV DS, AX MOV BX, X MOV CX, Y CALL SUB1 MOV Z, AX MOV AX, 4C00H INT 21H MAIN3 ENDP END MAIN3 ; this is the end of MAIN3.ASM External Example
External Example (Cont. 1) TITLE SUB1 in a separate file sub1.asm PUBLIC SUB1 .MODEL SMALL ; no stack segment ; data segment is optional .CODE SUB1 PROC NEAR SUB BX,CX SUB BX,CX MOV AX,BX RET SUB1 ENDP END ; NOTE this is NOT “END SUB1”
External Example (Cont. 2) To assemble and link the above: ml main3.asm sub1.asm will produce: main3.exe To debug the above: masm /zi main3; employ “zi”, not “Zi” as for ML masm /zi sub1; link /co main3 sub1; This produces main3.exe, but also allows you to debug using: cv main3 (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 inassembler 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 Method2 TITLE MAIN3 USING GLOBAL VARIABLES: X – 2*Y ; comments to describe program should go here EXTRN SUB1:NEAR ; SUB1 is in another file PUBLIC X, Y ; X, Y are in this file. ; makes X and Y global .MODEL SMALL .STACK 100H .DATA X DW 20 Y DW 3 Z DW ?
Example of Method2 (Cont. 1) .CODE MAIN3 PROC MOV AX, @DATA MOV DS, AX CALL SUB1 MOV Z, AX MOV AX, 4C00H INT 21H MAIN3 ENDP END MAIN3 ; this is the end of MAIN3.ASM
Example of Method2 (Cont. 2) TITLE SUB1 in a separate file sub1.asm ; comments to describe SUB1 module PUBLIC SUB1 ; SUB1 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 SUB1 PROC NEAR MOV AX, X SUB AX, Y SUB AX, Y RET SUB1 ENDP END ; end of SUB1.ASM
TERMINOLOGY • 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