每当我使用优化启用编译C或C ++代码时,d GCC将函数对齐到16字节边界(在IA-32上)。如果函数短于16个字节,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 :(得分:7)
填充由汇编程序创建,而不是由gcc创建。它只是看到.align
指令(或等价物)并且不知道要填充的空间是在函数内部(例如循环对齐)还是在函数之间,因此它必须插入一些NOP
s分类。现代x86汇编程序使用尽可能大的NOP
操作码,如果填充用于循环对齐,则意图花费尽可能少的周期。
就个人而言,我对作为优化技术的对齐持怀疑态度。我从来没有看到它有多大帮助,并且通过极大地增加总代码大小(和缓存利用率)肯定会受到伤害。如果您使用-Os
优化级别,默认情况下它已关闭,因此无需担心。否则,您可以使用正确的-f
选项停用所有路线。
答案 1 :(得分:2)
指令lea 0x0(%esi),%esi
只是将%esi
中的值加载到%esi
- 它是无操作(或NOP
),这意味着如果它被执行它将没有效果。
这恰好是单指令,6字节NOP。 8d 74 26 00
只是同一指令的4字节编码。
答案 2 :(得分:2)
汇编程序首先看到.align
指令。由于它不知道该地址是否在函数体内,因此它不能输出NULL 0x00
个字节,并且必须生成NOP
s(0x90
)。
然而:
lea esi,[esi+0x0] ; does nothing, psuedocode: ESI = ESI + 0
执行的时钟周期比
少nop
nop
nop
nop
nop
nop
如果此代码恰好位于函数体内(例如,循环对齐),lea
版本会更快,但仍然“无所事事。”