分享
 
 
 

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

王朝other·作者佚名  2006-11-24
窄屏简体版  字體: |||超大  

测试环境 redhat 6.2

★ 前言

本文讨论gcc的一些常用编译选项对代码的影响。当然代码变了,

它的内存布局也就会变了,随之exploit也就要做相应的变动。

gcc的编译选项实在太多,本文检了几个最常用的选项。

★ 演示程序

[alert7@redhat62 alert7]$ cat > test.c

#include

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 : push %ebp

0x80483e5 : mov %esp,%ebp

0x80483e7 : call 0x80483d0

0x80483ec : xor %eax,%eax

0x80483ee : jmp 0x80483f0

0x80483f0 : leave

0x80483f1 : ret

....

End of assembler dump.

(gdb) disass hi

Dump of assembler code for function hi:

0x80483d0 : push %ebp

0x80483d1 : mov %esp,%ebp

0x80483d3 : push $0x8048450

0x80483d8 : call 0x8048308

0x80483dd : add $0x4,%esp

0x80483e0 : leave

0x80483e1 : ret

0x80483e2 : 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 : push %ebp

0x80483d9 : mov %esp,%ebp

0x80483db : call 0x80483c8

0x80483e0 : xor %eax,%eax

0x80483e2 : leave

0x80483e3 : ret

0x80483e4 : nop

...

End of assembler dump.

(gdb) disass hi

Dump of assembler code for function hi:

0x80483c8 : push %ebp

0x80483c9 : mov %esp,%ebp

0x80483cb : push $0x8048440

0x80483d0 : call 0x8048308

0x80483d5 : leave

0x80483d6 : ret

0x80483d7 : 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 : push %ebp

0x80483d9 : mov %esp,%ebp

0x80483db : call 0x80483c8

0x80483e0 : xor %eax,%eax

0x80483e2 : leave

0x80483e3 : ret

...

0x80483ef : nop

End of assembler dump.

(gdb) disass hi

Dump of assembler code for function hi:

0x80483c8 : push %ebp

0x80483c9 : mov %esp,%ebp

0x80483cb : push $0x8048440

0x80483d0 : call 0x8048308

0x80483d5 : leave

0x80483d6 : ret

0x80483d7 : 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 : call 0x80483d0

0x80483e5 : xor %eax,%eax

0x80483e7 : jmp 0x80483f0

0x80483e9 : lea 0x0(%esi,1),%esi

0x80483f0 : ret

....

End of assembler dump.

(gdb) disass hi

Dump of assembler code for function hi:

0x80483d0 : push $0x8048450

0x80483d5 : call 0x8048308

0x80483da : add $0x4,%esp

0x80483dd : ret

0x80483de : 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 : call 0x80483c8

0x80483dd : xor %eax,%eax

0x80483df : ret

End of assembler dump.

(gdb) disass hi

Dump of assembler code for function hi:

0x80483c8 : push $0x8048430

0x80483cd : call 0x8048308

0x80483d2 : add $0x4,%esp

0x80483d5 : ret

0x80483d6 : 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

11805 test

[alert7@redhat62 alert7]$ gdb -q test

(gdb) disass main

Dump of assembler code for function main:

0x80483f8 : push %ebp

0x80483f9 : mov %esp,%ebp

0x80483fb : push %ebx

0x80483fc : call 0x8048401

0x8048401 : pop %ebx//取得该指令的地址

0x8048402 : add $0x1093,%ebx//此时ebx里面存放着是GOT表的地址

0x8048408 : call 0x80483d0

0x804840d : xor %eax,%eax

0x804840f : jmp 0x8048411

0x8048411 : mov 0xfffffffc(%ebp),%ebx

0x8048414 : leave

0x8048415 : ret

...

End of assembler dump.

(gdb) disass hi

Dump of assembler code for function hi:

0x80483d0 : push %ebp

0x80483d1 : mov %esp,%ebp

0x80483d3 : push %ebx

0x80483d4 : call 0x80483d9

0x80483d9 : pop %ebx

0x80483da : add $0x10bb,%ebx

0x80483e0 : lea 0xffffefdc(%ebx),%edx

0x80483e6 : mov %edx,%eax

0x80483e8 : push %eax

0x80483e9 : call 0x8048308

0x80483ee : add $0x4,%esp

0x80483f1 : mov 0xfffffffc(%ebp),%ebx

0x80483f4 : leave

0x80483f5 : ret

0x80483f6 : 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

|401081ec| 保存的ebx

0xbffffb74 +--------+

|0804840d| (存放过call 0x8048401的下一条指令地址)

0xbffffb70 +--------+

|bffffb78| 调用hi()前的esp

0xbffffb6c +--------+

|08049494| GOT表地址

0xbffffb68 +--------+

|08048470|(存放过call 0x80483d9的下一条指令地址)

0xbffffb64 +--------+

| ...... |

(内存低址)

★ -static 编译选项

-static

On systems that support dynamic linking, this prevents

linking with the shared libraries. On other systems,

this option has no effect.

把一些函数都静态的编译到程序中,而无需动态链接了。

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

[alert7@redhat62 alert7]$ wc -c test

962808 test

[alert7@redhat62 alert7]$ gdb -q test

(gdb) disass main

Dump of assembler code for function main:

0x80481b4 : push %ebp

0x80481b5 : mov %esp,%ebp

0x80481b7 : call 0x8048

[1] [2] 下一页

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有