2015-06-22 71 views
1

我使用MSVC++ 2012編寫C++,我的代碼是針對x86平臺的。我有一種情況,寫一個函數(除其他外)可以在CALLING函數的堆棧上分配一些內存將是有利的。我不打算在這篇文章中討論這樣做的智慧,而只是考慮技術上的可行性。在調用者堆棧上分配內存

我的實現計劃是將我的函數作爲帶內聯彙編中的自定義prolog代碼的裸函數編寫。在序言中,我將首先確定需要多少內存,然後將返回地址,參數和此指針向下移動到堆棧中。最後我會調整堆棧指針的數量。如果我沒有弄錯,這會在調用函數的堆棧上創建一個區域。

有沒有人在該計劃中看到任何漏洞?

+1

不是真的,不,假設你沒有搞砸彙編程序,並且有足夠的堆棧空間:)我認爲堆棧需要在返回刪除分配空間後的某個時刻修復? –

+1

與['alloca'](http://man7.org/linux/man-pages/man3/alloca.3.html)的功能類似? –

+0

這可能是一個XY問題。 'alloca'就像@CaptainObvlious所說的那樣做了你想要的,但是沒有任何背景,所有的解決方案都可能毫無意義 –

回答

6

一個明顯的缺點是,內聯彙編不支持x64,所以你將在未來限制你的可移植性。

另一個明顯的缺點是,調用函數會期待堆棧指針在某個地方相對於它們的本地,它不再是。我相信編譯器生成的代碼將無法應對這種情況。這種不和諧的一個簡單例子就是生成的代碼不知道要彈出多少堆棧空間。

我觀察到要做的事情的唯一方法就是使用默認參數。你可以做例如

int f(void* p = alloca(55)) { 
} 

技術上,因爲默認參數在調用功能評估,這將分配從調用函數的棧內存。然而,正如你可能會看到這裏的核心問題是計算你需要多少空間。

+0

這很聰明。我從來沒想過這點。它在這種情況下不起作用,因爲正如你所指出的那樣,確定所需的尺寸是一個問題。但我將不得不記住這種技術爲未來。 – Josh

+0

@Josh:明顯的反動是定義一個宏,它有效地傳遞給你的參數。 – Puppy

0

有幾個海報做了很多優點。我會在這裏總結。

我描述的技術將工作,但只有當調用函數是用CDECL調用約定定義的,並且鏈接器開關禁用堆棧幀指針未啓用時。調用函數必須是CDECL,而不是STDCALL或THISCALL,因爲STDCALL和THISCALL不會正確地恢復調用函數的epilog中的堆棧指針,因爲這些約定從當前的ESP中減去而不是恢復原始值。他們會減去錯誤的數量,而不是考慮增加的空間,因此堆棧會被損壞。禁用堆棧幀指針的鏈接器開關不能處於活動狀態,因爲如果它是調用函數,則會將參考參數指定爲ESP的偏移量而不是EBP,因此偏移量將不正確。

除了上述限制之外,使用此技術的重要性將會損失x64的可移植性和對性能優化的不可預測的影響。

鑑於侷限性,我選擇不繼續使用這種技術。