注册 登录
自由的生活_软路由 返回首页

心想事成的个人空间 https://www.routerclub.com/?681 [收藏] [复制] [分享] [RSS]

日志

mips汇编入门

已有 763 次阅读2009-11-6 12:31 |

据说若要深入学习MIPS开发的话,《MIPS处理器设计透视》这书是必不可少的。不过若只是学习MIPS汇编,这书可能就不大合适了。汇编语言还是隐藏了CPU的很多细节,而这本书里讲的貌似就是这部分,在对汇编有所了解之后再来阅读可能要更好。

学习函数式语言的时候总是满足于看书,理解下语法语义即可,真正写的代码则少的可怜,不过确实“改变了编程的看法”,目的也算达到了。汇编就不行了,看书不够,一定得动手。所以学MIPS需要一个模拟器。pcspim应该是比较标准的了,不过感觉Mars可能要更好用(准确地说,Mars非常非常好用)。

MIPS是以优雅著称,据说即使是其竞争对手也如此认为。RISC么,32个寄存器,指令长度都一样。其中的指令大约这么三种形式:

j 1000 
li $1, 10
add $1, $2,$3

差异就是各个参数的长度不同。如add指令的三个参数都只有两个位宽(0~255),每个参数表示一个寄存器。如果把指令看作函数,那参数就可以看作是有类型的。而MIPS的汇编器是很强大的(听说可以进行窥孔优化),像add $t0, $0, 10这样的指令会被汇编器翻译成addi $t0,$0,10。汇编器处理前后指令的对比可以在Mars中显示出来。

记几个helloworld吧,

求3的阶乘:

li $t0, 0
li $t1, 1
if_1:
add $t0, $t0, 1
mul $t1, $t1, $t0
bne $t0, 3, if_1

在Mars下可以看到寄存器的变化,最后$t1寄存器的值是6。

mips汇编的分支(branch)指令分b系(bne,beq,bgt等等)和j系(j, jr等),差别就是b系指令的跳转都是有条件的,而且地址在参数中指明,而j系的跳转都是无条件的。j系指令的地址长度更长,寻址范围要更大,所以远程跳转都是j。

输出Helloworld:

.text
.globl main
 
main:
li $v0, 4                     # just the print syscall in SPIM
la $a0, str
syscall
 
.data
str: 
.asciiz "hello world"

这应该算个比较完整的汇编程序了。程序的可执行代码都是在.text段,数据在.data段。.globl指明程序的入口地址,那个:str指代的就是这段字符串的地址。字符串么,就是数组。数组不就是指针么。

其中这个syscall会与操作系统的不同而有差异。系统调用的号码由$v0指明,参数在$a系的寄存器中传递,返回值放回到$v0。这里调用的是spim实现的4号系统调用,即print string。

定义一个函数f_add,它可以将两个数相加:

.text
.globl main
 
f_add: 
add $v0, $a0, $a1
jr $ra
 
main:
li $a0, 1
li $a1, 2
jal f_add
 
add $t0, $v0, $0
 
li $v0, 1
add $a0, $0, $t0
syscall

在使用jal指令的时候,它会把发生跳转的地址记录在$ra寄存器中。这样函数在结尾的时候就可以用jr返回原先的位置了。

使用寄存器传递参数的好处貌似就是约定了函数的调用规范,兼容性要更好。例如x86下的BASIC和C在参数传递时压栈的顺序貌似就是相反的。

 

    在MIPS中对这个32个通用寄存器的引用都是使用 $0~$31 来使用的。
    为了便于记忆,借助宏定义来简化这个的使用。      
                          
寄存器编号 助记符  用法
  $0  zero

永远返回0,有点象NULL设备,往里写东西都给你丢了。看似浪费,其实有用的。等会学到汇编的时候再提,呵呵!

 $1  at (Assembly Temporary汇编缓存)保留给汇编使用
 $2~$3    v0,v1 子函数调用的返回结果。 就是return 返回的那些东西保存的地方,这个简单。
 $4~$7  a0,a3 (Arguments)子函数调用的前几个参数,就像行参保存的东西。
 $8~$15     t0,t7 暂时变量,子函数使用时不需要保存与恢复,就像子函数中使用tmp这样的临时变量。
 $16~$23  s0,s7  子函数寄存器变量。子函数写入时必须保存其值并在返回前恢复原值,从而调用函数看到的这些寄存器的值没有变化。
 $24~$25    t8,t9  同t0 t7等 。
 $26~$27  k0,k1 异常使用的。保留给中断或自陷处理程序使用,其值可能在你眼皮底下改变。
 $28  gp (Global Pointer)全局指针,这个比较有意思。一些运行系统维护这个指针以便于存取static和extern 变量。
 $29  sp (Stack Pointer)栈指针
 $30  s8/fp

第九个寄存器变量,相当于s8;

如果需要的话作为帧指针,否则作sacved register。

 $31  ra 子程序的返回地址

路过

雷人

握手

鲜花

鸡蛋

评论 (0 个评论)

facelist doodle 涂鸦板

您需要登录后才可以评论 登录 | 注册

QQ|Archiver|手机版|小黑屋|软路由 ( 渝ICP备15001194号-1|渝公网安备 50011602500124号 )

GMT+8, 2025-7-6 13:59 , Processed in 0.138034 second(s), 15 queries , Gzip On, Redis On.

Powered by Discuz! X3.5 Licensed

© 2001-2025 Discuz! Team.

返回顶部