Фреймы, локальные переменные, рекурсия
Ранее рассмотренная конвенция не обеспечивает некоторые возможности языков высокого уровня. Добавим некоторые из этих функций в новой конвенции о вызове процедур основе стека.
- Сохранение регистров в стеке
- Сохранение адреса возврата в стеке($ra)
- Сохранение и востаноление регистров $s0―$s7 в/из стеке/стека
- Конвенция о вызове процедур на основе стека.
- Это не официальное соглашение. Однако оно может быть использовано для небольшого проекта на языке ассемблера. Конвенция не очень сложна и делает почти все, что может быть нужно. Если вы хотите использовать процедуры из программы на языке "C" или использовать процедуры из библиотек программ, то необходимо использовать официальные правила в полном объеме. (Что в эмуляторе MARS невозможно.)
- Правила:
- Вызов подпрограммы (делает вызывающая процедура):
- Сохранить в стеке регистры "$t0 - $t9", которые должны быть сохранены(будут использованы вызывающей процедурой после вызова подпрограммы). Подпрограмма может изменить эти регистры.
- Загрузить значения аргументов в регистры "$a0 - $a3".
- Вызов подпрограммы с помощью "jal".
- Пролог подпрограммы:
- Сохранить регистр "$ra" в стек.
- Сохранить в стек регистры "$s0 - $s7"(подпрограмма может изменять их).
- Тело подпрограммы:
- Подпрограмма может изменять регистры "$t0 - $t9", или те из регистров "$s0 - $s7", которые были сохранены в прологе.
- Из подпрограммы можно вызывать другую подпрограмму, тследуя этим правилам.
- Эпилог подпрограммы (непосредственно перед возвращением):
- Загрузить возвращаемые значения в регистры "$v0 - $v1".
- Извлечь из стека (в обратном порядке) сохраненые в прологе регистры "$s0 - $s7".
- Извлечь из стека в регистр '$ra" адрес возврата.
- Вернуться в вызывающую процедуру, используя "jr $ra".
- Восстановление состояния при выходе из подпрограммы:
- Извлечь из стека (в обратном порядке) сохраненые регистры "$t0 - $t9".
- Вызов подпрограммы (делает вызывающая процедура):
- Пролог и эпилог вызываемой подпрограммы: ris
- Вызов и возврат. ris
- Вложенные вызовы подпрограмм и цепь активации. ris
- О реальных конвенциях(ABI).
- Пример программы:
1 ## Driver -- main program for the application
2
3 .text
4 .globl main
5
6 main:
7 sub $sp,$sp,4 # push the return address
8 sw $ra,($sp)
9 sub $sp,$sp,4 # push $s0
10 sw $s0,($sp)
11
12 la $a0,xprompt # prompt the user
13 li $v0,4 # service 4
14 syscall
15 li $v0,5 # service 5 -- read int
16 syscall # $v0 = integer
17 move $s0,$v0 # save x
18
19 la $a0,yprompt # prompt the user
20 li $v0,4 # service 4
21 syscall
22 li $v0,5 # service 5 -- read int
23 syscall # $v0 = integer
24
25 # prepare arguments
26 move $a0,$s0 # x
27 move $a1,$v0 # y
28 jal maxExp # maximum expression
29 nop # returned in $v0
30 move $s0,$v0 # keep it safe
31
32 la $a0,rprompt # output title
33 li $v0,4 # service 4
34 syscall
35
36 move $a0,$s0 # get maximum
37 li $v0,1 # print it out
38 syscall
39
40 lw $ra,($sp) # pop $s0
41 add $s0,$sp,4
42 lw $ra,($sp) # pop return address
43 add $sp,$sp,4
44
45 li $s0,0 # return to OS
46 li $v0,10
47 syscall
48
49
50 .data
51 xprompt: .asciiz "Enter a value for x --> "
52 yprompt: .asciiz "Enter a value for y --> "
53 rprompt: .asciiz "The maximum expression is: "
54
55 ## maxInt -- compute the maximum of two integer arguments
56 ##
57 ## Input:
58 ## $a0 -- a signed integer
59 ## $a1 -- a signed integer
60 ##
61 ## Returns:
62 ## $v0 -- maximum
63
64 .text
65 .globl maxInt
66
67 maxInt:
68 # body
69 move $v0,$a0 # max = $a0
70 bgt $a0,$a1,endif # if $a1 > $a0
71 nop
72 move $v0,$a1 # max = $a1
73 endif: # endif
74 # epilog
75 jr $ra # return to caller
76 nop
77
78 ## maxExp -- compute the maximum of three expressions
79 ##
80 ## Input:
81 ## $a0 -- a signed integer, x
82 ## $a1 -- a signed integer, y
83 ##
84 ## Returns:
85 ## $v0 -- the maximum of x*x, x*y, or 5*y
86 ##
87 ## Registers:
88 ## $s0 -- x*x
89 ## $s1 -- x*y
90 ## $s2 -- 5*y
91
92 .text
93 .globl maxExp
94
95 maxExp:
96 # prolog
97 sub $sp,$sp,4 # push the return address
98 sw $ra,($sp)
99 sub $sp,$sp,4 # push $s0
100 sw $s0,($sp)
101 sub $sp,$sp,4 # push $s1
102 sw $s1,($sp)
103 sub $sp,$sp,4 # push $s2
104 sw $s2,($sp)
105
106 # body
107 mul $s0,$a0,$a0 # x*x
108 mul $s1,$a0,$a1 # x*y
109 li $t0,5
110 mul $s2,$t0,$a1 # 5*y
111
112 move $a0,$s0 # compute max of x*x
113 move $a1,$s1 # and x*y
114 jal maxInt # current max in $v0
115 nop
116
117 move $a0,$v0 # compute max of
118 move $a1,$s2 # current max, and 5*y
119 jal maxInt # total max will be in $v0
120 nop
121
122 # epilog
123 lw $s2,($sp) # pop $s2
124 add $sp,$sp,4
125 lw $s1,($sp) # pop $s1
126 add $sp,$sp,4
127 lw $s0,($sp) # pop $s0
128 add $sp,$sp,4
129 lw $ra,($sp) # pop return address
130 add $sp,$sp,4
131 jr $ra # return to caller
132 nop