1. 程式人生 > >【補充】關於ARM的PC指標異常返回處理(PC+8,PC+4,PC-4,PC-8情況)

【補充】關於ARM的PC指標異常返回處理(PC+8,PC+4,PC-4,PC-8情況)

要理解PC指標,首先就要好好了解LR指標

連線暫存器LR(r14):用來儲存和恢復PC暫存器的內容,它有兩個特殊功能。

    (1)儲存子程式返回地址。使用BL或BLX時,跳轉指令自動把返回地址放入r14中;子程式通過把r14複製到PC來實現返回,通常用下列指令之一:
                        MOV PC, LR 
                        BX LR

             通常子程式這樣寫,保證了子程式中還可以呼叫子程式。
                         stmfd sp!, {lr}
                         ……
                         ldmfd sp!, {pc}

    (2)當異常發生時,異常模式的r14用來儲存異常返回地址,將r14如棧可以處理巢狀中斷。

程式計數器r15(PC):PC是有讀寫限制的。當沒有超過讀取限制的時候,讀取的值是指令的地址加上8個位元組,由於ARM指令總是以字對齊的,故bit[1:0]總是00。當用str或stm儲存PC的時候,偏移量有可能是8或12等其它值。在V3及以下版本中,寫入bit[1:0]的值將被忽略,而在V4及以上版本寫入r15的bit[1:0]必須為00,否則後果不可預測。

知道PC暫存器和LR暫存器功能以後,再瞭解一下ARM處理器的三級流水線和多級流水線

首先,對於ARM7對應的流水線的執行情況,如下面這個圖所示:




從圖中可以看出,一條彙編指令的執行有三個步驟,取指、譯碼、執行,當第一條彙編指令取指完成後,緊接著就是第二條指令的取指,然後第三條...如此巢狀

其實很容易看出,第一條指令:

add r0, r1,#5

取指完成後,PC就指向了第二條指令,此時PC=PC+4

當第一條指令譯碼完成以後,此時PC=PC+8

所以第一條指令開始執行時,PC值已經加了8

所以必須記住這個前提,在arm中,每次該指令執行時,其實這時的PC值是PC=PC+8

接下來談談我們在arm彙編時,什麼時候需要PC-4, PC-8, PC什麼都不減

!記住:PC不是指向你正在執行的指令,而是PC始終指向你要取指的指令的地址

我們以下面uboot中的start.S的最開始的彙編程式碼為例來進行解釋:

00000000 <_start>:
   0:	ea000014 	b	58 <reset>
   4:	e59ff014 	ldr	pc, [pc, #20]	; 20 <_undefined_instruction>
   8:	e59ff014 	ldr	pc, [pc, #20]	; 24 <_software_interrupt>
   c:	e59ff014 	ldr	pc, [pc, #20]	; 28 <_prefetch_abort>
  10:	e59ff014 	ldr	pc, [pc, #20]	; 2c <_data_abort>
  14:	e59ff014 	ldr	pc, [pc, #20]	; 30 <_not_used>
  18:	e59ff014 	ldr	pc, [pc, #20]	; 34 <_irq>
  1c:	e59ff014 	ldr	pc, [pc, #20]	; 38 <_fiq>

00000020 <_undefined_instruction>:
  20:	00000120 	.word	0x00000120

流水線如表格:
指令實體地址Cycle1Cycle2Cycle3Cycle4Cycle5Cycle6
0
4取指譯碼執行
8取指譯碼執行
c取指譯碼執行
10取指譯碼執行
14取指譯碼
18取指

紅色加粗字型代表:實際PC的實體地址(即PC始終指向你要取的指令的地址

  1. 指令週期Cycle1
    1. 取指

      PC總是指向將要讀取的指令的地址(即我們常說的,指向下一條指令的地址),而當前PC=4,

      所以去取實體地址為4對對應的指令

      ldr	pc, [pc, #20]

      其對應二進位制程式碼為e59ff014。

      此處取指完之後,自動更新PC的值,即PC=PC+4(單個指令佔4位元組,所以加4)=4+4=8

  2. 指令週期Cycle2
    1. 譯指

      翻譯地址為4的指令e59ff014

    2. 同時再去取指

      PC總是指向將要讀取的指令的地址(即我們常說的,指向下一條指令的地址),而當前PC=8,

      所以去實體地址為8所對應的指令“ldr pc, [pc, #20]” 其對應二進位制程式碼為e59ff014。

      此處取指完之後,自動更新PC的值,即PC=PC+4=8+4=12=0xc

  3. 指令週期Cycle3
    1. 執行(指令)

      執行“e59ff014”,即

      ldr	pc, [pc, #20]

      所對錶達的含義,即PC

      = PC + 20

      = 12 + 20

      = 32

      = 0x20

      此處,只是計算出待會要賦值給PC的值是0x20,這個0x20還只是放在執行單元中內部的緩衝中。

    2. 譯指

      翻譯地址為8的指令e59ff014

    3. 取指

      此步驟由於是和上面a.中的執行同步做的,所以,未受到影響,繼續取指,而取指的那一時刻,PC為上一Cycle更新後的值,即PC=0xc,所以是去取實體地址為0xc所對應的指令

      ldr	pc, [pc, #20]

      對應二進位制為e59ff014   此處取指完之後,自動更新PC的值,即PC=PC+4=0xc+4=0x10

用圖來總結過程:


再記住:改變PC的值,會導致流水線清空!!!

好了,那我們繼續來看什麼時候需要PC-4, PC-8, PC什麼都不減

這個取決於是在正常程式的跳轉還是發生異常:

我先假設當前執行上面地址4所對應的指令,將它稱作第一條指令!<即現在狀態為上面cycle3>

------------------------------------------------------------------------------------------------------------------------------------------------------------

正常跳轉:

如果是使用BL執行了正常程式的跳轉,那麼執行這條BL指令時,由於是正常的跳轉指令,所以cpu會將下一句的實體地址存放在LR中,那麼將8地址存放在LR中),當從子程式跳轉回來的時候,那麼就需要將儲存在LR暫存器中的值恢復給PC暫存器,mov PC, LR     這樣的指令返回

------------------------------------------------------------------------------------------------------------------------------------------------------------

異常跳轉:

當前執行的是地址4對應的第一條指令,

在分別講解各種異常之前,有一條總的原則就是:無論發生什麼異常(除復位),核心總是會首先將 PC-4 放到LR暫存器中。(PC始終指向你要取指的指令的地址 即:PC = 當前指令實體地址 + 8

IRQ異常發生時cpu已經自動更新pc值(4+8+4=10),=》LR  = c(10-4),指向的第三條指令,如果不進行減4處理,我們回來將會漏執行第二條指令,所以PC恢復的時候就需要LR減4,所以正常從子程式返回的時候會使用如:

SUBS PC, LR,#4     返回到當前指令的下一條指令

未定義指令異常時cpu還沒有自動更新pc值(4+8=c),=》LR  = 8(c-4)  ;因為該指令未定義,所以返回時就不應該返回到這條未定義指令,而是返回到它的下一條指令,R14中儲存的剛好就是下一條指令的地址,所以就不用計算了,直接將R14賦值給PC就行了,即mov PC, LR

預取指令異常時即cpu還沒有自動更新pc值(4+8=c),=》LR  = 8(c-4)  出現預取指令異常後,要重新再執行一次這條指令,這也是與其他異常不太一樣的地方。,所以PC恢復的時候就需要R14減4,即SUBS PC, LR,#4

資料中止異常,這個異常表示當前儲存器的訪問不能完成,是在本指令執行完成才發生的,即cpu已經自動更新pc值(4+8+4=10)=》LR  = c(10-4),我們從異常返回時,要重新再執行一次這條指令,所以PC恢復的時候就需要R14減8,即SUBS PC, LR,#8


【參考資料】:

隋邊邊

相關推薦

補充關於ARM的PC指標異常返回處理PC+8PC+4PC-4,PC-8情況

要理解PC指標,首先就要好好了解LR指標連線暫存器LR(r14):用來儲存和恢復PC暫存器的內容,它有兩個特殊功能。    (1)儲存子程式返回地址。使用BL或BLX時,跳轉指令自動把返回地址放入r14中;子程式通過把r14複製到PC來實現返回,通常用下列指令之一:     

NIFI Apache NiFI 之 ExecuteScript處理 NIFI Apache NiFI 之 ExecuteScript處理

  本例介紹NiFI ExecuteScript處理器的使用,使用的指令碼引擎ECMScript   接上一篇【NIFI】 Apache NiFI 之 ExecuteScript處理(一) ExecuteScript使用   1、動態屬性     其中一個功能是動態屬性的概念,也稱為使用者定義屬性。這

Trick機器學習特徵工程處理

前言 機器學習特徵工程處理系列部落格為博主學習相關視訊教程以及結合平時接觸到的特徵工程處理方法,總結出的一些處理技巧,本篇部落格介紹資料格式化、資料清洗、資料取樣等,我在之前有總結過一篇部落格介紹資料預處理的常用方法,對其中的部分操作有涉及,如有需要,可參考本

Java基礎:常見修飾符權限修飾符以及abstract、static、final等與變量的描述

線程 cte string 數據 執行 style 權限 實例 類名 1. 修飾符 public、protected、private、default abstract、static、final、 abstract:抽象類、抽象方法 static:靜態變量、

安裝Windows下 TensorFlow 的安裝包含:CUP版、GPU版、CUDA、cuDNN——最後更新日期 2018-05-30

____tz_zs您可以直接使用pip安裝tensorflow,只需一行程式碼就安裝好了。cpu版:pip3 install --upgrade tensorflow·gpu版:pip3 install --upgrade tensorflow-gpu·但是,推薦您使用Ana

python全棧開發基礎補充異常處理

ret ror div 問題 條件 self. float 異常處理機制 有關 一、錯誤與異常 程序中難免會出現錯誤,而錯誤分為兩種 1.語法錯誤:(這種錯誤,根本過不了python解釋器的語法檢測,必須在程序執行前就改正) 2.邏輯錯誤:(邏輯錯誤),比如用戶輸入的不合適

SpringSpringMVC之異常處理

存儲 targe 存在 cnblogs del file 處理機制 href click java中的異常分為兩類,一種是運行時異常,一種是非運行時異常。在JavaSE中,運行時異常都是通過try{}catch{}捕獲的,這種只能捕獲顯示的異常,通常項目上拋出的異常都是不可

轉載java7的異常處理新特性

原文地址:https://my.oschina.net/fhd/blog/324484 前輩們非常給力! addSuppressed()方法 開發人員對異常處理的try-catch-finally語句塊都比較熟悉。如果在try語句塊中丟擲了異常,在控制權轉移到呼叫棧上一層程式碼之前,

python—爬蟲學習_3(異常處理

1.URLError 首先解釋下URLError可能產生的原因: 網路無連線,即本機無法上網 連線不到特定的伺服器 伺服器不存在 在程式碼中,我們需要用try-except語句來包圍並捕獲相應的異常。 2.HTTPError HTTPError是URLErr

JavaJava基礎 —— 異常處理

一、前言 寫程式碼的時候,異常處理是必不可少的。對異常處理的一些瞭解還是應該具備的,下面小編就從java的異常方面來說說 二、異常處理機制 使用try … catch 捕獲異常 try{ //業務程式碼 ... }catch(Exception

JAVA中異常分類以及異常處理方法之間的區別以及聯絡

異常在日長開發中就像看見地鐵裡邊的人頭一樣的,放眼望去,齊刷刷的一片,各種異常。分佈範圍比較廣泛,很多人看到異常,就這表情 JAVA中異常: NullPointerException 空指標異常

Java的異常處理

一、基本概念 看java的異常結構圖 Throwable是所有異常的根,java.lang.Throwable Error是錯誤,java.lang.Error Exception是異常,java.lang.Exception 二、Exception 一般分為Che

JAVA學習——JAVA中異常及其處理

        首先在瞭解異常的概念之前,需要了解一下異常和普通問題:對於普通的問題在編譯上是語法錯誤,而相較之異常則是在執行時邏輯產生的錯誤,往往產生異常。當然這是表面的理解。         普通問題是指:在當前環境下不能得到足夠的資訊,比如語法錯誤,此時錯誤將會向外傳

14.數據庫基本概念補充

acc net 要求 完整性 對數 輕量級 控制 sqlit 安全 數據庫特點:海量存儲、查找速度快、並發性問題控制、安全性、數據完整性(保存在數據庫中的數據是正確的,真實的)。 Table(表):關系數據庫中的[關系]指的就是表。 不同品牌的DBMS有自己的不同的特點:M

python全棧開發補充map函數和reduce函數的區別

lambda mage 多個 計算 兩個 數值 ima 所有 post ①從參數方面來講:map()函數:  map()包含兩個參數,第一個是參數是一個函數,第二個是序列(列表或元組)。其中,函數(即map的第一個參數位置的函數)可以接收一個或多個參數。reduce()函數

python全棧開發補充復習os模塊常用的一些操作

刪除 os.walk post 好用 更新 tor inux abs 結構 import os # 1.切換路徑============= d = os.getcwd() #獲取當前的工作路徑 os.chdir(‘D:\\‘)#目錄的切換 print(os.getcwd

python全棧開發補充包的補充

src 沖突 onf 全棧 map imp 創建目錄 bubuko com 1.包A和包B下有同名模塊也不會沖突,因為A.a與B.a來自倆個命名空間 2.常見目錄結構 # 創建目錄代碼 import os os.makedirs(‘glance/api‘) os.ma

python全棧開發補充單例模式的四種方式

實現 創建 初始 user 它的 pooled asa args 三種 一、什麽是單例模式 保證一個類只有一個實例,並提供一個訪問它的全局訪問點 二、優點 對唯一實例的受控訪問 單利相當於全局變量,但防止了命名空間被汙染 與單利模式功能相似的概念:全局變量、靜態變量

python全棧開發基礎補充metaclass元類

認識 全棧 rgs bubuko class a alt 創建 繼承 圖片 一、創建類的執行流程 二、元類的認識 什麽是元類呢?在Python3中繼承type的就是元類 二、元類的示例 # 方式一 class MyType(type): ‘‘‘繼承type

python全棧開發基礎補充解決tcp粘包

技術 服務端 消息 log 完成後 open unpack div pytho 一、什麽是粘包 須知:只有TCP有粘包現象,UDP永遠不會粘包 粘包不一定會發生 如果發生了:1.可能是在客戶端已經粘了       2.客戶端沒有粘,可能是在服務端粘了 首先需要掌握一個soc