x64汇编学习(12)-- jump table

-- TOC --

C语言天生与汇编就有很直接的对应关系。对于switch语句,编译成汇编后,有可能出现性能很高的jump table代码,这比连续的if..else...if...判断性能高很多。本文就来看看jump table是什么样的。

为什么C语言有do-while循环?我认为就是因为do-while结构几乎与汇编能够直接对应。

下面是测试用C代码:

int main(int argc, char **argv) {
    int a;
    switch(argc){
        case 0:
            a = 101;
            break;
        case 1:
        case 2:
            a = 102;
            break;
        case 3:
            a = 103;
            break;
        case 4:
            a = 104;
            break;
        case 5:
            a = 105;
        case 6:
            a = 106;
            break;
        default:
            a = 1000;
            break;
    }
    return a;
}

-Og编译,不要管warning,得到的汇编如下:

main:
        cmp     edi, 6
        ja      .L2
        mov     edi, edi
        jmp     [QWORD PTR .L4[0+rdi*8]]
.L4:
        .quad   .L8
        .quad   .L9
        .quad   .L9
        .quad   .L6
        .quad   .L5
        .quad   .L3
        .quad   .L3
.L8:
        mov     eax, 101
        ret
.L6:
        mov     eax, 103
        ret
.L5:
        mov     eax, 104
        ret
.L3:
        mov     eax, 106
        ret
.L2:
        mov     eax, 1000
        ret
.L9:
        mov     eax, 102
        ret

.L4就是传说中的jump table!

.L4中有两个.L9入口,对应的是case 1和2。case 5被优化调用,因为Fall Through,因此有两个.L3入口。代码首先用入参与6比较,如果比6大,就直接到.L2,这里对应的是default。然后一个mov,这行mov的效果是,将rdi寄存器的高32位清零。最后,根据rdi寄存器的值,直接跳到jump table中的某个位置,jmp [QWORD PTR .L4[0+rdi*8]],这行汇编有两个[]嵌套,这是Intel语法。

gcc在什么情况下会生成jump table?

《CSAPP》中是这样说的:case的数量要多一点,至少要4个,而且进入case的值的分布,要尽量在一个小范围内。

本文链接:https://cs.pynote.net/hd/asm/202307218/

-- EOF --

-- MORE --