在本Agner Fog document on calling conventions指出,第5章:
的適用於32位Linux和Mac OS X的Gnu編譯器版本3.x及更高版本使堆棧 的指針在每個函數調用指令處對齊16。
所以,@Anty在他們的答案解釋的那樣,-mpreferred-stack-boundary
的默認值是4,拿到2 對齊。
當檢查棧的對齊情況時,採用明確顯示堆棧指針與不對齊的約定很有用。
我發明我自己的,即採用如下形式@ M + N(例如@ 16 + 4),並且意味着堆棧指針是在和地址Ñ字節比米多少(例如比16的倍數少4個字節,如0x000c,0x001c,0x002c等)。
這很有用,因爲堆棧向下增長,所以如果堆棧指針位於@ 16 + 4,那麼在push ebp
之後位於@ 16 + 8等等(考慮到對齊的模塊化特性)。
在調用vuln
之前,堆棧位於@ 16 + 0(由編譯器強制執行)。
剛剛被調用後,由於返回地址的隱式推送,它是@ 16 + 4。
的序言是:
;Every annotation shows the alignment of the stack
; AFTER the annotated instruction has executed
push %ebp ;@16+8
mov %esp, %ebp
現在,編譯器必須分配0x100字節的,但希望他們能夠在最佳排列分配,只是在做一個sub $0x108,%esp
將導致堆棧指針在@ 16 + 8 + 0x100 = @ 16 + 0x108 === @ 16 + 8。
要使它到達下一個16字節的邊界,需要八個字節,因此需要0x108的大小。
sub $0x108,%esp ;@16+0, Aligned
接下來它需要執行一個調用,在調用指令中堆棧需要重新對齊。
到目前爲止,但推後參數將不再是。
由於strcpy
具有兩個32位的參數,在總共八個字節,則編譯器移動堆棧指針八個字節向下(8 + 8 = 16)尊重對準約束
sub $0x8,%esp ;@16+8
pushl 0x8(%ebp) ;@16+12
lea -0x108(%ebp),%eax
push %eax ;@16+0, Aligned
call 8048300 <[email protected]>
現在,C calling convention任務它是清理堆棧的調用者。
推送了兩個參數,因此需要add $0x8,%esp
。
加上另一個add $0x8,%esp
來平衡上面的sub $0x8,%esp
。
這兩個組合成一個單一的指令。
add $0x10,%esp ;@16+0, Aligned
請注意,這與函數的返回值和類型無關。
這是推算這個數字的論據。
最後序言
leave ;@16+8
ret ;@16+4
你忘了在啓用優化的編譯。否則,編譯器將生成垃圾代碼。請注意,您仍可能會看到更多的內存被分配,這通常是出於對齊的原因。 – Jester