PowerPC匯編指令集簡析-(1)


    在了解PowerPC匯編指令前,需要先看下編程所用的寄存器模型,PowerPC系統結構為大多數運算指令都定義了Register-Register的操作,這些操作的源操作數從寄存器取得,或作為嵌入指令操作碼中的立即數提供。這里的e300核可分為用戶編程模型和管理員編程模型,該模型有32個GPR、32個FPR、特殊目的寄存器SPR和一些功能寄存器,下圖為二者的示意圖:

    上面這些寄存器可能不太好理解,因為名字和Intel匯編不一樣,其實,可以這樣理解,GPR就相當於EAX/EBX/ECX,而CTR則完全就是ECX的功能,是吧?區別就是沒有堆棧而已咯。CR被分為8段,每段4位,分別代表LT、GT、EQ和SO(小於、大於、等於和溢出);LR用於記錄跳轉地址;特殊寄存器XER用於記錄溢出和進位標志;FPSCR用於記錄浮點運算類型和異常等。

    再看下指令集,大部分的CPU指令集可分為:數據讀寫、數值計算、流程控制和設備管理四個部分,由於PowerPC使用RISC,指令字長為32bit,Endian一般是可調的,默認為大端,另外,PowerPC沒有棧,所以程序需要自己實現相關操作。首先為運算和邏輯指令,列舉如下:

 

 

    它們與通用寄存器有關,源數據來自GPR 或16 位立即數,目的是GPR 寄存器,操作為32 位,GPR 中存放32 位更新數據。大多數指令都可以根據字面意思理解其作用,注意還有一個“cntlzw”指令,意為計算字中的第一個0,用於在一個字中找到1時將一個指令中的0的數量找出,它在決定例外寄存器中最高優先服務時有用。

    下面是數據讀寫指令,它們對數據在存儲器中核通用寄存器中的傳送很有用,若數據小於傳送長度(單字,半字或字節),指令會使數據變位為32位,將不同位填0或符號擴展。指令列舉如下:

 

 

    這里需要注意的是上面列舉的lbz和lhz兩個指令並不完全等同於mov al,[ebx]和mov ax,[ebx+10]這兩個,因為前面兩個是將字節和半字加載到r3時還清空了高位,而后兩條指令只是加載數據到eax,並不會清空高位

    另外,還有兩個指令sthbrw和stwbrx,對PowerPC存取小端格式數據很有用,它們允許存取這樣的數據,若數據以小端順序進入總線,就把它存為大端順序。

    好了,現在來詳細看下賦值指令,下面是最常見的賦值代碼:

lis    r3,0x1234

addi r3,r3,0x5678

這段代碼的含義是將0x12345678加載到寄存器r3中。因為在RISC下,PowerPC的每條指令都是32bit,除去指令和寄存器參數編碼,只剩下16bit的長度描述立即數,如立即數加載指令li:

這樣立即數SIMM只有16位,所以需要兩次加載,使用lis(立即數載入並左移)和addi(立即數加法)兩條指令完成。

再看下PowerPC不同的子程序調用:

func:       /* 子程序入口 */
    blr     /* 返回(跳轉到lr地址) */
start:      
    bl func   /* 調用func(跳轉並保存地址到lr) */
    li r1,1   /* 設置r1、r3 */
    li r3,1  
    sc        /* 系統調用,結束程序 */

    這里的調用由PowerPC使用lr寄存器完成,在bl指令跳轉前,下一條指令li r1,1的地址會被保存在lr,而執行的func中的blr時,系統會跳到lr表示的地址,完成返回。

    再來介紹下特殊寄存器的操作指令,它們可以完成特殊用途寄存器之間和通用寄存器之間的數據交換,不可以直接對特殊用途寄存器中的值進行處理,但是,可以將一個值先拷貝到一個通用寄存器上處理,再將信息存到特殊用途寄存器上。下面是指令集合:

這里回顧下,PowerPC里沒有堆棧,那用什么實現模擬呢?看下面的例子:

f1:
	mflr r2   /*保存lr中記錄的地址到r2*/
	stw r2,-8(r1)  /*記錄r2的值到mem[r1-8]*/
	addi r1,r1,-60   /*r1后移60個字節,完成進棧操作*/
	...
	addi r1,r1,60   /*r1前移60個字節,准備出棧*/
	lwz r2,-8(r1)   /*讀出老的lr值到r2*/
	mtfr r2       /*將r2的內容復制到lr*/
	blr       /*返回(跳轉到lr地址)*/
start:
	...
	bl f1       /*調用f1(跳轉並保持地址到lr)*/

    看到了吧,雖然沒有提供棧的相關指令(PUSH/POP/CALL/RET),但應用程序可以用r1模擬棧指針,實現多層調用對LR的記錄和恢復。

    前面說了,PowerPC指令為32位長,指令內僅有16位用於加載常量值,由於地址最多可達到64位,所以我們可以采用每次一段的方式載入地址,匯編程序中的@符號指示匯編程序給出一個符號值的特殊處理形式:@highest:表示一個常量的第48-63位;@higher:表示一個常量的第32-48位;@h:16-31位;@l:0-15位。

    下面是我們的一個稍大點的PowerPC匯編程序總結下上面的指令集,實現的功能就是載入兩個值並相加,最后退出,以結果為狀態代碼輸出。代碼如下:

#sum.s,第一個PowerPC匯編程序
.data
.align 3
#此處裝載兩個值
first_value:
.quad 1
second_value:
   .quad 2
#寫”.opd”(official procedure descriptor)
.section “.opd”,”aw”
.align 3
#._start的程序描述符,即為程序名
.global _start
_start:
   .quad .start, .TOC.@tocbase,0
#._text為程序代碼段
.text
._start:
   #裝載地址高位
lis r7,first_value@highest
ori r7,r7,first_value@higher
#shift these up to the high-order bits
rldier r7,r7,32,31
#裝載地址低位
oris r7,r7,first_value@h
ori r7,r7,first_value@l
#將第一個值載入寄存器4
ld r4,0(r7)
lis r7,second_value@highest
ori r7,r7,second_value@higher
rldicr r7,r7,32,31
oris r7,r7,second_value@h
ori r7,r7,second_value@l
ld r5,0(r7)
#二者相加並存到寄存器6
add r6,r4,r5
#程序退出
li 0,1 #寄存器0為系統調用
mr r3,r6 #將結果移到寄存器3中
sc #對內核進行系統調用

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com