switch语句跳转表
switch语句可以根据一个整数索引值进行多重分支。
GCC根据case的数量和case值的稀疏程度来翻译switch语句,当case情况比较多(例如4个以上),并且值的范围跨度比较小时,就会使用跳转表。
跳转表是一个数组,表项i是一个代码段的地址,这个代码段实现当开关索引值等于i时程序应该采取的动作。
void switcher(long a, long b, long *dest)
{
long val;
switch (a)
{
case 5:
val = a + b + 5;
case 0:
val = a + b;
break;
case 2:
case 7:
val = a * 2 + b * 7;
case 4:
val = a + b + 4;
break;
default:
val = 0xFF;
}
*dest = val;
}
switcher:
cmpq $7, %rdi
ja .L6
leaq .L4(%rip), %rcx
movslq (%rcx,%rdi,4), %rax
addq %rcx, %rax
jmp *%rax
jmp指令的操作数有前缀*,表明这是一个间接跳转,操作数在%rax中,而%rax的值由索引%rdi确定。
.L4:
.long .L3-.L4
.long .L6-.L4
.long .L5-.L4
.long .L6-.L4
.long .L5-.L4
.long .L3-.L4
.long .L6-.L4
.long .L5-.L4
.text
.L3:
addq %rsi, %rdi
.L2:
movq %rdi, (%rdx)
ret
.L5:
leaq 4(%rdi,%rsi), %rdi
jmp .L2
.L6:
movl $255, %edi
jmp .L2
这就是跳转表。
可以观察到,跳转表对重复情况就是简单地对表项使用同样的标号(例如2号以及7号都是L5),而对于缺失的情况就使用默认的标号(例如1号,3号以及6号都是L6)。