我已经使用C了很短的时间,最近才开始涉足ASM。当我编译程序时:
int main(void)
{
int a = 0;
a += 1;
return 0;
}
objdump反汇编具有代码,但在重新输入后会提示:
...
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
...
从我学到的知识,nops什么都不做,因为ret后甚至不会被执行。
我的问题是:为什么要打扰? ELF(linux-x86)不能与任何大小的.text部分(+ main)一起使用吗?
我将不胜感激,只是尝试学习。
最佳答案
首先,gcc
并不总是这样做。填充由-falign-functions
控制,由-O2
和-O3
自动打开:
-falign-functions
-falign-functions=n
将函数的开头与下一个大于n
的2的幂数对齐,最多跳过n
个字节。例如,
-falign-functions=32
将函数与下一个32字节边界对齐,但是-falign-functions=24
仅将函数与下一个32字节边界对齐
如果可以跳过23个字节或更少的字节来完成此操作。
-fno-align-functions
和-falign-functions=1
是等效的,表示函数将不对齐。
某些汇编程序仅在n为2的幂时才支持此标志。在
那样的话,就四舍五入了。
如果未指定n或为n,则使用与机器有关的默认值。
在-O2,-O3级别启用。
这样做可能有多种原因,但是x86上的主要原因可能是:
大多数处理器以对齐的16字节或32字节块来获取指令。有可能
有利于将关键循环条目和子例程条目对齐16以最小化
代码中16字节边界的数量。或者,请确保关键循环条目或子例程条目之后的前几条指令中没有16字节边界。
(引自“优化汇编中的子例程
语言”,作者:Agner Fog。
编辑:这是一个演示填充的示例:
// align.c
int f(void) { return 0; }
int g(void) { return 0; }
当使用带有默认设置的gcc 4.4.5进行编译时,我得到:
align.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <f>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: b8 00 00 00 00 mov $0x0,%eax
9: c9 leaveq
a: c3 retq
000000000000000b <g>:
b: 55 push %rbp
c: 48 89 e5 mov %rsp,%rbp
f: b8 00 00 00 00 mov $0x0,%eax
14: c9 leaveq
15: c3 retq
指定
-falign-functions
给出:align.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <f>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: b8 00 00 00 00 mov $0x0,%eax
9: c9 leaveq
a: c3 retq
b: eb 03 jmp 10 <g>
d: 90 nop
e: 90 nop
f: 90 nop
0000000000000010 <g>:
10: 55 push %rbp
11: 48 89 e5 mov %rsp,%rbp
14: b8 00 00 00 00 mov $0x0,%eax
19: c9 leaveq
1a: c3 retq
关于c - 为什么GCC垫可与NOP一起使用?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/41033978/