2016-07-17 158 views
0

我知道有rules管理堆棧指針在86的修改:在ARM內聯彙編修改SP

超越RSP的當前地址的所有內存被認爲是揮發性:操作系統,或一個調試器,可在用戶調試會話或中斷處理程序期間覆蓋此內存。因此,在嘗試讀取或寫入堆棧幀的值之前,必須始終設置RSP。

我的問題是,ARM的規則是什麼?我在看this代碼(看下面摘錄),它看起來像違反了x86規則(修改內存,然後更改堆棧指針),但這是ARM的問題嗎?

mov r4, sp 
sub r4, r4, #128 

... 

mov r3, #116 
1: ldr r7, [r2] 
add r2, r2, #4 
str r7, [r4] 
dd r4, r4, #4 
sub r3, r3, #4 
cmp r3, #0 
ne 1b 

sub sp, sp, #128 

我試過Google搜索,但找到一個規範,描述修改嵌入式asm ARM棧是...具有挑戰性。有一些關於ARM編譯器和修改堆棧的文檔,但是gcc的規則看起來不同。

+0

@artlessnoise對不起,是的,它是WIndows(添加標籤)。我剛剛意識到代碼不包含任何'.cfi_'指令。這是否意味着這個例程在某些情況下(以某種方式)在異常期間被「跳過」,或者它崩潰了? gcc文檔在哪裏說這是'未定義'(聽起來很有希望)? –

+0

'.cfi_'類型的東西取決於你的二進制規範(COFF/ELF/DWARF,PE-ARM?等)。 [你應該看看編譯器輸出一些'C'代碼引用堆棧/幀](http://stackoverflow.com/questions/37743620/arm-headers-to-get-proper-call-stacks/ )。當然,OS /調試器將執行堆棧遍歷並需要正確的信息。在彙編器堆棧mod之後處理的信號可能導致崩潰。沒有人可以肯定地知道。 –

回答

1

你稱之爲「規則」有點詳細和具體。但是「規則」適用於幾乎所有使用一個堆棧的所有處理器。

作爲一般規則,首先將你的堆棧指針移動到「分配」你想要的堆棧空間,這就是你如何防止下一件事物被摧毀。然後將其移回解除分配。

在ARM的情況下,可能是您鏈接的代碼。您的手臂中有儲存寄存器,這是體系結構參考手冊中的第一章(在分析或編寫彙編語言之前需要閱讀,尤其是寄存器上的一張圖片)。如圖所示的異常模式都有自己的堆棧指針。所以當例如發生中斷時,使用其他一些堆棧指針來保存狀態,所以你的數據不會被破壞。

用戶和系統共享堆棧指針,但這樣內核等代碼就可以訪問而不會陷入用戶模式。系統不用於例外,所以你的代碼不會停止並切換狀態並且打開堆棧。

現在ARM與任何其他品牌的福特例如。他們製作大卡車小卡車,SUV,小型車,爺爺車等。ARM擁有各種各樣的處理器內核。 cortex-m適用於微控制器和其他狹小空間。它有一個堆棧,當發生異常時,它會爲你保存堆棧狀態,從而破壞你的數據。所以你指出的代碼會很糟糕,因爲你爲什麼要在cortex-m上使用printf?

編譯器可以配置爲使用或不使用第二個堆棧指針,x86世界用於這個想法(sp和bsp),但它不是必需的。爲了使(數據)堆棧有用,需要有堆棧指針和用於引用到堆棧的使用部分的指令,堆棧指針相對尋址。在某些平臺上,您可以訪問堆棧指針並使用另一個寄存器(複製)訪問堆棧幀,從而使堆棧指針可以自由漫遊。不管有沒有,在內聯組件中觸摸一個堆棧指針是一個非常糟糕的想法,你需要很好地瞭解你的工具鏈,這樣的代碼需要不斷的維護,編譯器的每一個新版本或者你編譯代碼的每個新系統你必須手工檢查產生的輸出,以確保你的操作是安全的。如果你要達到這個水平,爲什麼要使用內聯asm並燒掉所有這些工作時間(工作安全?),那麼你會使用asm並且首次使得某些東西安全可靠。如果你只是想爲該函數提供更多的數據,只需創建一個局部變量,它就會改變sp上的減法,done。不需要內聯程序集。如果你有這樣的願望,看看堆棧的結束,使用程序集而不是內聯彙編。如果您想修改過去的堆棧指針或者由於某種原因而快速分配而不使用局部變量,那麼再次使用匯編並將堆棧指針移到必須避免這些數據被破壞的系統上。

除了崩潰的系統,它沒有多大意義,亂堆棧指針內聯彙編。與arm或x86無關或填充空白。

他們在那裏完成的工作是使用內聯彙編在彙編中編寫整個函數。這可能只是他們的構建系統選擇的一種情況,您可以將組件彙編到gnu C編譯器中(如果使用內聯彙編,則必須編寫特定於編譯器的代碼,以便您已知道使用的編譯器)並生成一個對象你可以和C一起工作。他們還有其他的方法可以做到這一點,那就是不那麼醜陋。不幸的是,看到這種解決方案並不罕見。如果運行在not-cortex-m上,那麼這個代碼是安全的,你不能在它的中間添加一個函數調用,因爲你會拋棄你的數據,它們會在調用之前移動堆棧指針,而不是移動就像一個正常的解決方案。將不得不跟蹤作者,詢問「他們爲什麼這樣做」的問題。

+0

我的tldr是這樣的:*如果運行在非皮層-m上,那麼該代碼是安全的。 IOW這是醜陋的,但並不完全違反規範,並且在這裏沒有明顯的崩潰。這不是我所希望的答案。我希望重新編寫這段代碼,但如果我可以將其描述爲「破碎」而不是「醜陋」,那麼通常會更容易些。由於目標操作系統是Windows,我可以使用'不需要幀指針的函數必須在序言中執行所有堆棧更新,並保持堆棧指針不變,直到結束語從https://msdn.microsoft.com/zh-cn -us /庫/ dn736986.aspx#Anchor_8? –

+0

只是將堆棧指針調整移至頂端...完成。在mov r4之後,sp但是在使用r4之前。 –

+1

@DavidWohlferd「紅色區域」似乎是一個更好的理由 - 即內核,調試器等在技術上仍然可以隨意中斷線程,並隨時隨地使用SP下面的兩個單詞。這是一個軟件ABI的原因,而不是架構之一,但它仍然是該代碼可能會出錯的東西。 – Notlikethat

0

ARM沒有這樣的規則。在中斷情況下,CPU(至少Cortex-A/R CPU)不會自動堆疊寄存器,即使對於Cortex-M,也能保證順序。

+0

我不知道我關注。如果這段代碼向堆棧寫入幾十個字節,則中斷,不能將中斷代碼寫入堆棧?如果sp不更新,中斷怎麼能避免覆蓋第一個人做的事情? –

+0

@David當然,中斷代碼寫入_a_堆棧,但不是用戶模式堆棧 - 每個處理器模式都有它自己的存儲區SP。我認爲這個問題_does_存在於Linux上,因爲信號處理程序(它們在相同的用戶模式下運行),但這不是一個架構問題。 FWIW,[這是所有微軟必須說的](https://msdn.microsoft.com/en-us/library/dn736986.aspx#Anchor_8)。 – Notlikethat

+0

cortex-m確實使用棧來保存狀態,這樣你就不必上面的代碼被破壞,內容就會被清除。 –