jump table
is an array where entry i
is the address of a code segment implementing the action the program should take when the switch index(开关索引值) equals i
.
jump table
是一个数组,这个数组其中一个条目,比如条目i
是一个代码段的地址,这个代码段的代码实现了当switch index
等于i
时程序应该采取的动作。
The code performs an array reference(数组引用)into the jump table using the switch index to determine the target for a jump instruction.
程序代码用
switch index
来执行一个jump table
内的数组引用,确定跳转指令的目标。(e.g.jmp *.L4(,%rdi,8)
)这句话理解起来相当别扭,记得看下面的习题就会豁然开朗。Practice Problem 3.30
The advantage of using a jump table over a long sequence of if-else
statements is that the time taken to perform the switch is independent of the number of switch cases.GCC selects the method of translating a switch
statement based on the number of cases and the sparsity of the case values.Jump tables are used when there are a number of cases(e.g. four or more)and they span a small range of values.
和使用一组很长的
if-else
语句相比,使用jump table
的优势是:程序执行switch
语句所需要的时间与case val:
的数量是相互独立的。GCC根据case val:
的数量跟val
的稀疏程度来翻译switch
语句,当case val:
数量很多(例如4个以上),而且val
值的跨度范围比较小时,就会使用jump table
。
Practice Problem 3.31
For a C function switcher
with the general structure
void switcher(long a, long b, long c, long *dest)
{
long val;
switch (a){
case ____: /*Case A*/
c = ____;
/*fall through*/
case ____: /*Case B*/
val = ___;
break;
case ____: /*Case C*/
case ____: /*Case D*/
val = ___;
break;
case ____: /*Case E*/
val = ___;
break;
default:
val = ___;
}
* dest = val;
}
GCC generates the assembly code and jump table shown in Figure 3.24.
Fill in the missing parts of the C code. Except for the ordering of case labels C and D, there is only one way to fit the different cases into the template.
void switcher(long a, long b, long c, long *dest)
a in %rdi, b in %rsi, c in %rdx, dest in %rcx
switcher:
cmpq %7, %rdi
ja .L2
jmp *.L4(, %rdi, 8)
.section .rodata
.L7:
xorq $15, %rsi
movq %rsi, %rdx
.L3:
leaq 112(%rdx), %rdi
jmp .L6
.L5:
leaq (%rdx, %rsi), %rdi
salq $2, %rdi
jmp .L6
.L2:
movq %rsi, %rdi
.L6:
movq %rdi, (%rcx)
ret
jump table is:
.L4:
.quad .L3
.quad .L2
.quad .L5
.quad .L2
.quad .L6
.quad .L7
.quad .L2
.quad .L5
Answer:
void switcher(long a, long b, long c, long *dest)
a in %rdi, b in %rsi, c in %rdx, d in %rcx
switcher:
cmpq %7, %rdi // a in %rdi => a-7
ja .L2 //a - 7 > 0 jump to the label .L2
jmp *.L4(, %rdi, 8)//array reference jump table
.section .rodata
.L7: //case 5:
xorq $15, %rsi // b = 0000 0000 0000 0000 0000 0000 0000 1111 ^ b
movq %rsi, %rdx // c = b
.L3: //case 0:
leaq 112(%rdx), %rdi // a = 112 + c
jmp .L6 //break;
.L5: //case 2:
leaq (%rdx, %rsi), %rdi // a = c + b
salq $2, %rdi // a = 4 * a
jmp .L6 //break
.L2: //default:
movq %rsi, %rdi // a = b
.L6:
movq %rdi, (%rcx) // *dest = a
ret
so the C code is :
void switcher(long a, long b, long c, long *dest)
{
long val;
switch (a){
case 5: /*Case A*/
c = 15 ^ b;
/*fall through*/
case 0: /*Case B*/
val = 112 + c;
break;
case 2: /*Case C*/
case 7: /*Case D*/
val = 4 * (c + b);
break;
case 4 : /*Case E*/
val = a;
break;
default:
val = b;
}
* dest = val;
}
本题中,变量
val
没有被分配寄存器,val
在逻辑上也是使用%rdi