2015-03-03 26 views
5

問題是,在C函數內部我有一個內聯程序集。 喜歡的東西爲內聯彙編創建常量池的正確方法是什麼?

ldr r7, =0xdeadbeef 
    svc 0 

如果文字池沒有明確創建(這種情況下),彙編 創建一個在翻譯單元的結束。通常情況下,這很好,但如果翻譯單元變得非常龐大,這不起作用,因爲 文字池離ldr指令太遠。

因此,我想知道處理問題的最佳方法是什麼。最明顯的方法是 手動創建聯彙編內有文字池:

ldr r7, =0xdeadbeef 
    svc 0 
    b 1f 
    .ltorg 
1: 

或者

ldr r7, 1f 
    svc 0 
    b 2f 
1: 
    .word 0xdeadbeef 
2: 

不幸的是,這將導致次優的代碼,因爲多餘的分支 指令。我不希望彙編程序足夠聰明,爲函數中的常量池找到合適的 位置。我想要做的是 在函數結尾創建一個常量池。有什麼辦法可以告訴 編譯器(gcc)在函數的末尾上創建文字池

PS我結束了使用movw/movt對而不是常量池。雖然,首先, ,movw/movt解決方案的便攜性稍低於文字池,其次,我只是想知道是否可以在內聯程序集 中既可靠又高效地使用常量池。


更新:那麼,什麼是處理問題的最佳方式是什麼?

要強制工具鏈在功能之後創建常量池,可以將該函數放在單獨的代碼段中。它的工作原理是在翻譯單元彙編程序結束時爲每個部分生成單獨的常量池 。

儘管事實上,最好的方法是避免將常量加載到內聯彙編中的寄存器中。最好讓編譯器這樣做。在我來說,我 最終寫了一個類似的代碼來

register int var asm("r7") = 0xdeadbeef; 
asm volatile("svc 0\n" :: "r" (var)); 
+0

可能正確的方法是使用約束,但這就像魔術。 https://gcc.gnu.org/onlinedocs/gcc/Simple-Constraints.html https://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html – auselen 2015-03-03 16:05:15

回答

3

您可以使用-ffunction-sections並按照query on -ffunction-section,使用ld --gc-sections刪除未使用的代碼。

有明顯的分裂文件。

應該起作用的解決方案是使用naked函數和unused註釋,因爲它永遠不會被調用。在這裏放置一個.ltorg,並將這兩個函數放在一個特殊的部分;例如.text.ltorg_kludge。鏈接器腳本應使用.text*,並將相同子部分中的函數放在一起。在某些方面,這就像分割文件,因爲編譯器會嘗試內聯static函數。

如果沒有特殊部分,您可能會依賴源代碼中遇到的編譯器發射函數。但是,我不確定這是否是一種標準或立場。通過在調用層次結構的某些DAG排序中發佈函數,編譯器可以更好地優化。


旁白:movw/movt更有效,因爲高速緩存的效果。它也適用於ARMv6及更高版本的Thumb2代碼。我認爲可移植性不是什麼大問題(因爲內聯彙編程序是不可移植的,您可能更喜歡性能超過),但問題與ARMv4/5用戶有關。


我調查了使用從gcc machine constraintsř約束的,

ř
     在常量池中

然而的項目,一個sample with gcc-4.8給出了一個錯誤不可能的約束。使用替代字母如C也會給出相同的錯誤消息。對source contraints.md的檢查似乎表明R約束是僅限於文檔的功能。不幸的是,這聽起來是爲了解決這個問題。

可能會讓編譯器加載該值,但這可能是次優的,具體取決於彙編程序的編號是inline。例如,

asm(" add %0, %0, %1\n" : "+r" (0xdeadbeef) : "r" (0xbaddeed0)); 
+0

謝謝你的偉大答案!我喜歡你擺弄部分的想法!由於 對於「R」約束,目前在constraints.md中的註釋表示「我們曾經使用 在ARM狀態下對S和R有約束字母,但這些現在的所有用途似乎已被刪除」。 – Nikolai 2015-03-04 10:36:53

相關問題