网站公告列表

  没有公告

加入收藏
设为首页
在线投稿

您现在的位置: IT知识网 >> IT知识 >> 网络安全 >> 编程技术 >> 文章正文

 

  gcc常用的编译选项对代码的影响           

gcc常用的编译选项对代码的影响
作者:佚名 文章来源:不详 点击数: 更新时间:2006-12-4 16:10:26
★ 前言

本文讨论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
0x80483d8 <hi+8>: call 0x8048308 <printf>
0x80483dd <hi+13>:add$0x4,%esp
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不平衡呢?
来看看部分的内存映象
 (内存高址)
  +--------+
  |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]的地址)
 0xbffffb84 +--------+
  |00000001| argc的值
 0xbffffb80 +--------+
  |400309cb|main的返回地址
 0xbffffb7c +--------+
  |080483e5| hi()的返回地址
 0xbffffb78 +--------+
  |08048450|"hi"字符串的地址
 0xbffffb74 +--------+
  | ...... |
 (内存低址)
没有保存上层执行环境的ebp.


★ -fomit-frame-pointer && -O2

-fomit-frame-pointer编译选项去掉了
push %ebp
mov%esp,%ebp//这两条指令安装
leave//这条指令恢复
-O2编译选项去掉了
add$0x4,%esp

两个加起来会不会这四条指令一起去掉,从而使stack不平衡呢?

[alert7@redhat62 alert7]$ gcc -fomit-frame-pointer -O2 -o test test.c
[alert7@redhat62 alert7]$ wc -c test
  11741 test
[alert7@redhat62 alert7]$ gdb -q test
(gdb) disass main
Dump of assembler code for function main:
0x80483d8 <main>: call 0x80483c8 <hi>
0x80483dd <main+5>: xor%eax,%eax
0x80483df <main+7>: ret
End of assembler dump.
(gdb) disass hi
Dump of assembler code for function hi:
0x80483c8 <hi>:push $0x8048430
0x80483cd <hi+5>: call 0x8048308 <printf>
0x80483d2 <hi+10>:add$0x4,%esp
0x80483d5 <hi+13>:ret
0x80483d6 <hi+14>:mov%esi,%esi
End of assembler dump.
来看看部分的内存映象
 (内存高址)
  +--------+
  |bffffbc4| argv的地址(即argv[0]的地址)
 0xbffffb84 +--------+
  |00000001| argc的值
 0xbffffb80 +--------+
  |400309cb|main的返回地址
 0xbffffb7c +--------+
  |080483dd| hi()的返回地址
 0xbffffb78 +--------+
  |08048430|"hi"字符串的地址
 0xbffffb74 +--------+
  | ...... |
 (内存低址)

此时就没有把add$0x4,%esp优化掉,如果优化掉的话,整个stack就
会变的不平衡,从而会导致程序出错。


★ -fPIC 编译选项

-fPICIfsupported for the target machine, emit position-independent
  code, suitable for dynamic linking,even if branches need large
  displacements.
产生位置无关代码(PIC),一般创建共享库时用到。
在x86上,PIC的代码的符号引用都是通过ebx进行操作的。

[alert7@redhat62 alert7]$ gcc -fPIC -o test test.c
[alert7@redhat62 alert7]$ wc -c test
 

[1] [2] 下一页

文章录入:bolang    责任编辑:bolang 
  • 上一篇文章:

  • 下一篇文章:
  • 【字体: 】【发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口
    最 新 热 门
    相 关 文 章
    高薪直通车:CCNA认证的考
    CCNP路由精华3:在单个区
    Cisco宣布2006年底CCDP认
    新版CCNA 640-801考试IO
    新版CCNA 640-801考试IO
    思科在2004CCBN上展示Li
    从民工到CCNA-献给想考
    思科在2004CCBN上展示Li
    CCIP认证系列教程之MPLS
    CCNA手册:交换机(Switch
     
      网友评论:(只显示最新10条。评论内容只代表网友观点,与本站立场无关!)
    Copyright© ITZS.NET All Rights Reserved
    QQ:272895858   ICP备案编号:吉ICP备07000044号
    IT知识网 站长:博浪