天天看點

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位圖解如下

arm64彙編篇-07cpsr狀态寄存器

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位,就是相對于最高有效位的更高位。如下圖所示:

arm64彙編篇-07cpsr狀态寄存器

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).建立彙編檔案command + n 選擇assembly 檔案寫彙編代碼,詳情見https://www.jianshu.com/p/9f63cb7a334c  這裡就不重複介紹了。

2.cpsr作用執行個體:輸入以下代碼

void cpsrFunc(){

     int a = 1;   

     int b = 2;   

    if (a == b) {     

        printf("a==b"); 

  }    else    {       

       printf("a!=b");    

   }

}

運作結果如下圖:

arm64彙編篇-07cpsr狀态寄存器

在判斷結束并未執行的時候修改寄存器如下圖:

1)先切換成檢視彙編模式

arm64彙編篇-07cpsr狀态寄存器

2)設定斷點并修改cpsr寄存器值

arm64彙編篇-07cpsr狀态寄存器

3)運作結果

arm64彙編篇-07cpsr狀态寄存器

3.N(negative)标志執行個體:

1)cpsrFunc方法中輸入以下代碼:

asm(   

    "mov w0,#0xffffffff\n" 

      "adds w0,w0,#0x0\n" 

      );

2)彙編調試

arm64彙編篇-07cpsr狀态寄存器

如圖0xffffffff在計算符号時候為負數,現在改成0x0fffffff看結果這個在有符号中為正數。

arm64彙編篇-07cpsr狀态寄存器

4.Z标志執行個體

1)cpsrFunc方法輸入以下代碼

asm( 

      "mov w0,#0x0\n"     

  "adds w0,w0,#0x0\n"       

);

2)執行代碼效果:

arm64彙編篇-07cpsr狀态寄存器

3)将相加值修改成大于0 #0x1

arm64彙編篇-07cpsr狀态寄存器

5.C标志執行個體

注:C位主要是無符号的進位和借位問題,上文已經講了,這邊可以系統的了解。

1)進位當相加超限會進1,例如11 + 1 = 100 其中1超限被儲存在c位,是以c位為1。

2)借位就是不夠減從前面借一位前面會多出1,例如 00 - 1 為100 - 1 = 11,同理憑空而生的1也儲存在c位,是以得到借位為1,進位為1其他為0的結論,如果不了解可以死記。

代碼上面在介紹進位借位已經寫明大家可以自己嘗試。

arm64彙編篇-07cpsr狀态寄存器

6.V标志執行個體。

注:這邊是在有符号位運算。

1)cpsrFunc方法輸入以下代碼

  asm(       

"mov w0,#0x7fffffff\n"     

  "adds w0,w0,#0x2\n"     

  "mov w0,#0x80000000\n"     

  "subs w0,w0,#0x2\n"     

  );

2)運作結果

arm64彙編篇-07cpsr狀态寄存器

注:mac電腦功能很強大是很好輔助工具。

如上圖當v位滿足正正得負 負負得正的情況下v位為1否則為0。