Set 12

advertisement
ICS312 Set 12
Subroutines: Passing Arguments
Using the Stack
Passing Arguments via the Stack
Arguments to a subroutine are pushed onto the stack.
The subroutine accesses the arguments from
the stack using the Base Pointer (BP) and indirect addressing.
Arguments can be passed by value (their values are pushed onto the stack,
or by reference (their offsets are pushed onto the stack).
The calling routine used in MAIN3 can be either:
To use CALL by Value:
PUSH X
PUSH Y
CALL SUB1
To use CALL by Reference:
PUSH OFFSET X
PUSH OFFSET Y
CALL SUB1
Call by Value Using the Stack
Suppose that X and Y are defined in the MAIN file:
X DW ...
Y DW ...
To call a subroutine CALC to evaluate X - 2Y using
call by value:
TITLE MAIN3 (main3.asm)
EXTRN CALC: NEAR
.MODEL SMALL
.STACK 100H
.DATA
X DW 30
Y DW 40
.CODE
MAIN3 PROC
MOV AX, @DATA
MOV DS, AX
PUSH Y ; call by value
PUSH X
CALL CALC
; the answer should be returned in AX
MOV AX,4C00H
INT 21H
MAIN3 ENDP
END MAIN3
Pay close attention to the following slide
(and the one so indicated a few slides on).
These are the methods used by all
commercial compilers
You are expected to know these methods off
by heart! You’ll be asked to supply them
both in a quiz and in the midterm.
Call by Value Using the Stack(Cont.)
TITLE CALC (CALC.ASM - a separate file)
PUBLIC CALC
.MODEL SMALL
.CODE
CALC PROC NEAR
;evaluates X - 2Y with result in AX
PUSH BP
;save BP
MOV BP,SP
;BP points to stack top
; push any registers to be used in the subroutine and
; restored before returning from the subroutine here
MOV AX,[BP+4]
;AX has X
SUB AX,[BP+6]
;AX = X - Y
SUB AX,[BP+6]
;AX = X - 2Y
; pop any registers that were saved in the subroutine here
POP BP
;restore BP
RET 4
;pop IP and add 4 bytes to SP
CALC ENDP
END
Call by Value Using the Stack(Cont.)
Stack Representation for NEAR Call by Value in this version of the
program:
Instruction
Stack Contents
PUSH Y (Arg1)
PUSH X (Arg2)
CALL CALC
PUSH BP
MOV BP, SP
push regs
Y
X
Ret Address
BP
regs
SP
SP -=2
SP -=2
SP -=2
SP -=2
BP (at the end of this code)
[BP+6] = offset of Y on stack
[BP+4] = offset of X on stack
[BP+2] = RETADDR (IP)
[BP] = original contents of BP
BP = SP
SP -=2/each reg
Call by Value Using the Stack(Cont.)
The purpose of using the BP in this way is because it gives a standard way
to retrieve arguments from the stack that is not affected by pushing any
additional registers or other values within the subroutine.
Note: if BP is used for indirect addressing, it is assumed to be referring to
an offset in the stack segment (SS). Any other register used for indirect
addressing is assumed to be an offset in the data segment (DS).
TITLE CALC (CALC.ASM - a separate file)
PUBLIC CALC
.MODEL SMALL
.CODE
CALC PROC NEAR
;evaluates X - 2Y with result in AX
PUSH BP
;save BP
MOV BP,SP
;BP points to stack top
; push any registers to be used in the subroutine
MOV AX, [BP+4] ;AX has X
SUB AX, [BP+6] ;AX = X - Y
SUB AX, [BP+6] ;AX = X - 2Y
; pop any registers that were saved in the subroutine
POP BP
;restore BP
RET 4
;pop IP and add 4 bytes to SP
CALC ENDP
END
NOTE
C assumes that
(1) the calling program will fix the stack after the return from a subroutine
(2) arguments will be passed using call by value
(3) arguments are pushed in reverse order, as shown above.
Different compilers use different calling conventions.
Call by Reference Using the Stack
Here is another version to demonstrate passing
arguments by reference on the stack.
TITLE MAIN3 (main3.asm)
EXTRN SUB2: NEAR
.MODEL SMALL
.STACK 100H
.DATA
X
DW
30
Y
DW
40
.CODE
MAIN3 PROC
MOV AX,@DATA
MOV DS,AX
PUSH OFFSET Y ;using call by reference
PUSH OFFSET X ;using call by reference
CALL CALC
; answer should be in AX
MOV AX,4C00H
INT 21H
MAIN3 ENDP
END MAIN3
The following slide (and its continuation) is
the other method (call by reference) used
by commercial compilers
and which you are expected to know off by
heart!
Call by Reference Using the Stack
TITLE SUB2 (sub2.asm - a separate file)
PUBLIC SUB2
.MODEL SMALL
.CODE
SUB2 PROC NEAR
;evaluates X - 2Y, with result in AX
PUSH BP
;save BP (and DEC SP)
MOV BP,SP
;BP pts to stack top
; push any registers to be used in the subroutine and
; restored before returning from the subroutine here
MOV
MOV
MOV
SUB
SUB
BX,
AX,
BX,
AX,
AX,
[BP+4]
[BX]
[BP+6]
[BX]
[BX]
;BX
;AX
;BX
;AX
;AX
has
has
has
= X
= X
address of X (not its value)
the value of X
address of Y
- Y
- 2Y
;pop any registers that were saved in the subroutine here
POP BP
;restore BP
RET 4
;pop IP and add 4 bytes to SP
SUB2 ENDP
END
Stack Representation for call by reference example
Instruction
code)
PUSH AX
PUSH AX
CALL ADDNOS
PUSH BP
MOV BP, SP
PUSH regs
Stack contents
Y address
X address
IP
BP
regs
SP
SP -=2
SP -=2
SP -=2
SP -=2
BP (at end of this
[BP+6]= Y address
[BP+4]= X address
[BP+2] = return addr. offset
[BP] = orig. contents of BP
BP = SP
SP -=2/reg
Example on storing a result in
an argument
Call SUB(X, Y, Z), Result is to set Z = Y – X
Main Program
.
.
PUSH
OFFSET X
PUSH OFFSET Y
PUSH OFFSET Z
CALL
SUB
.
.
Example on storing a result in
an argument (Cont.1)
Title SUB3
.Model Small
.586
PUBLIC SUB
.CODE
SUB PROC NEAR
PUSH BP
MOV
BP, SP
PUSH DX
PUSH BX
MOV
BX, [BP+6]
MOV
DX, [BX]
MOV
BX, [BP+8]
SUB
DX, [BX]
;Save BP
;Save DX
;Save BX
;BX = OFFSET of ADDRESS of Y
;DX = Y
;BX = OFFSET of ADDRESS of X
;DX = Y – X
Example on storing a result in
an argument (Cont.2)
; to store DX in Z
MOV
BX, [BP+4]
MOV
[BX], DX
POP
POP
POP
RET
SUB ENDP
END
BX
DX
BP
6
; puts offset of Z into BX
; restore original value of BX
FIXING UP THE STACK
If the subroutine is to fix up the stack, then
it should end up with:
RET 2*no. of arguments
e.g. if there are 3 arguments, then it should
end up with:
RET 6
If the calling program is to fix up the stack,
then the subroutine should end up with:
RET
and, assuming that the subroutine is SUB1,
the calling program should contain the code:
call sub1
add sp, 6 (i.e. 2*no. of arguments)

ILLUSTRATION OF A RECURSIVE
PROCEDURE
A procedure to evaluate factorial(n)
if n = 1
return 1
else
return n*factorial(n-1)
factorial proc near
push bp
mov bp,sp
cmp word ptr [bp+4], 1
jg cont
mov ax, 1
jmp endup
cont:
mov bx, [bp+4]
dec bx
push bx
call factorial
imul
word ptr [bp+4]
endup:
pop bp
ret 2
factorial endp
end
An Example of a Recursive Procedure
Employed in Cryptography
Definition. The GCD (greatest common
denominator) of two numbers a, b is the
largest number that divides both a and b.
25
Euler’s Extended Algorithm.
For given a, b to find:
(a) the GCD d of a, b
(b) numbers x and y (positive, negative
or zero) such that xa + yb = d
(Euler’s original algorithm is just part (a) )
26
If a = b, then obviously the GCD of
(a,b) is a, and we have a*1 + b*0 = a
Otherwise, proceed as follows:
Define E(a,b) as a function whose value is the triple
(x, y, d) such that d is the GCD of a, b and
xa + yb = d. E(a,b) can then be evaluated using
the following recursive algorithm:
Function E(a, b) where a > b
If b = 0 then return (1, 0, a),
else evaluate q, r such that
a = qb + r and 0 ≤ r < b.
Evaluate E(b, r), let result be (X, Y, D)
Return (Y, X – qY, D)
End function
28
EXAMPLE. To find the GCD d of 75 and 30, and,
further to find x, y such that 75x + 30y = d.
E(75, 30) = (x1, y1, d) to be filled in later
75 = 2*30 + 15
(so q1 = 2)
E(30, 15) = (x2, y2, d) to be filled in later
30 = 2*15 + 0
(so q2 = 2)
E(15, 0) = (x3, y3, d) = (1, 0, 15). So d = 15.
Now x2 =y3=0 and y2 = x3 – q2y3 = 1
and x1 =y2=1 and y1 = x2 – q1y2 = -2
So d = 15 and 1*75 + (-2)*30 = 15
29
PROOF THAT THE ALGORITHM WORKS (optional)
First of all note that since a = qb + r,
any number that divides both b and r must also
divide a (so it divides both a and b). And since
r = a – qb, any number that divides both a and b
must also divide r
(so it divides both b and r).
Thus the largest number that divides both b and r
must also be the largest number that divides both
a and b
i.e.
the GCD of a,b = GCD of b,r
The case where b = 0 obviously returns the
correct result, since 1*a + 0*0 = a, and a is
the GCD of a and 0.
If b > 0, and q, r, X, Y, D are as defined in the
algorithm, then
Xb + Yr = D where D is the GCD of b,r
and hence also of a,b
Since r = a - qb, this provides
Xb + Y(a-qb) = D
Giving Ya + (X-qY)b = D
31
Finally note that the algorithm terminates,
because the second argument decreases in
each successive recursive call. So the
sequence of iterations must end up with one
in which the second argument is zero
32
Textbook Reading (Jones):
Chapter 13 Procedures and High-Level Languages
Download