MIPS汇编语言之多文件开发和宏定义

580 阅读2分钟

「这是我参与11月更文挑战的第24天,活动详情查看:2021最后一次更文挑战」。

mips多文件开发

在文件A中定义函数

fun:
  li $v0,1
  li $a0,1
  syscall 
  jr $ra

在文件B中使用关键字.include引用A文件中的函数

.text
jal fun

.include "A.asm"

所有文件必须在同一目录下

  1. 宏替换

    全局替换,使用我们之前学过的.include伪指令进行替换

  2. 宏匹配

在汇编中,如果我们要依次打印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就行

  1. 宏定义

    全局定义,如果我们想给一个数据或者寄存器,甚至是一行代码取个别名,然后在代码中使用别名的方式指代,那么可以使用宏定义指令.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
    

:宏定义宏匹配必须先定义后使用,也就是说定义的代码需要放在前头