2014-10-08 157 views
0

我對ARM寄存器有些懷疑。ARM寄存器的功能

  • r12的主要目標是什麼?與其他精品課程中的FP相同嗎?
  • 其中一些用於「刮」,是否意味着臨時存儲/調用者保存?
  • r13和r14根據模式有不同的名稱。如果我使用#MOV R0,R14_svc,我會在R0中獲取它的內容嗎?或者它只是一種區分不同模式下的R14的方法,而不存在硬件差異?
+0

[ARM寄存器保存](http://stackoverflow.com/questions/261419/arm-to-c-calling-convention-registers-to-save),[ARM鏈接和幀](http:// stackoverflow .com/questions/15752188/arm-link-register-and-frame-pointer)等。請參閱:[問],特別是,我認爲只有第3點還沒有被解決。然而,符號'R14_svc'是針對特定的ARM,而不是通用的。也就是說,在更高級的版本中,你這樣做。 – 2014-10-08 20:11:13

+0

版本ARM7TDMI?只是爲了測試,我想申請的代碼在樹莓B,版本11 – adrian 2014-10-08 20:12:16

+0

我不相信ARM7TDMI可以直接訪問'R14_svc'。它經常用在手冊中來描述中斷和/或SVC呼叫如何執行某些操作。從一種特權模式中,您可以暫時更改爲另一種特權模式,並將該寄存器移至**非庫**寄存器。 – 2014-10-08 20:14:30

回答

1

您正在查看結果而非症狀。

去武器網站(infocenter.arm.com)找到armv5的arm架構參考手冊,你可能不得不放棄一個電子郵件地址,但這些很容易,沒有什麼大不了的。

所以有了arm指令集和arm架構。有些寄存器是特殊的,有些則不是。很明顯,r15是非常特殊的,它是程序計數器,並且有一些尋址模式只支持r15(pc相對尋址)。同樣r14也是特殊的,它也是硬連線的分支鏈接指令,返回是通用的,但調用不是,確定你可以不使用r14進行調用,但這並不重要,r14是特殊的,因爲它是硬連接到一個/一些指令。

在拇指模式下,r13被硬編碼爲push和pop指令(在arm模式下ldm和stm可以在技術上使用任何寄存器,雖然r15可能是個壞主意)。

並有可能成爲別人...

所以一些寄存器是硬連接到某些指令或尋址模式。因此,除了所有這些,可能出於性能原因,還有不同的處理器模式,管理程序,中斷等...... arm文檔告訴你,這些寄存器中的一些具有_svc版本或_und版本等。是的, r14_svc位與r14_abt不同,如果修改r14_abt,則不能用r14_svc或r14_irq讀取該值。當特定指令根據處理器模式去讀或寫r14或r13等時,會選擇一個不同的存儲區並使用模式特定的寄存器組。對於r0-r7,在所有模式下使用相同的實際寄存器/位/ RAM,但是以r8開始以瞭解使用哪些寄存器,則必須查看該模式。根據ARM公司本聲明可能是不同的,但現在我在看一個說:

的ARM處理器共有37個寄存器:

,他們告訴你R0-R15的圖片,它加起來是37而不是16,因爲它們是單獨的寄存器。

現在你已經進入了與硬件無關的調用約定,它只是一個人們習慣使用的習慣或約定。如果你在回溯機器上跳轉,你可能會發現一些x86編譯器使用基於棧的參數傳遞,一些使用了基於寄存器的並且它們彼此不兼容,有時你可以指定在編譯時使用哪種約定。其他一些也是如此,但並非全部。如果您查看mips文檔,那裏的硬件人員喜歡根據慣例重新命名寄存器來定義調用約定,但這不是用硅來刻畫的,您不必遵守它。與在體系結構手冊之外的其他地方定義的手臂調用約定相同,因爲這從來沒有道理,但是它在某個地方被定義,並且編譯器編寫者無論是否適用於這些標準,甚至在符合這些標準時甚至改變手臂改變了慣例。

這是你開始看到使用r0-r3傳遞參數的約定,然後在你使用堆棧之後,如果你的電腦感覺需要有一個幀指針(懶惰的程序員,更容易調試編譯器輸出)他們選擇r12或其他。該公約規定,其登記的功能需要保留,哪些它沒有保存和它定義瞭如何返回值。雖然在某些方面的約定是任意的,如果你做你自己的編譯器,你可以發明自己的,或者使用堆疊中的所有時間,而不是登記等,你很可能使用的符合手臂調用約定(ABI/EABI編譯器)在其不斷髮展的版本之一。

是的,這就是爲什麼上寄存器中的一個或多個未在約定保留,因此,如果您覺得需要有一個幀指針,你可以使用它作爲一個幀指針。

是什麼意思保存?如果你看一下舊的天用更少的寄存器和不太成熟的編譯器和棧參數傳遞,你基本上保持每一個註冊你要在進入觸摸到一個功能,並恢復他們在退出時,您修改(返回值)的東西是在棧上或者你在函數中使用了堆棧的頂部來作爲volatile變量(局部變量,中間值等)。即使有16個寄存器,你可以開始談論使用寄存器傳遞參數,甚至去那麼遠,讓在那裏你不必保留所有這些公約。這是武裝公約所做的和其他一些事情。

unsigned int fun (unsigned int a, unsigned int b) 
{ 
    return(a+b+7); 
} 

a將被傳遞給寄存器r0中的寄存器r0中的函數,因爲慣例是這樣說的。返回值在r0中,因爲約定是這樣說的,所以代碼的優化版本將通過將r0加7來銷燬r0,所以a值不見了,從代碼中我們可以看到只需要一個值足夠長的時間用它做一次數學運算。所以我們可以

r0 = r0 + 7; 
r0 = r0 + r1; 

,並返回

,或者,我們

r1 = r1 + 7; 
r0 = r0 + r1; 
return 

或主題的其他變化。在上述任何一種情況下,我們都沒有保留r0,因爲該慣例基本上說我們必須銷燬內容,因爲這是我們的回報。但是,我們也允許在最低R0修改,R1,R2,R3所以我們也可以這樣做:

r2 = r1+7; 
r3 = r2+r0; 
r0 = r3; 
return 

因爲任何人,但我們關心與R0-R3,我們混亂的,這將是合法的(和有時是其他)。

,如果你這樣做

r4 = r1+7; 
r0 = r0 + r4; 
return 

你可能會得到幸運,不死機,或者你可能會崩潰正確的方式或許不是崩潰了很長很長時間,但隨後崩潰。爲什麼,因爲該規則說,我們不應該修改R4,我們必須保護它:

push {r4} 
r4 = r1+7; 
r0 = r0 + r4; 
pop {r4} 
return 

它必須是相同的值,當我們退出的功能,當我們進入。爲了說明這一點:

unsigned int fun (unsigned int a, unsigned int b) 
{ 
    return(more_fun(a,b)+a+b+7); 
} 

來實現這一點,我們可以做到這一點

push {r4,r14} 
r4 = r0 + r1; 
r4 = r4 + 7; 
call more_fun(); 
r0 = r0 + r4; 
pop {r4,r14} 
return 

我們需要記住的A + B + 7是基於R0和R1的值,但由於R0和R1可以通過more_fun()修改,我們或者需要保存它們,或者先做數學計算然後保存結果。無論哪種方式,我們都需要將它們放在堆棧上以保存它們或將它們放入非易失性寄存器中,並且要使用非易失性寄存器,我們需要保存其先前的內容。

現在,如果more_fun()違反了規則並修改了r4,那麼我們的fun()結果將不正確,並且該錯誤的值可能導致fun()的調用者做錯某事或崩潰或者其他任何事情,有時它會修改r4,但它會以一種相同的值或安全的值進行修改。然後,也許你改變了幾行代碼,現在r4上游是用來保存其他東西,你用軟管,現在你崩潰了。

只要每個函數的每個實現遵循約定,那麼它就全部解決。 (假設該慣例是一個正常的慣例)。