MIPS模擬器MARS彙編入門

前言

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,記錄了printf("YES")程序的開始地址
  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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章