gcc对c语言中的switch的优化 在这里:
http://simohayha.iteye.com/admin/show/146825
接着用上次的代码 switch.c
[code]int switch_eg(int x)
{
int result = x;
switch (x) {
case 100:
result *= 13;
break;
case 102:
result += 10;
/* Fall through */
case 103:
result += 11;
break;
case 104:
case 106:
result *= result;
break;
default:
result = 0;
}
return result;
} [/code]
我们先键入下面的命令:
[code]cc -O2 -c switch.c[/code]
然后新建一个main.c的文件,内容为:
[code]
int main()
{
return switch_eg(102);
}[/code]
然后再键入
[code]cc -O2 -o switch switch.o main.c[/code]
这时会生成一个switch的二进制文件,我们将它反汇编:
[code]objdump -d switch[/code]
会生成很多代码,我这里只把重要的贴出来:
[code]08048350 <switch_eg>:
8048350: 55 push %ebp
8048351: 89 e5 mov %esp,%ebp
8048353: 8b 45 08 mov 0x8(%ebp),%eax
8048356: 8d 50 9c lea -0x64(%eax),%edx
8048359: 83 fa 06 cmp $0x6,%edx
804835c: 76 04 jbe 8048362 <switch_eg+0x12>
804835e: 5d pop %ebp
804835f: 31 c0 xor %eax,%eax
8048361: c3 ret
8048362: ff 24 95 80 84 04 08 jmp *0x8048480(,%edx,4)
8048369: 0f af c0 imul %eax,%eax
804836c: 5d pop %ebp
804836d: 8d 76 00 lea 0x0(%esi),%esi
8048370: c3 ret
8048371: 5d pop %ebp
8048372: b8 72 00 00 00 mov $0x72,%eax
8048377: c3 ret
8048378: 5d pop %ebp
8048379: b8 7b 00 00 00 mov $0x7b,%eax
804837e: 66 90 xchg %ax,%ax
8048380: c3 ret
8048381: 5d pop %ebp
8048382: b8 14 05 00 00 mov $0x514,%eax[/code]
注意看8048362这一行.这行就是进入跳转表的汇编代码,现在我们再进入test程序的调试:
[code]gdb test[/code]
然后键入:
[code]x/6w 0x8048480[/code]
这个命令是打印出从地址0x8048480开始的6个四字节的地址的内容.
会显示出下面的地址:
[code]0x8048480: 0x08048381 0x0804835e 0x08048378 0x08048371
0x8048490: 0x08048369 0x0804835e
[/code]
也就是说0x8048480里面存储的是0x08048381,0x08048384里面存储的是0x0804835e,然后是 0x08048378.....
这样的话,通过8048362那边的计算,就可以直接跳转到某个地址,从而把这个地址所存储的内容提取出来.
可以通过这些地址前去上面的代码里面找:
[code]0x08048381 : case 100
0x0804835e : case 101 (不存在所以跳转到default)
0x08048378 :case 102
0x08048371 :case 103
0x08048369 : 这边要注意,由于104是空语句,因此104 和106的case语句,编译器进行了合并,因此这边 即是 case 104也是case 106.
0x0804835e :case 105 (不存在所以跳转到default)[/code]
通过反汇编和调试信息,对switch的跳转表理解的更清晰了..
http://simohayha.iteye.com/admin/show/146825
接着用上次的代码 switch.c
[code]int switch_eg(int x)
{
int result = x;
switch (x) {
case 100:
result *= 13;
break;
case 102:
result += 10;
/* Fall through */
case 103:
result += 11;
break;
case 104:
case 106:
result *= result;
break;
default:
result = 0;
}
return result;
} [/code]
我们先键入下面的命令:
[code]cc -O2 -c switch.c[/code]
然后新建一个main.c的文件,内容为:
[code]
int main()
{
return switch_eg(102);
}[/code]
然后再键入
[code]cc -O2 -o switch switch.o main.c[/code]
这时会生成一个switch的二进制文件,我们将它反汇编:
[code]objdump -d switch[/code]
会生成很多代码,我这里只把重要的贴出来:
[code]08048350 <switch_eg>:
8048350: 55 push %ebp
8048351: 89 e5 mov %esp,%ebp
8048353: 8b 45 08 mov 0x8(%ebp),%eax
8048356: 8d 50 9c lea -0x64(%eax),%edx
8048359: 83 fa 06 cmp $0x6,%edx
804835c: 76 04 jbe 8048362 <switch_eg+0x12>
804835e: 5d pop %ebp
804835f: 31 c0 xor %eax,%eax
8048361: c3 ret
8048362: ff 24 95 80 84 04 08 jmp *0x8048480(,%edx,4)
8048369: 0f af c0 imul %eax,%eax
804836c: 5d pop %ebp
804836d: 8d 76 00 lea 0x0(%esi),%esi
8048370: c3 ret
8048371: 5d pop %ebp
8048372: b8 72 00 00 00 mov $0x72,%eax
8048377: c3 ret
8048378: 5d pop %ebp
8048379: b8 7b 00 00 00 mov $0x7b,%eax
804837e: 66 90 xchg %ax,%ax
8048380: c3 ret
8048381: 5d pop %ebp
8048382: b8 14 05 00 00 mov $0x514,%eax[/code]
注意看8048362这一行.这行就是进入跳转表的汇编代码,现在我们再进入test程序的调试:
[code]gdb test[/code]
然后键入:
[code]x/6w 0x8048480[/code]
这个命令是打印出从地址0x8048480开始的6个四字节的地址的内容.
会显示出下面的地址:
[code]0x8048480: 0x08048381 0x0804835e 0x08048378 0x08048371
0x8048490: 0x08048369 0x0804835e
[/code]
也就是说0x8048480里面存储的是0x08048381,0x08048384里面存储的是0x0804835e,然后是 0x08048378.....
这样的话,通过8048362那边的计算,就可以直接跳转到某个地址,从而把这个地址所存储的内容提取出来.
可以通过这些地址前去上面的代码里面找:
[code]0x08048381 : case 100
0x0804835e : case 101 (不存在所以跳转到default)
0x08048378 :case 102
0x08048371 :case 103
0x08048369 : 这边要注意,由于104是空语句,因此104 和106的case语句,编译器进行了合并,因此这边 即是 case 104也是case 106.
0x0804835e :case 105 (不存在所以跳转到default)[/code]
通过反汇编和调试信息,对switch的跳转表理解的更清晰了..