數(shù)據(jù)類型
這是 ARM 匯編基礎知識系列教程的第二部分,涉及數(shù)據(jù)類型和寄存器。

與高級語言類似,ARM支持對不同數(shù)據(jù)類型的操作。我們可以加載(或存儲)的數(shù)據(jù)類型可以是有符號和無符號字、半字或字節(jié)。這些數(shù)據(jù)類型的擴展是。-h或-sh用于半字,-b或-sb用于字節(jié),而字則沒有擴展。有符號和無符號數(shù)據(jù)類型之間的區(qū)別是。
有符號的數(shù)據(jù)類型可以容納正值和負值,因此范圍較小。
無符號數(shù)據(jù)類型可以保存大的正值(包括 "零"),但不能保存負值,因此范圍更廣。
下面是一些例子,說明這些數(shù)據(jù)類型如何與指令Load和Store一起使用。

大小端
在內(nèi)存中,有兩種查看字節(jié)的基本方法。小端(LE)或大端(BE)。區(qū)別在于一個對象的每個字節(jié)在內(nèi)存中的存儲順序。在像英特爾x86這樣的小端機器上,最不重要的字節(jié)被存儲在最低地址(最接近零的地址)。在big-endian機器上,最重要的字節(jié)被存儲在最低地址。ARM架構(gòu)在第3版之前是小-endian,從那時起,它是雙-endian,這意味著它有一個允許可切換endianness的設置。例如,在ARMv6中,指令是固定的小字節(jié),數(shù)據(jù)訪問可以是小字節(jié)或大字節(jié),由程序狀態(tài)寄存器(CPSR)的第9位(E位)控制。

ARM寄存器
寄存器的數(shù)量取決于ARM的版本。根據(jù)ARM參考手冊,除了基于ARMv6-M和ARMv7-M的處理器外,有30個通用的32位寄存器。前16個寄存器可在用戶級模式下訪問,其他寄存器可在特權軟件執(zhí)行中使用(ARMv6-M和ARMv7-M例外)。在本系列教程中,我們將處理在任何特權模式下都可以訪問的寄存器:r0-15。這16個寄存器可以分成兩組:通用寄存器和特殊用途寄存器。


下表展示了ARM寄存器與Intel處理器中的寄存器之間的關系。

R0-R12:在普通操作中可用于存儲臨時值、指針(存儲器的位置)等。例如,R0在進行算術運算時可作為累加器,或用于存儲先前調(diào)用的函數(shù)的結(jié)果。R7在處理系統(tǒng)調(diào)用時變得非常有用,因為它存儲了系統(tǒng)調(diào)用的編號,R11幫助我們跟蹤堆棧上的邊界,作為框架指針(將在后面介紹)。此外,ARM的函數(shù)調(diào)用慣例規(guī)定,函數(shù)的前四個參數(shù)存儲在寄存器r0-r3中。
R13:SP(堆棧指針)。堆棧指針指向堆棧的頂部。堆棧是一個用于特定函數(shù)存儲的內(nèi)存區(qū)域,在函數(shù)返回時被回收。因此,堆棧指針用于分配堆棧的空間,方法是用堆棧指針減去我們要分配的值(以字節(jié)為單位)。換句話說,如果我們想分配一個32位的值,我們從堆棧指針中減去4。
R14:LR(鏈接寄存器)。當一個函數(shù)被調(diào)用時,鏈接寄存器被更新為內(nèi)存地址,引用函數(shù)啟動的下一條指令。這樣做允許程序在 "子 "函數(shù)完成后返回到啟動 "子 "函數(shù)的 "父 "函數(shù)。
R15:PC(程序計數(shù)器)。程序計數(shù)器根據(jù)所執(zhí)行的指令的大小自動遞增。這個大小在ARM狀態(tài)下總是4字節(jié),在THUMB模式下是2字節(jié)。當一個分支指令被執(zhí)行時,PC保存目標地址。在執(zhí)行過程中,PC在ARM狀態(tài)下存儲當前指令的地址加8(兩條ARM指令),在Thumb(v1)狀態(tài)下存儲當前指令加4(兩條Thumb指令)。這與x86不同,x86的PC總是指向要執(zhí)行的下一條指令。
讓我們看看PC在調(diào)試器中是如何表現(xiàn)的。我們用下面的程序?qū)C的地址存入r0,并包括兩條隨機指令。讓我們看看會發(fā)生什么。

在gdb中我們在_start處設定一個斷點

如下是運行的結(jié)果:

我們可以看到,PC持有將被執(zhí)行的下一條指令(mov r0, pc)的地址(0x8054)。現(xiàn)在讓我們執(zhí)行下一條指令,之后R0應該持有PC的地址(0x8054),對嗎?

...對嗎?錯了。看看R0中的地址。當我們期望R0包含先前讀取的PC值(0x8054)時,它卻包含了比我們先前讀取的PC值(0x805c)提前兩條指令的值。從這個例子中你可以看到,當我們直接讀取PC時,它遵循PC指向下一條指令的定義;但在調(diào)試時,PC指向當前PC值前面的兩條指令(0x8054 + 8 = 0x805C)。這是因為較早的ARM處理器總是在當前執(zhí)行的指令之前獲取兩條指令。ARM保留這一定義的原因是為了確保與早期處理器的兼容性。
當前程序狀態(tài)寄存器
當你用gdb調(diào)試一個ARM二進制文件時,你會看到一個叫做Flags的東西。

寄存器$cpsr顯示了當前程序狀態(tài)寄存器(CPSR)的值,在它下面可以看到Flagsthumb, fast, interrupt, overflow, carry, zero, and negative。這些標志代表了CPSR寄存器中的某些位,并根據(jù)CPSR的值來設置,激活時變成粗體。N、Z、C和V位與x86上EFLAG寄存器中的SF、ZF、CF和OF位相同。這些位被用來支持匯編級的條件和循環(huán)的條件執(zhí)行。我們將在第6部分 "條件執(zhí)行和分支 "中介紹使用的條件代碼。

上圖顯示了一個32位寄存器(CPSR)的布局,左邊(<-)是最重要的位,右邊(->)是最小的位。每一個單元(除了GE和M部分以及空白部分)都是一個比特的大小。這些一比特的部分定義了程序當前狀態(tài)的各種屬性。

讓我們假設我們使用CMP指令來比較數(shù)字1和2。結(jié)果是 "負",因為1-2=-1。當我們比較兩個相等的數(shù)字時,比如2對2,Z(零)標志被設置,因為2-2=0。請記住,CMP指令使用的寄存器不會被修改,只有CPSR會根據(jù)這些寄存器相互比較的結(jié)果被修改。
這是GDB中的情況(安裝了GEF)。在這個例子中,我們比較寄存器r1和r0,其中r1=4,r0=2。這是執(zhí)行了cmp r1, r0操作后的標志的情況。
進位標志被設置,因為我們用cmp r1, r0來比較4和2(4-2)。相反,如果我們使用cmp r0, r1來比較一個較小的數(shù)字(2)和一個較大的數(shù)字(4),則負標志(N)被設置。
下面是ARM信息中心的一段摘錄:
APSR包含以下ALU狀態(tài)標志。
N - 當操作的結(jié)果為負數(shù)時設置。
Z - 當操作的結(jié)果為零時設置。
C - 當操作的結(jié)果是Carry時設置。
V--當操作引起溢出時設置。
carry在以下情況被設置:
如果加法的結(jié)果大于或等于2^32
如果減法的結(jié)果是正數(shù)或零
作為移動或邏輯指令中的內(nèi)聯(lián)移位操作的結(jié)果。
如果加法、減法或比較的結(jié)果大于或等于2^31,或小于2^31,則發(fā)生溢出。
-
ARM
+關注
關注
135文章
9552瀏覽量
391843 -
寄存器
+關注
關注
31文章
5608瀏覽量
129968 -
匯編
+關注
關注
2文章
214瀏覽量
27406
發(fā)布評論請先 登錄
MSP-ESP430G2常用數(shù)據(jù)類型及字節(jié)數(shù)值范圍基礎知識補充
數(shù)據(jù)寄存器,數(shù)據(jù)寄存器是什么意思
匯編語言教程-段寄存器的說明語句
匯編語言學習課件_微處理器基礎知識
python教程之變量和簡單數(shù)據(jù)類型
[從零學習匯編語言] -寄存器詳解
第二章(1) 初識P0,P1并口 數(shù)據(jù)類型,常量定義方法,特殊功能寄存器定義
Verilog HDL語言的數(shù)據(jù)類型和運算符
四種類型的 JTAG 數(shù)據(jù)寄存器介紹
Go匯編基礎知識
Verilog最常用的2種數(shù)據(jù)類型
匯編基礎知識教程之數(shù)據(jù)類型與寄存器
評論