「这是我参与11月更文挑战的第24天,活动详情查看:2021最后一次更文挑战」。
mips多文件开发
在文件A中定义函数
fun:
li $v0,1
li $a0,1
syscall
jr $ra
在文件B中使用关键字.include引用A文件中的函数
.text
jal fun
.include "A.asm"
所有文件必须在同一目录下
宏
-
宏替换
全局替换,使用我们之前学过的
.include伪指令进行替换 -
宏匹配
在汇编中,如果我们要依次打印1,2,3三个整数,那么汇编如下:
print1:
li $v0,1
li $a0,1
syscall
jr $ra
print2:
li $v0,1
li $a0,2
syscall
jr $ra
print2:
li $v0,1
li $a0,3
syscall
jr $ra
我们发现使用标签的方式定义函数,当函数体内容存在不确定变量值时,代码非常冗余, 如果使用高级语言进行封装的话,我们一般一个函数就搞定了:
void print(int a){
print(a);
}
有没有办法使得汇编能像高级语言一样简洁呢?
在MARS中给我们提供了一个扩展伪指令,叫做宏匹配
宏匹配使用的格式如下:
.macro 别名
#汇编指令...
.end_macro
示例:
li $v0,10
syscall
#比如我们要对以上两行指令使用宏匹配进行封装
#封装结果为
.macro exit
li $v0,10
syscall
.end_macro
#在代码中引用
.text
exit #直接使用别名调用
如果我们要封装一个打印整型数据的函数,那么我们可以:
#封装结果为
.macro print_int(%param)
li $v0,1
li $a0,%param
syscall
.end_macro
#在代码中引用
.text
print_int(1) #直接使用别名调用
print_int(2)
print_int(3)
这样是不是和高级语言没什么区别啦
打印字符串封装示例:
.macro print_str (%str)
.data
myLabel: .asciiz %str
.text
li $v0, 4
la $a0, myLabel
syscall
.end_macro
print_str ("test1")
print_str ("test1")
然后结合我们之前学过的多文件开发,完全可以将这个封装好的函数单独放在一个文件中,直接在头部.include就行
-
宏定义
全局定义,如果我们想给一个数据或者寄存器,甚至是一行代码取个别名,然后在代码中使用别名的方式指代,那么可以使用宏定义指令
.eqv别名的好处就是方便我们进行记忆.eqv LIMIT 20 #给20这个立即数取个别名为LIMIT .eqv CTR $t2 .eqv CLEAR_CTR add CTR, $zero, 0当我们有以下代码:
.text li $v0,1 add $t2, $zero, 0 li $t0,20如果我们使用宏定义,我们可以写成如下:
.eqv LIMIT 20 #给20这个立即数取个别名为LIMIT .eqv CTR $t2 .eqv CLEAR_CTR add CTR, $zero, 0 .text li $v0,1 CLEAR_CTR li $t0,LIMIT
注:宏定义和宏匹配必须先定义后使用,也就是说定义的代码需要放在前头