为什么GCC垫功能与NOP指令?

我一直用C很短的一段时间,最近开始进入ASM。 当我编译的程序:

int main(void) { int a = 0; a += 1; return 0; }

该objdump的反汇编有代码,但沤后的NOP:

... 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 ...

从我了解到的NOP什么都不做,自从退役后甚至不被执行。

我的问题是:何必呢? 无法ELF(Linux的x86)的任何大小的.text段(+主)工作?

我会很感激任何帮助,只是想学习。

--------------解决方案-------------

首先, gcc并不总是这样做。 填充由控制-falign-functions ,这是由自动开启-O2-O3

-falign-functions
-falign-functions=n

对齐功能开始到电源的两大于下一n ,最多跳过n个字节。 例如, -falign-functions=32对齐功能到下一个32字节边界,但是-falign-functions=24会对准下一个32字节边界仅当此可以通过跳过23个字节或更少进行。

-fno-align-functions-falign-functions=1是等价的,表明函数不会被对齐。

当n为二的幂有些汇编只支持这个标志; 在这种情况下,上舍入。

如果没有指定n,或者为零,使用由机器决定的默认设置。

在级别-O2,-O3启用。

有可能是这样做的原因是多方面的,但在x86主要原因之一可能是这样的:

大多数处理器取在对准16字节或32字节的块的指令。 它可以是有利的通过16,以尽量减少在代码的16字节边界的数目来对齐临界循环条目和子程序条目。 此外,请确保有一个关键循环条目或子程序入口后的最初几个指令没有16字节边界。

(由瓦格纳雾“汇编语言优化子程序”援引)。

编辑:下面是一个说明填充 ​​的例子:

// 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

这样做是由8,16或32字节边界对齐的下一个功能。

从A.Fog“汇编语言子程序优化”:

代码11.5对齐

大多数微处理器取在对准16字节或32字节的块码。 如果importantsubroutine条目或跳转标签恰好是附近的一个16字节的块结束,然后获取代码块的时候themicroprocessor只会代码了一些有用的字节。 Itmay有过取接下来的16字节,才可以thelabel解码后的第一个指令。 这可以通过由16对准重要子程序条目和环条目来避免。

[...]

对准一个子程序入口是把简单许多NOP的需要之前thesubroutine进入8,16,32或64整除做出的地址,根据需要。

至于我记得,指令流水线CPU和不同的CPU块(装载机,解码器和等)的过程后面的指令。 当RET被执行的指令,几下一指令已经装入CPU流水线。 这是一个猜测,但你可以从这里开始挖,如果你发现(也许的具体数目NOP S中的安全,分享你的发现吧。

分类:C# 时间:2015-03-14 人气:0
本文关键词: 装配,GCC
分享到:

相关文章

Copyright (C) 55228885.com, All Rights Reserved.

55228885 版权所有 京ICP备15002868号

processed in 0.851 (s). 10 q(s)