新聞中心

        入門級ARM匯編指令

        作者: 時間:2016-11-09 來源:網(wǎng)絡(luò) 收藏
        無論是體系結(jié)構(gòu)還是指令集,大家或多或少都應(yīng)該對X86匯編有些了解,而對于嵌入式領(lǐng)域已被廣泛采用的ARM 處理器,了解的可能并不多。如果你有興趣從事嵌入式方面的開發(fā),那么了解一些RISC 體系結(jié)構(gòu)和ARM匯編的知識還是有必要的。這里,我們找出了這兩種體系結(jié)構(gòu)最明顯的不同之處,并對此進行介紹,讓大家對于RISC體系結(jié)構(gòu)的匯編有一個基本的了解。首先,我們就來看一看基于RISC的ARM的體系結(jié)構(gòu)。

        基于RISC 的ARM CPU
        ARM是一種RISC體系結(jié)構(gòu)的處理器芯片。和傳統(tǒng)的CISC體系結(jié)構(gòu)不同,RISC 有以下的幾個特點:
        ◆ 簡潔的指令集——為了保證CPU可以在高時鐘頻率下單周期執(zhí)行指令,RISC指令集只提供很有限的操作(例如add,sub,mul等),而復(fù)雜的操作都需要由這些簡單的指令來組合進行模擬。并且,每一條指令不僅執(zhí)行時間固定,其指令長度也是固定的,這樣,在譯碼階段就可以對下一條指令進行預(yù)取。
        ◆ Load-Store 結(jié)構(gòu)——這個應(yīng)該是RISC 設(shè)計中比較有特點的一部分。在RISC 中,CPU并不會對內(nèi)存中的數(shù)據(jù)進行操作,所有的計算都要求在寄存器中完成。而寄存器和內(nèi)存的通信則由單獨的指令來完成。而在CSIC中,CPU是可以直接對內(nèi)存進行操作的,這也是一個比較特別的地方。
        ◆ 更多的寄存器——和CISC 相比,基于RISC的處理器有更多的通用寄存器可以使用,且每個寄存器都可以進行數(shù)據(jù)存儲或者尋址。
        當然,作為RISC 領(lǐng)域最成功的處理器,ARM也遵從上面的特點。這里,我們不妨來看一看在user 模式下,ARM處理器的體系結(jié)構(gòu),這對于我們了解其匯編語言是有好處的。而其它模式下只是有一些寄存器分組略有不同,大家可以在ARM的手冊上查到。這里要說明的是,盡管ARM處理器也支持16位指令,不過在下文中,我們都假定ARM處理器在32 位模式下工作。


        圖1:user模式下ARM處理器體系結(jié)構(gòu)
        從圖1中我們看到,在user 模式下,ARM CPU 有16個數(shù)據(jù)寄存器,被命名為r0~r15(這個要比x86的多一些)。r13~r15有特殊用途,其中:
        ◆ r13 - 指向當前棧頂,相當于x86的esp,這個東西在匯編指令中要用sp 表示
        ◆ r14 - 稱作鏈接寄存器,指向函數(shù)的返回地址。用lr表示,這和x86將返回地址保存在棧中是不同的
        ◆ r15 - 類似于x86的eip,其值等于當前正在執(zhí)行的指令的地址+8(因為在取址和執(zhí)行之間多了一個譯碼的階段),這個用pc表示
        另外,ARM處理器還有一個名為cspr的寄存器,用來監(jiān)視和控制內(nèi)部操作,這點和x86 的狀態(tài)寄存器是類似的。具體的內(nèi)容就用到再說了。

        本文引用地址:http://www.104case.com/article/201611/317878.htm

        ARM 指令集
        ARM處理器可以支持3種指令集——ARM,Thumb和Jazelle。
        采用那種指令集,由cspr中的標志位來決定。大體說來:
        ◆ ARM——這是ARM自身的32 位指令集
        ◆ Thumb ——這是一個全16 位的指令集,在16 位外部數(shù)據(jù)總線寬度下,這個指令集的效率要比32 位的ARM指令高一些。
        ◆ Jazelle ——這是一個8位指令集,用來加速Java字節(jié)碼的執(zhí)行
        整個ARM指令集由數(shù)據(jù)處理指令、分支指令、Load-Store指令、程序中斷指令和一些系統(tǒng)控制指令構(gòu)成,除了Load-Store指令外,其他部分和x86指令集是比較類似的。但和x86相比,ARM指令最顯著的特點它們都是32-bit 定長的。另外,由于arm是基于RISC指令集的,所以CPU只處理在寄存器中的數(shù)據(jù)并通過獨立的load-store指令在內(nèi)存和寄存器之間進行數(shù)據(jù)的傳遞。
        在使用方面,ARM指令的格式也要比Intel的復(fù)雜些。一般說來,一條ARM指令有如下的形式:
        {S} [Rd], [Rn], [Rm]
        其中:
        * {S} —— 加上這個后綴的指令會更新cpsr 寄存器
        * [Rd] —— 目的寄存器
        * [Rn]/[Rm] —— 源寄存器
        一般來說,arm 指令有3個操作數(shù),其中Rm寄存器在執(zhí)行指令前可以進入桶形移位器進行移位操作,而Rn則會直接進入ALU 單元。如果一條arm 指令只有2 個操作數(shù),那么源寄存器按照Rm 來處理。例如,一條加法指令:
        add r0, r1, #1
        就會把r1+1的結(jié)果存放到r0中。
        在熟悉了基本的匯編格式后,讀者就可以自行去查詢基本的ARM匯編指令了,下面,我們找出ARM中比較有特色部分——Load-Store指令結(jié)構(gòu),它是CPU 和內(nèi)存進行通信的一個重要媒介。

        Load-Store 指令體系
        由于ARM CPU并不直接處理內(nèi)存中的數(shù)據(jù),這個指令體系就擔起了在寄存器和內(nèi)存之間交換數(shù)據(jù)的重要媒介。它要比x86 的內(nèi)存訪問機制復(fù)雜一些。該指令體系分成3 類:
        ◆ 單寄存器傳輸(這是與x86 最為相像的)
        ◆ 多寄存器傳輸
        ◆ 交換指令

        單寄存器傳輸
        先看第一個,很簡單:把單一的數(shù)據(jù)傳入(LDR) 或傳出(STR)寄存器,對內(nèi)存的訪問可以是DWORD(32-bit), WORD(16-bit)和BYTE(8-bit)。指令的格式如下:
        DWORD:
        Rd, addressing1
        WORD:
        H Rd, addressing2 無符號版
        SH Rd, addressing2 有符號版
        BYTE:
        B Rd, addressing1 無符號版
        SB Rd, addressing2 有符號版
        addressing1 和addressing2 的分類下面再說,現(xiàn)在理解成某種尋址方式就可以了。
        在單寄存器傳輸方面,還有以下三種變址模式,他們是:
        ◆ preindex
        這種變址方式和x86的尋址機制是很類似的,先對寄存器進行運算,然后尋址,但是在尋之后,基址寄存器的內(nèi)容并不發(fā)生改變,例如:
        ldr r0, [r1, #4]
        的含義就是把r1+4 這個地址處的DOWRD 加載到r0,而尋址后,r1 的內(nèi)容并不改變。
        ◆ preindex with writeback
        這種變址方式有點類似于++i的含義,尋址前先對基地址寄存器進行運算,然后尋址. 其基本的語法是在尋址符[]后面加上一個"!" 來表示.例如:
        ldr r0, [r1, #4]!
        就可以分解成:
        add r1, r1, #4
        ldr r0, [r1, #0]
        ◆ postindex
        自然這種變址方式和i++的方式就很類似了,先利用基址寄存器進行尋址,然后對基址寄存器進行運算,其基本語法是把offset 部分放到[]外面,例如:
        ldr r0, [r1], #4
        就可以分解成:
        ldr r0, [r1, #0]
        add r1, r1, #4
        如果你還記得x86 的SIB 操作的話,那么你一定想ARM是否也有,答案是有也沒有。在ss上面提到的addressing1 和addressing2的區(qū)別就是比例寄存器的使用,addressing1可以使用[base, scale, 桶形移位器]來實現(xiàn)SB 的效果,或者通過[base,offset](這里的offset 可以是立即數(shù)或者寄存器)來實現(xiàn)SI 的效果,而addressing2則只能用后者了。于是每一種變址方式最多可以有3 種尋址方式,這樣一來,最多可以有9種用來尋址的指令形式。例如:
        ldr r0, [r1, r2, LSR #0x04]!
        ldr r0, [r1, -#0x04]
        ldr r0, [r1], LSR #0x04
        每樣找了一種,大概就是這個意思。到此,單寄存器傳輸就結(jié)束了,掌握這些足夠應(yīng)付差事了。下面來看看多寄存器傳輸吧。

        多寄存器傳輸
        說得很明白,意思就是通過一條指令同時把多個寄存器的內(nèi)容寫到內(nèi)存或者從內(nèi)存把數(shù)據(jù)寫到寄存器中,效率高的代價是會增加系統(tǒng)的延遲,所以armcc 提供了一個編譯器選項來控制寄存器的個數(shù)。指令的格式有些復(fù)雜:
        <尋址模式> Rn{!}, {r^}
        我們先來搞明白尋址模式,多寄存器傳輸模式有4 種:
        也就是說以A開頭的都是在Rn的原地開始操作,而B開頭的都是以Rn的下一個位置開始操作。如果你仍然感到困惑,我們不妨看個例子。
        所有的示例指令執(zhí)行前:
        mem32[0x1000C] = 0x04
        mem32[0x10008] = 0x03
        mem32[0x10004] = 0x02
        mem32[0x10000] = 0x01
        r0 = 0x00010010
        r1 = 0x00000000
        r3 = 0x00000000
        r4 = 0x00000000
        1) ldmia r0!, {r1-r3} 2) ldmib r0!, {r1-r3}
        執(zhí)行后: 執(zhí)行后:
        r0 = 0x0010001C r0 = 0x0010001C
        r1 = 0x01 r1 = 0x02
        r2 = 0x02 r2 = 0x03
        r3 = 0x03 r3 = 0x04
        至于DA 和DB 的模式,和IA / IB 是類似的,不多說了。
        最后要說的是,使用ldm 和stm指令對進行寄存器組的保護是很常見和有效的功能。配對方案:
        stmia / ldmdb
        stmib / ldmda
        stmda / ldmib
        stmdb / ldmia
        繼續(xù)來看兩個例子:
        執(zhí)行前:
        r0 = 0x00001000
        r1 = 0x00000003
        r2 = 0x00000002
        r3 = 0x00000001
        執(zhí)行的指令:
        stmib r0!, {r1-r3}
        mov r1, #1 ; These regs have been modified
        mov r2, #2
        mov r3, #3
        當前寄存器狀態(tài):
        r0 = 0x0000100C
        r1 = 0x00000001
        r2 = 0x00000002
        r3 = 0x00000003
        ldmia r0!, {r1-r3}
        最后的結(jié)果:
        r0 = 0x00001000
        r1 = 0x00000003
        r2 = 0x00000002
        r3 = 0x00000001
        另外,我們還可以利用這個指令對完成內(nèi)存塊的高效copy:
        loop
        ldmia r9!, {r0-r7}
        stmia r10!, {r0-r7}
        cmp r9, r11
        bne loop
        說到這里,讀者應(yīng)該對RISC的Load-Store體系結(jié)構(gòu)有一個大概的了解了,能夠正確配對使用指令,是很重要的。



        關(guān)鍵詞: 入門級ARM匯編指

        評論


        技術(shù)專區(qū)

        關(guān)閉
        主站蜘蛛池模板: 石屏县| 南城县| 云南省| 河南省| 北流市| 穆棱市| 广南县| 吉安县| 陆良县| 阿克陶县| 修武县| 安康市| 玛沁县| 岳西县| 重庆市| 镇坪县| 蓬溪县| 安岳县| 安龙县| 县级市| 玛纳斯县| 陇川县| 尼木县| 龙南县| 如皋市| 皮山县| 天门市| 乌拉特中旗| 阳西县| 庆安县| 天峻县| 无为县| 甘谷县| 民县| 塔城市| 启东市| 禹城市| 县级市| 右玉县| 盘山县| 绥滨县|