前言

B站有个入门视频,文中的例子来自MIPS汇编语言小科普

我会在代码中添加详细的注解,方便自己日后查看。这里使用的是MARS模拟器,很小巧方便。

MARS模拟器

三段小程序

(1) Hello World!

C语言的Hello World! 如何转变为汇编语言呢?

#include<stdio.h>
int main(){
    printf("Hello World!");
    return 0;
}

汇编语言实际上是对进行寄存器操作,需要向外输出,需要调用syscall指令,当v0(2号寄存器)的值为4时,输出a0(4号寄存器)保存地址处的"字符串"。字符串需要保存在.data字段,程序保存在.text字段,相当于main确定程序开始的地方。(#为注释)

 .data           #数据字段,保存要打印的字符串
  msg: .ascii "Hello World!\0"  #msg记录了数据的地址,.ascii告诉计算机编码类型
                                #\0告诉计算机这里字符串结束
.text          #代码字段,表示程序的入口,相当于main
  la $a0,msg   #$a0寄存器加载字段的地址,la表示load address加载地址指令
  li $v0,4     # $v0寄存器加载4,表示要显示字符串,li表示load immediate加载立即数指令
  syscall      # 调用字符串输出

总体来看,汇编代码分成两段,数据段和代码段。printf输出函数需要连个寄存器v0, a0配合syscall指令完成。

(2) IF-ELSE

输入两个数,如果前者大,输出YES,反之NO。

#include<stdio.h>
int main(){
    int a,b;        
    scanf("%d",&a);
    scanf("%d",&b);
    if(a>b)
        printf("YES");
    else
        printf("NO");
  return 0;
}

这里同样要定义数据字段保存“YES”,“NO”,但多了一个终端输入部分,同样需要用syscall,但需要改变v0加载的值,变为5,输入的数据会保存在v0中。另外需要一个比较跳转语句bgt(greater 就跳)。最后需要一个程序结束命令,相当于return 0,同样调用syscall,但v0改为10。具体下

.data              #数据段保存输出字符串,注意加\0
  msg_yes: .ascii "YES\0" 
  msg_no:  .ascii "NO\0"  


.text               #程序段相当于main入口
  li $v0,5          #scanf("%d",&a);  t0保存a的值
  syscall 
  move $t0,$v0  

  li $v0,5          #scanf("%d",&b);  t1保存b的值
  syscall 
  move $t1,$v0 

  bgt $t0,$t1,s1    #a>b就跳转到标签s1,记录了地址
  la $a0,msg_no     #printf("NO");
  li $v0,4
  syscall 

  j stop            #直接跳转到结束语句stop

s1:
  la $a0,msg_yes     #printf("YES");
  li $v0,4
  syscall 

  stop:             #结束程序语句,类似return 0;
  li $v0 10
  syscall 

这里的j指令表示直接跳转,一般跟某个标签作为跳转地址,不会具体写内存地址。如果希望预留空间指定某个地址写程序,可以用.ktext 加地址。

.ktext 0x0100  #stop标签的地址在内存0x100的位置上
 stop:   
  li $v0 10
  syscall 

(3) WHILE

计算1+2+...+100并输出

#include<stdio.h>
int main(){
    int i=1;
    int s=0;        
    while (i<=100){
        s=s+i;
        i=i+1;  
    }
    printf("%d",s);
  return 0;
}

我们需要两个寄存器保存i,s的值,while循环通过跳转指令,循环里面用加法指令,最后输出整型并返回,输出整型需要让v0=1,a0=s(和字符串不一样v0=4,a0是地址):

.text           #main 入口
  li $t0,1      #t0表示i;t1表示s
  li $t1,0

loop:
  add $t1,$t1,$t0  #s=s+i
  add $t0,$t0,1    #i=i+1
  ble $t0,100,loop #while(i<=100) .ble=branch if less or equal

  move $a0,$t0   #寄存器之间数据转移用move
  li $v0,1       #打印整数
  syscall        #printf("%d",s)

  li $v0, 10    #return 0;
  syscall     

值得注意的是,这里没有数据段,不是必须的。

总结

  • mips汇编代码一般分两端,数据段和代码段。其他段详情参见模拟器Help->MIPS->Directives
  • 输入输出返回等指令需要调用syscall,配合v0和a0,其他详情参加模拟器Help->MIPS->Syscalls
功能 v0 a0
输出整型 1 待输出整型
输出字符串 4 待输出字符串地址
输入整型 5
返回 10
  • 用到的跳转指令:bgt(branch if greater than),j(jump),ble(branch if less or equal)
  • 用到的加载指令:move(寄存器间数据移动),li(加载立即数),la(加载地址)
  • 用到的运算指令:add

更进一步的学习可以参看pdf:Introduction To MIPS Assembly Language Programming

标签: none

添加新评论