arm64彙編篇-07cpsr狀態暫存器
狀態暫存器
CPU內部的暫存器中,有一種特殊的暫存器(對於不同的處理器,個數和結構都可能不同).這種暫存器在ARM中,被稱為狀態暫存器就是CPSR(current program status register)暫存器
CPSR和其他暫存器不一樣,其他暫存器是用來存放資料的,都是整個暫存器具有一個含義.而CPSR暫存器是按位起作用的,也就是說,它的每一位都有專門的含義,記錄特定的資訊.
cpsr特點
1.CPSR暫存器是32位的.
2.CPSR的低8位(包括I、F、T和M[4:0])稱為控制位,程式無法修改,除非CPU運行於特權模式下,程式才能修改控制位!
3.N、Z、C、V均為條件碼標誌位。它們的內容可被算術或邏輯運算的結果所改變,並且可以決定某條指令是否被執行!意義重大!
4.32點陣圖解如下
NZCV介紹
N(Negative)標誌
CPSR的第31位是 N,符號標誌位。它記錄相關指令執行後,其結果是否為負.如果為負 N = 1,如果是非負數 N = 0.
注意,在ARM64的指令集中,有的指令的執行時影響狀態暫存器的,比如add\sub\or等,他們大都是運算指令(進行邏輯或算數運算);
Z(Zero)標誌
CPSR的第30位是Z,0標誌位。它記錄相關指令執行後,其結果是否為0.如果結果為0.那麼Z = 1.如果結果不為0,那麼Z = 0.
對於Z的值,我們可以這樣來看,Z標記相關指令的計算結果是否為0,如果為0,則N要記錄下是0這樣的肯定資訊.在計算機中1表示邏輯真,表示肯定.所以當結果為0的時候Z = 1,表示結果是0.如果結果不為0,則Z要記錄下不是0這樣的否定資訊.在計算機中0表示邏輯假,表示否定,所以當結果不為0的時候Z = 0,表示結果不為0。
C(Carry)標誌
CPSR的第29位是C,進位標誌位。一般情況下,進行無符號數的運算。加法運算:當運算結果產生了進位時(無符號數溢位),C=1,否則C=0。減法運算(包括CMP):當運算時產生了借位時(無符號數溢位),C=0,否則C=1。
對於位數為N的無符號數來說,其對應的二進位制資訊的最高位,即第N - 1位,就是它的最高有效位,而假想存在的第N位,就是相對於最高有效位的更高位。如下圖所示:
V(Overflow)溢位標誌
CPSR的第28位是V,溢位標誌位。在進行有符號數運算的時候,如果超過了機器所能標識的範圍,稱為溢位。
注意:運算規則
正數 + 正數 為負數 溢位
負數 + 負數 為正數 溢位
正數 + 負數 不可能溢位
相關概念介紹
進位
我們知道,當兩個資料相加的時候,有可能產生從最高有效位想更高位的進位。比如兩個32位資料:0xaaaaaaaa + 0xaaaaaaaa,將產生進位。由於這個進位值在32位中無法儲存,我們就只是簡單的說這個進位值丟失了。其實CPU在運算的時候,並不丟棄這個進位制,而是記錄在一個特殊的暫存器的某一位上。ARM下就用C位來記錄這個進位值。比如,下面的指令:
mov w0,#0xaaaaaaaa;0xa 的二進位制是 1010
adds w0,w0,w0; 執行後 相當於 1010 << 1 進位1(無符號溢位) 所以C標記 為 1
adds w0,w0,w0; 執行後 相當於 0101 << 1 進位0(無符號沒溢位) 所以C標記 為 0
adds w0,w0,w0; 重複上面操作\nadds w0,w0,w0
注:adds subs 等後面加s代表其運算會影響標記暫存器
借位
當兩個資料做減法的時候,有可能向更高位借位。再比如,兩個32位資料:0x00000000 - 0x000000ff,將產生借位,借位後,相當於計算0x100000000 - 0x000000ff。得到0xffffff01 這個值。由於借了一位,所以C位 用來標記借位。C = 0.比如下面指令:
mov w0,#0x0
subs w0,w0,#0xff ;
subs w0,w0,#0xff
subs w0,w0,#0xff
真機實踐:
1.c語言中使用匯編程式碼方法:1)在方法中加asm()如下
void func()
{
asm(
"mov w0,#0x0\n" //這區域中寫彙編程式碼 換行用\n
)
}
2.cpsr作用例項:輸入以下程式碼
/** 狀態暫存器 cpsr */
void cpsrFunc(){
/**1. cpsr的作用 */
int a = 1;
int b = 2;
if (a == b) {
printf("a==b");
} else {
printf("a!=b");
}
}
執行結果如下圖:
在判斷結束並未執行的時候修改暫存器如下圖:
1)先切換成檢視彙編模式
2)設定斷點並修改cpsr暫存器值
3)執行結果
3.N(negative)標誌例項:
1)cpsrFunc方法中輸入以下程式碼:
/** 2. negative標誌符 */
asm(
"mov w0,#0xffffffff\n"
"adds w0,w0,#0x0\n"
);
2)彙編除錯
如圖0xffffffff在計算符號時候為負數,現在改成0x0fffffff看結果這個在有符號中為正數。
4.Z標誌例項
1)cpsrFunc方法輸入以下程式碼
/** 3. zero標誌符 */
asm(
"mov w0,#0x0\n"
"adds w0,w0,#0x0\n"
);
2)執行程式碼效果:
3)將相加值修改成大於0 #0x1
5.C標誌例項
注:C位主要是無符號的進位和借位問題,上文已經講了,這邊可以系統的理解。
1)進位當相加超限會進1,例如11 + 1 = 100 其中1超限被儲存在c位,所以c位為1。
2)借位就是不夠減從前面借一位前面會多出1,例如 00 - 1 為100 - 1 = 11,同理憑空而生的1也儲存在c位,所以得到借位為1,進位為1其他為0的結論,如果不理解可以死記。
程式碼上面在介紹進位借位已經寫明大家可以自己嘗試。
6.V標誌例項。
注:這邊是在有符號位運算。
1)cpsrFunc方法輸入以下程式碼
/** 5. overflow v位標誌符號 */
asm(
"mov w0,#0x7fffffff\n"
"adds w0,w0,#0x2\n"
"mov w0,#0x80000000\n"
"subs w0,w0,#0x2\n"
);
2)執行結果
注:mac計算器功能很強大是很好輔助工具。
如上圖當v位滿足正正得負 負負得正的情況下v位為1否則為0。