2011-07-28 53 views
2

我在GCC中遇到了一個導致我出現問題的場景。我得到的行爲不是我期望的行爲。爲了總結這種情況,我提出了幾個在硬件模擬器中實現的x86-64新指令。爲了測試這些指令,我正在使用現有的C源代碼並使用十六進制對新指令進行手動編碼。由於這些指令與現有的x86-64寄存器交互,我使用輸入/輸出/ clobber列表來聲明GCC的依賴關係。GCC不在函數調用中保存/恢復保留的寄存器

發生什麼事情是,如果我打電話功能,例如printf,從屬寄存器不會被保存和恢復。

例如

register unsigned long r9 asm ("r9") = 101; 
printf("foo %s\n", "bar"); 
asm volatile (".byte 0x00, 0x00, 0x00, 0x00" : /* no output */ : "q" (r9)); 

101被分配到R9和內聯組件(假在本例中)是依賴於R9。這在沒有printf的情況下可以正確運行,但是當它存在時,GCC不會保存和恢復r9,並且在調用我的自定義指令時存在另一個值。

我想也許是GCC可能有私自改分配到變量 R9,但是當我做這個

asm volatile (".byte %0" : /* no output */ : "q" (r9)); 

,並期待在大會輸出,它確實使用%R9。

我使用的是gcc 4.4.5。你認爲可能會發生什麼?我認爲GCC會一直保存和恢復函數調用的寄存器。有什麼方法可以強制執行嗎?

謝謝!

編輯:順便說一句,我在編譯程序這樣

gcc -static -m64 -mmmx -msse -msse2 -O0 test.c -o test 

回答

7

ABI,第3.2.1節說:

寄存器%RBP,RBX%和%到%R15 R12「屬於」調用函數和 調用的函數需要 保留它們的值。換句話說,一個被調用的函數必須爲這個調用者保存這些寄存器的值。剩餘的寄存器「屬於」被叫 功能。如果一個調用函數想要通過一個 函數調用來保存這樣的寄存器值,它必須將該值保存在其本地堆棧幀中。

所以你不應該期望%rbp,%rbx和%r12到%r15以外的寄存器被函數調用保留。

+0

謝謝你的澄清,我不知道這件事。作爲後續問題,是否有一種簡單的(單行)方法來請求在printf之前保存自定義寄存器集並在printf之後進行恢復? – hayesti

+0

'unsigned long tmp = r9;的printf(...); r9 = tmp;' –

2

GCC不會做出明確的寄存器變量,像這樣被調用方保存。基本上,您使用的這個寄存器符號使變量成爲寄存器的直接別名,假設您希望能夠讀回被調用者在寄存器中的值。如果您使用被保存的寄存器而不是呼叫限制(呼叫者保存)的寄存器,問題就會消失。

+0

謝謝,我甚至不知道有保存呼叫者/被叫者的寄存器! – hayesti