2010-12-20 73 views
5

每當我在優化啓用時編譯C或C++代碼時,d GCC會將函數與IA-32上的16字節邊界對齊。如果函數少於16個字節,GCC墊它與一些字節,這似乎都不是隨機的,在所有:GCC函數填充值

19: c3      ret 
1a: 8d b6 00 00 00 00  lea 0x0(%esi),%esi 

它似乎總是要麼8d b6 00 00 00 00 ...8d 74 26 00

函數的填充字節有什麼意義嗎?

+0

我的理解是/是GCC使用0作爲函數對齊填充,但是因爲我不能指出你可能不是非常有用的源代碼...... – William 2010-12-20 02:05:32

回答

6

填充由彙編程序創建,而不是由gcc創建。它只看到一個.align指令(或等效指令),並不知道要填充的空間是在函數內部(例如循環對齊)還是在函數之間,所以它必須插入某種類型的內存。現代x86彙編器使用最大可能的NOP操作碼,如果填充用於循環對齊,則意圖花費盡可能少的週期。就個人而言,我非常懷疑對齊作爲一種優化技術。我從來沒有看到過它有什麼幫助,而且它可以通過極大地增加總代碼大小(和緩存利用率)而受到傷害。如果您使用-Os優化級別,則默認關閉,所以沒有什麼可擔心的。否則,您可以使用正確的-f選項禁用所有對齊。

+0

看起來這是正確的。 '-S'輸出沒有填充空操作。 – 2010-12-20 02:46:35

2

指令lea 0x0(%esi),%esi只是加載在%esi價值爲%esi - 這是無操作(或NOP),這意味着,如果是執行它不會有任何效果。

這恰好是一個單指令,6字節的NOP。 8d 74 26 00只是同一指令的一個4字節編碼。

+0

但它不是一個可到達的指令(在'ret之後) , 是嗎? – 2010-12-20 02:08:19

+0

@亞歷B:不可直接到達(但可以跳到)。通常有理由在函數中產生可執行的填充,所以很可能GCC只是重用相同的填充算法來完成函數的結尾。 – caf 2010-12-20 02:15:12

1

彙編程序首先看到一個.align指令。由於它不知道這個地址是否在函數體內,它不能輸出NULL 0x00字節,並且必須生成NOP0x90)。

然而:

lea esi,[esi+0x0] ; does nothing, psuedocode: ESI = ESI + 0 

執行更少的時鐘週期比

nop 
nop 
nop 
nop 
nop 
nop 

如果此代碼碰巧落在函數體內(例如,循環對齊)時,lea版本將是非常更快,而仍「無所事事」。