我已经和C一起工作了一段时间,最近才开始进入ASM . 当我编译一个程序时:
int main(void)
{
int a = 0;
a += 1;
return 0;
}
objdump反汇编有代码,但在ret之后nops:
...
08048394 <main>:
8048394: 55 push %ebp
8048395: 89 e5 mov %esp,%ebp
8048397: 83 ec 10 sub $0x10,%esp
804839a: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%ebp)
80483a1: 83 45 fc 01 addl $0x1,-0x4(%ebp)
80483a5: b8 00 00 00 00 mov $0x0,%eax
80483aa: c9 leave
80483ab: c3 ret
80483ac: 90 nop
80483ad: 90 nop
80483ae: 90 nop
80483af: 90 nop
...
从我学到的东西,什么都不做,因为ret之后甚至都不会被执行 .
我的问题是:为什么要这么麻烦? ELF(linux-x86)无法使用任何大小的.text段(主)吗?
我很感激任何帮助,只是想学习 .
3 回答
这样做是为了将下一个函数与8,16或32字节边界对齐 .
来自A.Fog的“用汇编语言优化子程序”:
首先,
gcc
并不总是如此 . 填充由-falign-functions控制,由-O2
和-O3
自动打开:执行此操作可能有多种原因,但x86上的主要原因可能是:
(引自Agner Fog的“用汇编语言优化子程序” . )
edit: 这是一个演示填充的示例:
使用gcc 4.4.5使用默认设置编译时,我得到:
指定
-falign-functions
给出:据我所知,指令在cpu中流水线化,不同的cpu块(加载器,解码器等)处理后续指令 . 当正在执行
RET
指令时,很少有下一条指令已加载到cpu管道中 . 这是一个猜测,但你可以开始挖掘这里,如果你发现(也许NOP
的具体数量是安全的,请分享你的发现 .