文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>gcc常用编译选项对代码效率的影响(1)

gcc常用编译选项对代码效率的影响(1)

时间:2005-06-22  来源:heack

本文结合例子详细讨论了不同的gcc参数对于代码效率的影响
在这里感谢张量同学(牛人啊)

★ 前言

本文讨论gcc的一些常用编译选项对代码的影响。当然代码变了,
它的内存布局也就会变了,随之exploit也就要做相应的变动。
gcc的编译选项实在太多,本文检了几个最常用的选项。

★ 演示程序

[alert7@redhat62 alert7]$ cat > test.c
#include <stdio.h>
void hi(void)
{
printf("hi");
}

int main(int argc, char *argv[])
{
        hi();
        return 0;
}

★ 一般情况

[alert7@redhat62 alert7]$ gcc -o test test.c
[alert7@redhat62 alert7]$ wc -c test
  11773 test
[alert7@redhat62 alert7]$ gdb -q test
(gdb) disass main
Dump of assembler code for function main:
0x80483e4 <main>:       push   %ebp
0x80483e5 <main+1>:     mov    %esp,%ebp
0x80483e7 <main+3>:     call   0x80483d0 <hi>
0x80483ec <main+8>:     xor    %eax,%eax
0x80483ee <main+10>:    jmp    0x80483f0 <main+12>
0x80483f0 <main+12>:    leave
0x80483f1 <main+13>:    ret
....
End of assembler dump.
(gdb) disass hi
Dump of assembler code for function hi:
0x80483d0 <hi>:        push   %ebp
0x80483d1 <hi+1>:       mov    %esp,%ebp
0x80483d3 <hi+3>:       push   $0x8048450

/*congwu 2005.2.26:这里是压入字符串的地址*/
0x80483d8 <hi+8>:       call   0x8048308 <printf>
0x80483dd <hi+13>:      add    $0x4,%esp

/* congwu 2005.2.26:这里与push   $0x8048450对应,中间栈里经历了许多变化,但这时需要将压入的字符串地址“弹出”,也就是修改栈指针*/
0x80483e0 <hi+16>:      leave
0x80483e1 <hi+17>:      ret
0x80483e2 <hi+18>:      mov    %esi,%esi
End of assembler dump.

来看看部分的内存映象
                   (内存高址)
                              +--------+
                              |bffffbc4| argv的地址(即argv[0]的地址)
                   0xbffffb84 +--------+
                              |00000001| argc的值
                   0xbffffb80 +--------+
                              |400309cb|main的返回地址
                   0xbffffb7c +--------+ <-- 调用main函数前的esp
                              |bffffb98| 调用main函数前的ebp
                   0xbffffb78 +--------+ <-- main函数的ebp
                              |080483ec| hi()的返回地址
                   0xbffffb74 +--------+
                              |bffffb78| 调用hi()前的esp
                   0xbffffb70 +--------+ 
                              |08048450| "hi"的地址
                   0xbffffb6c +--------+ 
                              | ...... |
                   (内存低址)

leave    指令所做的操作相当于MOV ESP,EBP 然后 POP EBP 
ret    指令所做的操作相当于POP EIP

★ -O 编译选项

With `-O', the compiler tries to reduce code size and execution time.
When you specify `-O', the two options `-fthread-jumps' and 
`-fdefer-pop' are turned  on
优化,减少代码大小和执行的时间

[alert7@redhat62 alert7]$ gcc -O -o test test.c
[alert7@redhat62 alert7]$ wc -c test
  11757 test
[alert7@redhat62 alert7]$ gdb -q test
(gdb) disass main
Dump of assembler code for function main:
0x80483d8 <main>:       push   %ebp
0x80483d9 <main+1>:     mov    %esp,%ebp
0x80483db <main+3>:     call   0x80483c8 <hi>
0x80483e0 <main+8>:     xor    %eax,%eax
0x80483e2 <main+10>:    leave
0x80483e3 <main+11>:    ret
0x80483e4 <main+12>:    nop
...
End of assembler dump.
(gdb) disass hi
Dump of assembler code for function hi:
0x80483c8 <hi>:        push   %ebp
0x80483c9 <hi+1>:       mov    %esp,%ebp
0x80483cb <hi+3>:       push   $0x8048440
0x80483d0 <hi+8>:       call   0x8048308 <printf>
0x80483d5 <hi+13>:      leave
0x80483d6 <hi+14>:      ret
0x80483d7 <hi+15>:      nop
End of assembler dump.

在main()中,把一条jmp指令优化掉了,很显然,这条指令是可以不需要的。
在hi()中,把add    $0x4,%esp优化掉了,这会不会使stack不平衡呢?

/这种优化不知道是如何实现的,但可以想象一下,add    $0x4,%esp和leave指令都是对esp的操作,那么连续的两个操作肯定前者是多余的,实际上,这是最最普通的优化了。*/
来看看部分的内存映象
                   (内存高址)
                              +--------+
                              |bffffbc4| argv的地址(即argv[0]的地址)
                   0xbffffb84 +--------+
                              |00000001| argc的值
                   0xbffffb80 +--------+
                              |400309cb|main的返回地址
                   0xbffffb7c +--------+ <-- 调用main函数前的esp
                              |bffffb98| 调用main函数前的ebp
                   0xbffffb78 +--------+ <-- main函数的ebp
                              |080483e0| hi()的返回地址
                   0xbffffb74 +--------+
                              |bffffb78| 调用hi()前的esp
                   0xbffffb70 +--------+ 
                              |08048440| "hi"的地址
                   0xbffffb6c +--------+ 
                              | ...... |
                   (内存低址)

leave    指令所做的操作相当于把MOV ESP,EBP 然后 POP EBP  
看到leave指令操作了没有,先把ebp-->esp,再pop ebp,这样即使
在过程内堆栈的esp,ebp是不平衡的,但只要返回时候碰到leave指令
就会平衡了,所以把add    $0x4,%esp优化掉也是没有问题的。

★ -O2 编译选项

-O2    Optimize  even more.  Nearly all supported optimizations that do 
    not involve a space-speed tradeoff are performed.  Loop unrolling
    and function inlining are not done, for example.  As compared to -O,
        this option increases both compilation time and the performance of
    the generated code.

[alert7@redhat62 alert7]$ gcc -O2 -o test test.c
[alert7@redhat62 alert7]$ wc -c test
  11757 test
[alert7@redhat62 alert7]$ gdb -q test
(gdb) disass main
Dump of assembler code for function main:
0x80483d8 <main>:       push   %ebp
0x80483d9 <main+1>:     mov    %esp,%ebp
0x80483db <main+3>:     call   0x80483c8 <hi>
0x80483e0 <main+8>:     xor    %eax,%eax
0x80483e2 <main+10>:    leave
0x80483e3 <main+11>:    ret
...
0x80483ef <main+23>:    nop
End of assembler dump.
(gdb) disass hi
Dump of assembler code for function hi:
0x80483c8 <hi>:        push   %ebp
0x80483c9 <hi+1>:       mov    %esp,%ebp
0x80483cb <hi+3>:       push   $0x8048440
0x80483d0 <hi+8>:       call   0x8048308 <printf>
0x80483d5 <hi+13>:      leave
0x80483d6 <hi+14>:      ret
0x80483d7 <hi+15>:      nop
End of assembler dump.

由于程序比较简单,再优化也没有好优化的了,所以跟-O出来的一样。

★ -fomit-frame-pointer 编译选项

-fomit-frame-pointer
              Don't keep the frame pointer in a register for functions 
          that don't need one.  This avoids the  instructions to save, 
          set up and restore frame pointers; it also makes an extra 
          register available in many functions.  It also makes 
          debugging impossible on most machines.

忽略帧指针。这样在程序就不需要保存,安装,和恢复ebp了。这样ebp也就是一个
free的register了,在函数中就可以随便使用了。

[alert7@redhat62 alert7]$ gcc -fomit-frame-pointer -o test test.c
[alert7@redhat62 alert7]$ wc -c test
  11773 test
[alert7@redhat62 alert7]$ gdb -q test
(gdb) disass main
Dump of assembler code for function main:
0x80483e0 <main>:       call   0x80483d0 <hi>
0x80483e5 <main+5>:     xor    %eax,%eax
0x80483e7 <main+7>:     jmp    0x80483f0 <main+16>
0x80483e9 <main+9>:     lea    0x0(%esi,1),%esi
0x80483f0 <main+16>:    ret
....
End of assembler dump.
(gdb) disass hi
Dump of assembler code for function hi:
0x80483d0 <hi>:        push   $0x8048450
0x80483d5 <hi+5>:       call   0x8048308 <printf>
0x80483da <hi+10>:      add    $0x4,%esp
0x80483dd <hi+13>:      ret
0x80483de <hi+14>:      mov    %esi,%esi
End of assembler dump.

在main()和hi()中都去掉了以下指令
push   %ebp
mov    %esp,%ebp//这两条指令安装
leave//这条指令恢复
来看看部分的内存映象
                   (内存高址)
                              +--------+
                              |bffffbc4| argv的地址(即argv[0]
相关阅读 更多 +
排行榜 更多 +
胜利女神新的希望小米服手游下载

胜利女神新的希望小米服手游下载

角色扮演 下载
我要当老板伐木工厂游戏下载

我要当老板伐木工厂游戏下载

模拟经营 下载
涡轮螺旋桨最新版下载

涡轮螺旋桨最新版下载

模拟经营 下载