狀態(tài)寄存器--CPSR寄存器
CPU內(nèi)部的寄存器中嚣镜,有一種特殊的寄存器(對于不同的處理器,個數(shù)和結(jié)構(gòu)都可能不同)。這種寄存器在ARM中橘蜜,被稱為狀態(tài)寄存器就是CPSR(current program status register)寄存器菊匿。
CPSR和其他寄存器不一樣,其他寄存器是用來存放數(shù)據(jù)的计福,都是整個寄存器具有一個含義跌捆。而CPSR寄存器是按位起作用的,也就是說,它的每一位都有專門的含義,記錄特定的信息。
也叫標(biāo)記寄存器
注:CPSR寄存器是32位的
- CPSR的低8位(包括I象颖、F佩厚、T和M[4:0])稱為控制位,程序無法修改,除非CPU運行于特權(quán)模式下说订,程序才能修改控制位抄瓦。
- N、Z克蚂、C闺鲸、V均為條件碼標(biāo)志位筋讨。它們的內(nèi)容可被算術(shù)或邏輯運算的結(jié)果所改變埃叭,并且可以決定某條指令是否被執(zhí)行,意義重大!
N(Negative)標(biāo)志
CPSR的第31位是 N(符號標(biāo)志位)悉罕,它記錄相關(guān)指令執(zhí)行后,其結(jié)果是否為負(fù)數(shù)赤屋。
如果結(jié)果為負(fù)數(shù)立镶,那么 N = 1;如果結(jié)果是非負(fù)數(shù)类早,那么 N = 0
注意:在ARM64的指令集中媚媒,有的指令的執(zhí)行時影響狀態(tài)寄存器的,比如adds / subs / ors等涩僻,它們大都是運算指令(進(jìn)行邏輯或算數(shù)運算)
上代碼測試
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
void fun(){
asm(
"mov w0, #0x7fffffff\n"
"adds w0, w0, #0x1\n"
"subs w0, w0, #0x1\n"
);
}
int main(int argc, char * argv[]) {
fun();
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
Z(Zero)標(biāo)志
CPSR 的第30位是 Z(0標(biāo)志位)逆日,它記錄相關(guān)指令執(zhí)行后,其結(jié)果是否為0嵌巷。
如果結(jié)果為0,那么 Z = 1室抽;如果結(jié)果不為0搪哪,那么Z = 0
對于Z的值,我們可以這樣來看坪圾,Z 標(biāo)記相關(guān)指令的計算結(jié)果是否為0晓折。
如果結(jié)果為0,則 N 要記錄下"結(jié)果為0"這樣的肯定信息兽泄。
在計算機(jī)中1表示邏輯真漓概,表示肯定。所以當(dāng)結(jié)果為0的時候 Z = 1病梢,表示"結(jié)果為0"如果結(jié)果不為0垛耳,則Z要記錄下"結(jié)果不為0"這樣的否定信息。
在計算機(jī)中0表示邏輯假飘千,表示否定堂鲜,所以當(dāng)結(jié)果不為0的時候 Z = 0,表示"結(jié)果不為0"护奈。
上代碼測試
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
void fun(){
asm(
"mov w0, #0xffffffff\n"
"adds w0, w0, #0x1\n"
"subs w0, w0, #0x1\n"
);
}
int main(int argc, char * argv[]) {
fun();
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
C(Carry)標(biāo)志
CPSR 的第29位是 C(進(jìn)位標(biāo)志位)霉旗,一般情況下痴奏,進(jìn)行無符號數(shù)的運算。
加法運算:當(dāng)運算結(jié)果產(chǎn)生了進(jìn)位時(無符號數(shù)溢出)厌秒,那么 C = 1读拆,否則C = 0
減法運算(包括CMP):當(dāng)運算時產(chǎn)生了借位時(無符號數(shù)溢出),C=0鸵闪,否則C=1檐晕。
對于位數(shù)為 N 的無符號數(shù)來說,其對應(yīng)的二進(jìn)制信息的最高位,即第N - 1位辟灰,就是它的最高有效位个榕,而假想存在的第N位,就是相對于最高有效位的更高位芥喇。如下圖所示:
-
進(jìn)位
我們知道西采,當(dāng)兩個數(shù)據(jù)相加的時候,有可能產(chǎn)生從最高有效位向更高位的進(jìn)位继控。比如兩個32位數(shù)據(jù):0xaaaaaaaa + 0xaaaaaaaa械馆,將產(chǎn)生進(jìn)位。由于這個進(jìn)位值在32位中無法保存武通,我們就只是簡單的說這個進(jìn)位值丟失了狱杰。其實CPU在運算的時候,并不丟棄這個進(jìn)位制厅须,而是記錄在一個特殊的寄存器的某一位上仿畸。ARM下就用C位來記錄這個進(jìn)位值。比如朗和,下面的指令
mov w0, #0xaaaaaaaa ;0xa 的二進(jìn)制是 1010 ==> 1010 1010 1010 ... 1010
adds w0, w0, w0 ;執(zhí)行后相當(dāng)于 1010 << 1 進(jìn)位1(無符號溢出)所以 C 標(biāo)記 為 1
adds w0, w0, w0 ;執(zhí)行后相當(dāng)于 0101 << 1 進(jìn)位0(無符號沒溢出)所以 C 標(biāo)記 為 0
adds w0, w0, w0 ;重復(fù)上面操作
adds w0, w0, w0
-
借位
當(dāng)兩個數(shù)據(jù)做減法的時候错沽,有可能向更高位借位。再比如眶拉,兩個32位數(shù)據(jù):0x00000000 - 0x000000ff千埃,將產(chǎn)生借位,借位后忆植,相當(dāng)于計算0x100000000 - 0x000000ff放可。得到0xffffff01 這個值。由于借了一位朝刊,所以C位 用來標(biāo)記借位耀里。C = 0.比如下面指令:
mov w0, #0x0
subs w0, w0, #0xff
subs w0, w0, #0xff
subs w0, w0, #0xff
V(Overflow)溢出標(biāo)志
CPSR的第28位是V(溢出標(biāo)志位),一般情況下拾氓,在進(jìn)行有符號數(shù)運算的時候冯挎,如果超過了機(jī)器所能標(biāo)識的范圍,稱為溢出咙鞍。
- 正數(shù) + 正數(shù) = 值為負(fù)數(shù) 溢出 V = 1
- 負(fù)數(shù) + 負(fù)數(shù) = 值為正數(shù) 溢出 V = 1
- 正數(shù) + 負(fù)數(shù) 不可能溢出 V = 0
內(nèi)存分布
內(nèi)存分布 | 特性 |
---|---|
代碼區(qū) | 可讀可寫 |
棧 | 存放參數(shù)和局部變量房官,可讀可寫 |
堆 | 動態(tài)申請,可讀可寫 |
全局區(qū) | 可讀可寫 |
常量區(qū) | 只讀 |
adrp 指令
是計算指定的數(shù)據(jù)地址到當(dāng)前PC值的相對偏移续滋。
adrp x0, 1
/*
假設(shè)當(dāng)前的 PC 寄存器為 0x1002e6874
1.先將1的值左移12位二進(jìn)制位則為 1 0000 0000 0000 ==> 0x1000
2.將 PC 寄存器的低12位清零翰守,也就是 0x1002e6874 ==> 0x1002e6000
3.最后將1和2的結(jié)果相加給 x0 寄存器,
x0 = 0x000001000 + 0x1002e6000
x0 = 0x1002e7000
*/
補充:
- 計算機(jī)存儲數(shù)據(jù)它會分為有符號數(shù)和無符號數(shù)疲酌。
- 有符號數(shù)是針對二進(jìn)制來講的蜡峰。用最高位作為符號位,“0”代表“+”,“1”代表“-” 事示;其余數(shù)位用作數(shù)值位早像,代表數(shù)值僻肖。
- 有符號數(shù)的表示:計算機(jī)中的數(shù)據(jù)用二進(jìn)制表示肖爵,數(shù)的符號也只能用0/1表示。一般用最高有效位(MSB)來表示數(shù)的符號臀脏,正數(shù)用0表示劝堪,負(fù)數(shù)用1表示。
32位 int 中 0x7FFFFFFF為最大值2^31 - 1 揉稚、0x80000000為最小值-2^31
-
我們來看看0x80000000的輸出
- 0x80000000的二進(jìn)制位原碼為 1000 0000 0000 0000 0000 0000 0000 0000
- 若最高位是符號位為1秒啦,為負(fù)數(shù),則為 -0搀玖。
- 可是在代碼執(zhí)行 int i = 0x80000000 余境,卻輸出為 i = -(2^31)。
- 原因是在十六進(jìn)制中負(fù)數(shù)的二進(jìn)制原碼的最高位是符號位灌诅,后面的31位為序號位芳来,不是值位。
- 1后面的000 0000 0000 0000 0000 0000 0000 0000猜拾,表示序號1即舌,表示負(fù)數(shù)中,從小到大的第一位挎袜。
- 由于 int 的最小值為 -(2^31)顽聂,排在負(fù)數(shù)從小到大的序號0,所以 int i = 0x80000000盯仪,輸出為 i = -(2^31)紊搪。
-
我們來看看0xFFFFFFFF的輸出
- 0xFFFFFFFF的二進(jìn)制原碼為 1111 1111 1111 1111 1111 1111 1111 1111
- 最高位是符號位為1 ,為負(fù)數(shù)全景,序號位為第(2^31) - 1位 (111 1111 1111 1111 1111 1111 1111 1111=(2^31-1)嗦明,
- 所以 0xFFFFFFFF 為負(fù)數(shù)從小到大 第2^31-1位 ,即 -(2^31) + (2^31-1) = -1
總結(jié):數(shù)值 = 該符號下最小值 + 序號位表示數(shù)