关于x86-64下汇编指令switch case部分的疑问

sol*_*ego 2 assembly x86-64 switch-statement

源代码

void switch_eg(long x, long n, long* dest) {
    long val = x;
    switch(n) {
        case 0: 
            val *= 13;
            break;
        case 2:
            val += 10;
        case 3:
            val += 11;
            break;
        case 4:
        case 6:
            val += 11;
            break;
        default: 
            val = 0;
    }
    *dest = val;
} 

Run Code Online (Sandbox Code Playgroud)

对应的汇编代码

.LFB0:
    // x in %rdi, n in %rsi, *dest in %rdx
    cmpq    $6, %rsi
    ja  .L8 // if n > 6, switch->default
    -------------------------
    leaq    .L4(%rip), %rcx
    movslq  (%rcx,%rsi,4), %rax
    addq    %rcx, %rax
    jmp *%rax
    -------------------------
    
    
.L4:
    .long   .L3-.L4 // case 0
    .long   .L8-.L4 // case 1
    .long   .L5-.L4 // case 2
    .long   .L6-.L4 // case 3
    .long   .L7-.L4 // case 4
    .long   .L8-.L4 // case 5
    .long   .L7-.L4 // case 6
.L3:
    leaq    (%rdi,%rdi,2), %rax // %rax = 3 * val
    leaq    (%rdi,%rax,4), %rdi // val = 4 * 3 * val + val = 13val
    jmp .L2 // break
.L5:
    addq    $10, %rdi // val += 10
.L6:
    addq    $11, %rdi // val += 11
.L2:
    movq    %rdi, (%rdx) // *dest = val
    ret // return 
.L7:
    addq    $11, %rdi // val += 11
    jmp .L2 // break
.L8:
    movl    $0, %edi // val = 0
    jmp .L2 // break

Run Code Online (Sandbox Code Playgroud)

谁能解释一下下面这段汇编代码的含义?

    leaq    .L4(%rip), %rcx
    movslq  (%rcx,%rsi,4), %rax
    addq    %rcx, %rax
    jmp *%rax
Run Code Online (Sandbox Code Playgroud)

在我看来,

leaq .L4(%rip), %rcx %rcx 接收跳转表数组的首地址

movslq (%rcx, %rsi, 4), %rax %rax 接收具体的数组元素值,即case对应的操作的地址

但我不知道addq %rcx, %rax这里的意思是什么...

谁能帮助我...谢谢!

Aki*_*nen 5

跳转表实际上不是用来包含跳转地址的,而是包含偏移量的。看 (.L3-.L4)。

当从表中取出偏移量时,需要加上表的基址,位于leaq .L4(%rip), %rcx

该方案使得目标文件可重定位;并且使用符号扩展加载允许使用 32 位整数来解码偏移量以节省空间。