2013-10-15 47 views
5

我正在編寫代碼以臨時使用我自己的堆棧進行實驗。當我使用文字內聯彙編時,這工作。我將變量位置硬編碼爲ebp的偏移量。不過,我希望我的代碼能夠在不需要硬編碼內存地址的情況下工作,所以我一直在尋找GCC的擴展聯機彙編。我有以下幾點:

volatile intptr_t new_stack_ptr = (intptr_t) MY_STACK_POINTER; 
volatile intptr_t old_stack_ptr = 0; 
asm __volatile__("movl %%esp, %0\n\t" 
     "movl %1, %%esp" 
     : "=r"(old_stack_ptr) /* output */ 
     : "r"(new_stack_ptr) /* input */ 
     ); 

這樣做的關鍵是首先將堆棧指針保存到變量old_stack_ptr中。接下來,堆棧指針(%esp)被我保存在new_stack_ptr中的地址覆蓋。

儘管如此,我發現GCC正在將%esp保存到old_stack_ptr中,但並未用new_stack_ptr替換%esp。在更深入的考察,我發現它實際上擴大了我的組裝和增加它自己的指令,它有以下幾種:

mov -0x14(%ebp),%eax 
mov %esp,%eax 
mov %eax,%esp 
mov %eax,-0x18(%ebp) 

我認爲GCC試圖ESP保存%,因爲我沒有做到這一點明確的聲明爲一個「輸出」操作數...我可能是完全錯誤的...

我真的想用擴展內聯彙編做到這一點,因爲如果不是這樣,似乎我必須「硬編碼」的位置從%ebp偏移到程序集中,我寧願使用像這樣的變量名...尤其是因爲此代碼需要在幾個不同的系統上工作,這似乎都以不同的方式偏移了我的變量,因此使用擴展內聯程序集讓我明白Ÿ說變量的位置......但我不明白爲什麼它正在做額外的東西,而不是讓我像以前一樣覆蓋堆棧指針,自從我開始使用擴展裝配以來,它一直在這樣做。

我感謝任何幫助!

+0

不知道這是否有幫助,但'-fomit-frame-pointer'(用'-O1'啓用)會消除「%ebp」的問題。 – DaoWen

+0

額外的東西可能在那裏,因爲你正在做一個調試(沒有優化)構建和GCC默認情況下它捕捉潛在的錯誤。搜索「GCC Stack Frame Checks」查看GCC提供的選項。 – Skizz

回答

8

好吧,所以問題是海灣合作委員會是分配輸入和輸出到同一個寄存器eax。你想告訴gcc你在使用輸入之前會打破輸出,也就是說。 「earlyclobber」。

asm __volatile__("movl %%esp, %0\n\t" 
     "movl %1, %%esp" 
     : "=&r"(old_stack_ptr) /* output */ 
     : "r"(new_stack_ptr) /* input */ 
     ); 

請注意&符號的輸出。這應該修復你的代碼。

更新:或者,你可以強制輸入和輸出是相同的註冊和使用xchg,像這樣:

asm __volatile__("xchg %%esp, %0\n\t" 
     : "=r"(old_stack_ptr) /* output */ 
     : "0"(new_stack_ptr) /* input */ 
     ); 

注意的"0",說:「要把它放到同一個寄存器作爲參數0「。

+0

謝謝soooo多!我以前從來沒有聽說過早期的破壞。優秀的答案。對此,我真的非常感激。這解決了它。 – Chad

+1

我想或者你可以使用'xchg',然後強制輸入和輸出在同一個寄存器中。 – Jester