这几天看KVM代码的时候看到里面有个内联汇编的语法很陌生(下面的代码截取了部分内联汇编片段):

    asm (
        "mov %c[rax](%3), %%rax \n\t"
        "mov %c[rbx](%3), %%rbx \n\t"
        "mov %c[rdx](%3), %%rdx \n\t"
        "mov %c[rsi](%3), %%rsi \n\t"
        "mov %c[rdi](%3), %%rdi \n\t"
          : "=q" (fail)
          : "r"(vcpu->launched), "d"((unsigned long)HOST_RSP),
        "c"(vcpu),
        [rax]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RAX])),
        [rbx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RBX])),
        [rcx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RCX]))
          : "cc", "memory" );

stackoverflow上问了下才知道这是gcc的operand substitution语法,%c后面跟上常量名,就能在内联汇编中使用这个常量了。

以这段代码为例,vcpu是struct kvm_vcpu类型,[rax]“i”(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RAX])这句话把vcpu->regs[VCPU_REGS_RAX]相对于vcpu的偏移赋值给了rax这一常量。接下来回到第一行mov %crax, %%eax,%c[rax]等于前面得到的偏移量,加上vcpu并取值后就是vcpu->regs[VCPU_REGS_RAX]中保存的值了,这个指令会把这个值保存在%rax寄存器中,从而完成了vcpu的rax寄存器恢复工作。