<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>

新聞中心

EEPW首頁(yè) > 學(xué)習方法與實(shí)踐 > MIPS匯編語(yǔ)言的特點(diǎn)

MIPS匯編語(yǔ)言的特點(diǎn)

——
作者: 時(shí)間:2007-10-24 來(lái)源:嵌入式在線(xiàn)論壇 收藏
是CPU二進(jìn)制指令的可讀寫(xiě)版本。我們在后面將有單獨的一章來(lái)講述。從來(lái)沒(méi)有接觸過(guò)的讀者在閱讀本書(shū)時(shí)可能會(huì )有一些迷惑 。 

大多數匯編語(yǔ)言都是非常古板的,都是一些寄存器號碼。但是工具鏈(toolchains)可以使得使用微處理機語(yǔ)言變得簡(jiǎn)單。工具鏈至少允許程序員引用一些助記符,而嚴格的匯編語(yǔ)言要求嚴格的數字編碼。大多我們都是用比較熟悉的C預處理器。C預處理器會(huì )把C風(fēng)格的注解去掉,而得到一個(gè)可用的匯編代碼。 

有C預處理器的幫助,匯編程序都是用助記符來(lái)表示寄存器。助記符同時(shí)也代表了每個(gè)寄存器的用法(我們將在2.2節介紹這一點(diǎn))。 

對於熟悉匯編語(yǔ)言但不熟悉的讀者,下面是一些例子。 

/* this is a comment */ 
#so is this 

entrypoint: #this's a label 

addu $1, $2, $3 # (registers) $1 = $2 + $3 

與大多數匯編語(yǔ)言一樣, MIPS匯編語(yǔ)言也是以行為單位的。每一行的結束是一個(gè)指令的結束,并且忽略任何“#”之后的內容,認為是注釋。在一行里可以有多條指令。指令之間要用分號“;”隔開(kāi)。 

一個(gè)符號(label)是一個(gè)后面跟著(zhù)冒號“:”的字。符號可以是任何字符串的組合。符號被用來(lái)定義一段代碼的入口和定義數據段的一個(gè)存儲位置。 

如上所示,許多指令都是3個(gè)操作數/符(operand)。目標寄存器在左側(注意,這一點(diǎn)與Intetel x86 正相反)。一般而言,寄存器結果和操作符的順序與C語(yǔ)言或其他符號語(yǔ)言的方式是一致的。 例如: 

subc $1, $2, $3 

意味著(zhù): 

$1 = $2 - $3; 

這方面我們就先講這么多。 

2.2 寄存器 

對於一個(gè)程序,可以有32個(gè)通用寄存器,分別為:$0-$31。其中,兩個(gè),也只有兩個(gè)的使用不同于其他。 

$0:不管你存放什么值,其返回值永遠是零。 

$31:永遠存放著(zhù)正常函數調用指令(jal)的返回地址。請注意call-by-registe的jalr指令可以使用任何寄存器來(lái)存放其返回地址。當然,如不用$31,看起來(lái)程序會(huì )有點(diǎn)古怪。 

其他方面,所有的寄存器都是一樣的??梢员挥迷谌魏我粋€(gè)指令中(你也可以用$0作為一個(gè)指令的目標寄存器。當然不管你存入什么數據,數據都消失了。) 

MIPS體系結構下,程序計數器不是一個(gè)寄存器,其實(shí)你最好不要去那樣想。在一個(gè)具有流水線(xiàn)的CPU中,程序計數器的值在一個(gè)給定的時(shí)刻有多個(gè)可選值。這一點(diǎn)有點(diǎn)迷惑人。jal指令的返回地址跟隨其后的第二條指令。 

... 
jal printf 
move $4, $6 
xxx # return here after call 

上述的解釋是有道理的,因為緊跟蹤jal指令后面的指令,由於在delay slot(延遲位置)上--請記住,關(guān)于延遲位置的規則是該指令將在轉移目標(如上述的printf)之前執行。延遲位置指令經(jīng)常被用來(lái)傳遞函數調用的參數。 

MIPS里沒(méi)有狀態(tài)碼。CPU狀態(tài)寄存器或內部都不包含任何用戶(hù)程序計算的結果狀態(tài)信息。 

hi和lo是與乘法運算器相關(guān)的兩個(gè)寄存器大小的用來(lái)存放結果的地方。它們并不是通用寄存器,除了用在乘除法之外,也不能有做其他用途。但是,MIPS里定義了一些指令可以往hi和lo里存入任何值。想一想我們會(huì )發(fā)現,這是非常有必要的當你想要恢復一個(gè)被打斷的程序時(shí)。 

浮點(diǎn)運算協(xié)處理器(浮點(diǎn)加速器,FPA),如果存在的話(huà),有32個(gè)浮點(diǎn)寄存器。按匯編語(yǔ)言的簡(jiǎn)單約定講,是從$f0到$31。 

實(shí)際上,對於MIPS I和MIPS II的機器,只有16個(gè)偶數號的寄存器可以用來(lái)做數學(xué)計算。當然,它們可以既用來(lái)做單精度(32位)和雙精度(64位)。當你做一個(gè)雙精度的運算時(shí),寄存器$f1存放$f0的余數。奇數號的寄存器只用來(lái)作為寄存器與FPA之間的數據傳送。 

MIPS III CPU有32個(gè)FP寄存器。但是為了保持軟件與過(guò)去的兼容性,最好不要用奇數號的寄存器。 

2.2.1 助記符與通用寄存器的用法 

我們已經(jīng)描述了一些體系結構方面的內容,下面來(lái)介紹一些軟件方面的內容。 

寄存器編號 助記符 用法 
0 zero 永遠返回值為0 
1 at 用做匯編器的暫時(shí)變量 
2-3 v0, v1 子函數調用返回結果 
4-7 a0-a3 子函數調用的參數 
8-15 t0-t7 暫時(shí)變量,子函數使用時(shí)不需要保存與恢復 
24-25 t8-t9 
16-25 s0-s7 子函數寄存器變量。子函數必須保存和恢復使用過(guò)的變量在函數返回之前,從而調用函數知道這些寄存器的值沒(méi)有變化。 
26,27 k0,k1 通常被中斷或異常處理程序使用作為保存一些系統參數 
28 gp 全局指針。一些運行系統維護這個(gè)指針來(lái)更方便的存取“static“和”extern"變量。 
29 sp 堆棧指針 
30 s8/fp 第9個(gè)寄存器變量。子函數可以用來(lái)做楨指針 
31 ra 子函數的返回地□ 
'7d 

雖然硬件沒(méi)有強制性的指定寄存器使用規則,在實(shí)際使用中,這些寄存器的用法都遵循一系列約定。這些約定與硬件確實(shí)無(wú)關(guān),但如果你想使用別人的代碼,編譯器和操作系統,你最好是遵循這些約定。 

寄存器約定用法引人了一系列的寄存器約定名。在使用寄存器的時(shí)候,要盡量用這些約定名或助記符,而不直接引用寄存器編號。 

1996年左右,SGI開(kāi)始在其提供的編譯器中使用新的寄存器約定。這種新約定可以用來(lái)建立使用32位地址或64位地址的程序,分別叫 "n32"和"n64"。我們暫時(shí)不討論這些,將會(huì )在第10章詳細討論。 

寄存器名約定與使用 

*at: 這個(gè)寄存器被匯編的一些合成指令使用。如果你要顯示的使用這個(gè)寄存器(比如在異常處理程序中保存和恢復寄存器),有一個(gè)匯編directive可被用來(lái)禁止匯編器在directive之后再使用at寄存器(但是匯編的一些宏指令將因此不能再可用)。 

*v0, v1: 用來(lái)存放一個(gè)子程序(函數)的非浮點(diǎn)運算的結果或返回值。如果這兩個(gè)寄存器不夠存放需要返回的值,編譯器將會(huì )通過(guò)內存來(lái)完成。詳細細節可見(jiàn)10.1節。 


*a0-a3: 用來(lái)傳遞子函數調用時(shí)前4個(gè)非浮點(diǎn)參數。在有些情況下,這是不對的。請參考10.1細節。 

* t0-t9: 依照約定,一個(gè)子函數可以不用保存并隨便的使用這些寄存器。在作表達式計算時(shí),這些寄存器是非常好的暫時(shí)變量。編譯器/程序員必須注意的是,當調用一個(gè)子函數時(shí),這些寄存器中的值有可能被子函數破壞掉。 

*s0-s8: 依照約定,子函數必須保證當函數返回時(shí)這些寄存器的內容必須恢復到函數調用以前的值,或者在子函數里不用這些寄存器或把它們保存在堆棧上并在函數退出時(shí)恢復。這種約定使得這些寄存器非常適合作為寄存器變量或存放一些在函數調用期間必須保存原來(lái)值。 

* k0, k1: 被OS的異?;蛑袛嗵幚沓绦蚴褂?。被使用后將不會(huì )恢復原來(lái)的值。因此它們很少在別的地方被使用。 

* gp: 如果存在一個(gè)全局指針,它將指向運行時(shí)決定的,你的靜態(tài)數據(static data)區域的一個(gè)位置。這意味著(zhù),利用gp作基指針,在gp指針32K左右的數據存取,系統只需要一條指令就可完成。如果沒(méi)有全局指針,存取一個(gè)靜態(tài)數據區域的值需要兩條指令:一條是獲取有編譯器和loader決定好的32位的地址常量。另外一條是對數據的真正存取。為了使用gp, 編譯器在編譯時(shí)刻必須知道一個(gè)數據是否在gp的64K范圍之內。通常這是不可能的,只能靠猜測。一般的做法是把small global data (小的全局數據)放在gp覆蓋的范圍內(比如一個(gè)變量是8字節或更小),并且讓linker報警如果小的全局數據仍然太大從而超過(guò)gp作為一個(gè)基指針所能存取的范圍。 

并不是所有的編譯和運行系統支持gp的使用。 

*sp: 堆棧指針的上下需要顯示的通過(guò)指令來(lái)實(shí)現。因此MIPS通常只在子函數進(jìn)入和退出的時(shí)刻才調整堆棧的指針。這通過(guò)被調用的子函數來(lái)實(shí)現。sp通常被調整到這個(gè)被調用的子函數需要的堆棧的最低的地方,從而編譯器可以通過(guò)相對於sp的偏移量來(lái)存取堆棧上的堆棧變量。詳細可參閱10.1節堆棧使用。 

* fp: fp的另外的約定名是s8。如果子函數想要在運行時(shí)動(dòng)態(tài)擴展堆棧大小,fp作為楨指針可以被子函數用來(lái)記錄堆棧的情況。一些編程語(yǔ)言顯示的支持這一點(diǎn)。匯編編程員經(jīng)常會(huì )利用fp的這個(gè)用法。C語(yǔ)言的庫函數alloca()就是利用了fp來(lái)動(dòng)態(tài)調整堆棧的。 

如果堆棧的底部在編譯時(shí)刻不能被決定,你就不能通過(guò)sp來(lái)存取堆棧變量,因此fp被初始化為一個(gè)相對與該函數堆棧的一個(gè)常量的位置。這種用法對其他函數是不可見(jiàn)的。 

* ra: 當調用任何一個(gè)子函數時(shí),返回地址存放在ra寄存器中,因此通常一個(gè)子程序的最后一個(gè)指令是jr ra. 

子函數如果還要調用其他的子函數,必須保存ra的值,通常通過(guò)堆棧。 

對於浮點(diǎn)寄存器的用法,也有一個(gè)相應的標準的約定。我們將在7.5節。在這里,我們已經(jīng)介紹了MIPS引入的寄存 


關(guān)鍵詞: MIPS 匯編語(yǔ)言

評論


相關(guān)推薦

技術(shù)專(zhuān)區

關(guān)閉
国产精品自在自线亚洲|国产精品无圣光一区二区|国产日产欧洲无码视频|久久久一本精品99久久K精品66|欧美人与动牲交片免费播放
<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>