免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 4803 | 回复: 10
打印 上一主题 下一主题

[虚拟化] VMLAUNCH指令内联汇编,请高手们帮忙解释下 [复制链接]

论坛徽章:
15
射手座
日期:2014-02-26 13:45:082015年迎新春徽章
日期:2015-03-04 09:54:452015年辞旧岁徽章
日期:2015-03-03 16:54:15羊年新春福章
日期:2015-02-26 08:47:552015年亚洲杯之卡塔尔
日期:2015-02-03 08:33:45射手座
日期:2014-12-31 08:36:51水瓶座
日期:2014-06-04 08:33:52天蝎座
日期:2014-05-14 14:30:41天秤座
日期:2014-04-21 08:37:08处女座
日期:2014-04-18 16:57:05戌狗
日期:2014-04-04 12:21:33技术图书徽章
日期:2014-03-25 09:00:29
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2014-08-26 19:26 |只看该作者 |倒序浏览
本帖最后由 humjb_1983 于 2014-08-26 19:28 编辑

VMLAUNCH指令执行的内联汇编有些地方不太明白,请高手们帮忙解释下如下格式Operand的具体含义:
                 %c[host_rsp](%0)

个人理解,[host_rsp]是在后面输入部分定义的tag,即(offsetof(struct vcpu_vmx, host_rsp)),%0是输入部分第一个参数即vmx,
这里的“%c”就不是很好理解了,个人暂时理解为如下意思:
%C[tag] adds 2 to a register number, or 4 to an address constant, or substitutes #hlo() for an integer constant.
如果以[host_rsp](%0)作为整体来看的话,那就是vmx中host_rsp成员的地址加上4;
或者单独看[host_rsp]的话,就是host_rsp相对于vmx的偏移量,中的第5、6字节(应该是0,这个显然不对~~)

请大侠帮忙解释下,这里%c的作用,如果我的理解是对的话,那么为什么要“加上4”?

谢谢!

arch/x86/kvm/vmx.c:
        asm(
                /* Store host registers */
                "push %%" _ASM_DX "; push %%" _ASM_BP ";"
                "push %%" _ASM_CX " \n\t" /* placeholder for guest rcx */
                "push %%" _ASM_CX " \n\t"
                "cmp %%" _ASM_SP ", %c[host_rsp](%0) \n\t"
                "je 1f \n\t"
                "mov %%" _ASM_SP ", %c[host_rsp](%0) \n\t"
                __ex(ASM_VMX_VMWRITE_RSP_RDX) "\n\t"
                "1: \n\t"
                /* Reload cr2 if changed */
                "mov %c[cr2](%0), %%" _ASM_AX " \n\t"
                "mov %%cr2, %%" _ASM_DX " \n\t"
                "cmp %%" _ASM_AX ", %%" _ASM_DX " \n\t"
                "je 2f \n\t"
                "mov %%" _ASM_AX", %%cr2 \n\t"
                "2: \n\t"
                /* Check if vmlaunch of vmresume is needed */
                "cmpl $0, %c[launched](%0) \n\t"
                /* Load guest registers.  Don't clobber flags. */
                "mov %c[rax](%0), %%" _ASM_AX " \n\t"
                "mov %c[rbx](%0), %%" _ASM_BX " \n\t"
                "mov %c[rdx](%0), %%" _ASM_DX " \n\t"
                "mov %c[rsi](%0), %%" _ASM_SI " \n\t"
                "mov %c[rdi](%0), %%" _ASM_DI " \n\t"
                "mov %c[rbp](%0), %%" _ASM_BP " \n\t"
#ifdef CONFIG_X86_64
                "mov %c[r8](%0),  %%r8  \n\t"
                "mov %c[r9](%0),  %%r9  \n\t"
                "mov %c[r10](%0), %%r10 \n\t"
                "mov %c[r11](%0), %%r11 \n\t"
                "mov %c[r12](%0), %%r12 \n\t"
                "mov %c[r13](%0), %%r13 \n\t"
                "mov %c[r14](%0), %%r14 \n\t"
                "mov %c[r15](%0), %%r15 \n\t"
#endif
                "mov %c[rcx](%0), %%" _ASM_CX " \n\t" /* kills %0 (ecx) */

                /* Enter guest mode */
                "jne 1f \n\t"
                /* 执行VMLAUNCH指令,进入Guest模式*/
                __ex(ASM_VMX_VMLAUNCH) "\n\t"
                "jmp 2f \n\t"
                /* 执行VMRESUME指令,从Guest模式恢复到root模式*/
                "1: " __ex(ASM_VMX_VMRESUME) "\n\t"
                "2: "
                /* Save guest registers, load host registers, keep flags */
                "mov %0, %c[wordsize](%%" _ASM_SP ") \n\t"
                "pop %0 \n\t"
                "mov %%" _ASM_AX ", %c[rax](%0) \n\t"
                "mov %%" _ASM_BX ", %c[rbx](%0) \n\t"
                __ASM_SIZE(pop) " %c[rcx](%0) \n\t"
                "mov %%" _ASM_DX ", %c[rdx](%0) \n\t"
                "mov %%" _ASM_SI ", %c[rsi](%0) \n\t"
                "mov %%" _ASM_DI ", %c[rdi](%0) \n\t"
                "mov %%" _ASM_BP ", %c[rbp](%0) \n\t"
#ifdef CONFIG_X86_64
                "mov %%r8,  %c[r8](%0) \n\t"
                "mov %%r9,  %c[r9](%0) \n\t"
                "mov %%r10, %c[r10](%0) \n\t"
                "mov %%r11, %c[r11](%0) \n\t"
                "mov %%r12, %c[r12](%0) \n\t"
                "mov %%r13, %c[r13](%0) \n\t"
                "mov %%r14, %c[r14](%0) \n\t"
                "mov %%r15, %c[r15](%0) \n\t"
#endif
                "mov %%cr2, %%" _ASM_AX "   \n\t"
                "mov %%" _ASM_AX ", %c[cr2](%0) \n\t"

                "pop  %%" _ASM_BP "; pop  %%" _ASM_DX " \n\t"
                "setbe %c[fail](%0) \n\t"
                ".pushsection .rodata \n\t"
                ".global vmx_return \n\t"
                "vmx_return: " _ASM_PTR " 2b \n\t"
                ".popsection"
              : : "c"(vmx), "d"((unsigned long)HOST_RSP),
                [launched]"i"(offsetof(struct vcpu_vmx, __launched)),
                [fail]"i"(offsetof(struct vcpu_vmx, fail)),
                        [host_rsp]"i"(offsetof(struct vcpu_vmx, host_rsp)),
                [rax]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_RAX])),
                [rbx]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_RBX])),
                [rcx]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_RCX])),
                [rdx]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_RDX])),
                [rsi]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_RSI])),
                [rdi]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_RDI])),
                [rbp]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_RBP])),
#ifdef CONFIG_X86_64
                [r8]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_R8])),
                [r9]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_R9])),
                [r10]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_R10])),
                [r11]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_R11])),
                [r12]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_R12])),
                [r13]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_R13])),
                [r14]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_R14])),
                [r15]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_R15])),
#endif
                [cr2]"i"(offsetof(struct vcpu_vmx, vcpu.arch.cr2)),
                [wordsize]"i"(sizeof(ulong))
              : "cc", "memory"
#ifdef CONFIG_X86_64
                , "rax", "rbx", "rdi", "rsi"
                , "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
#else
                , "eax", "ebx", "edi", "esi"
#endif
              );

论坛徽章:
9
辰龙
日期:2014-08-18 20:38:42未羊
日期:2014-09-04 08:50:45丑牛
日期:2014-09-06 00:12:55寅虎
日期:2014-12-22 20:50:56摩羯座
日期:2015-01-14 22:28:15巳蛇
日期:2015-01-23 20:39:272015年辞旧岁徽章
日期:2015-03-03 16:54:1515-16赛季CBA联赛之青岛
日期:2016-03-13 23:37:1915-16赛季CBA联赛之深圳
日期:2016-03-29 18:52:38
2 [报告]
发表于 2014-08-26 21:38 |只看该作者
回复 1# humjb_1983

humjb_1983,我也给你搜索了一下,最吻合的就你自己的解释了。我觉得最好的办法就是你把这个.c  gcc -S一下,直接看一下最终生成的汇编,那就一切都开朗了。{:3_189:}


   

论坛徽章:
15
射手座
日期:2014-02-26 13:45:082015年迎新春徽章
日期:2015-03-04 09:54:452015年辞旧岁徽章
日期:2015-03-03 16:54:15羊年新春福章
日期:2015-02-26 08:47:552015年亚洲杯之卡塔尔
日期:2015-02-03 08:33:45射手座
日期:2014-12-31 08:36:51水瓶座
日期:2014-06-04 08:33:52天蝎座
日期:2014-05-14 14:30:41天秤座
日期:2014-04-21 08:37:08处女座
日期:2014-04-18 16:57:05戌狗
日期:2014-04-04 12:21:33技术图书徽章
日期:2014-03-25 09:00:29
3 [报告]
发表于 2014-08-27 08:42 |只看该作者
Tinnal 发表于 2014-08-26 21:38
回复 1# humjb_1983

humjb_1983,我也给你搜索了一下,最吻合的就你自己的解释了。我觉得最好的办法就是 ...

Tinnal兄费心了,感谢~,我抽空试试。。。

论坛徽章:
15
射手座
日期:2014-02-26 13:45:082015年迎新春徽章
日期:2015-03-04 09:54:452015年辞旧岁徽章
日期:2015-03-03 16:54:15羊年新春福章
日期:2015-02-26 08:47:552015年亚洲杯之卡塔尔
日期:2015-02-03 08:33:45射手座
日期:2014-12-31 08:36:51水瓶座
日期:2014-06-04 08:33:52天蝎座
日期:2014-05-14 14:30:41天秤座
日期:2014-04-21 08:37:08处女座
日期:2014-04-18 16:57:05戌狗
日期:2014-04-04 12:21:33技术图书徽章
日期:2014-03-25 09:00:29
4 [报告]
发表于 2014-08-27 10:15 |只看该作者
Tinnal 发表于 2014-08-26 21:38
回复 1# humjb_1983

humjb_1983,我也给你搜索了一下,最吻合的就你自己的解释了。我觉得最好的办法就是 ...

实验效果跟网上的说法不太一样,很不解:
代码:
#define LONGVAL 0x12345678l
int main()
{
    long a,b;
    asm("mov %A2, %A0 \n\t"
        "mov %B2, %B0 \n\t"
        "mov %A2, %A1 \n\t"
        "mov %B2, %B1 \n\t"
        : "=r"((long)a),"=m"((long)b)
        : "i"((long)LONGVAL) );
}
汇编过后(内联汇编部分):
        mov *$305419896, *%rax //305419896=0x12345678l
        mov b, b
        mov *$305419896, *-16(%rbp)
        mov b, b

实际并不像网上说的一样,一起看看~

参考来源:
http://mspgcc.sourceforge.net/manual/c1308.html

估计是因为硬件平台的差异,这样的话%c的含义就找不到出处了。。。。

我的简化测试代码:
int main()
{
asm(
        "cmp %%eax, %c[host_rsp] \n\t"
        ::[host_rsp]"i"(286331153) :
}
汇编过后(内联汇编部分):
        cmp %eax, 286331153

看起来%c好像没起任何作用~

论坛徽章:
9
辰龙
日期:2014-08-18 20:38:42未羊
日期:2014-09-04 08:50:45丑牛
日期:2014-09-06 00:12:55寅虎
日期:2014-12-22 20:50:56摩羯座
日期:2015-01-14 22:28:15巳蛇
日期:2015-01-23 20:39:272015年辞旧岁徽章
日期:2015-03-03 16:54:1515-16赛季CBA联赛之青岛
日期:2016-03-13 23:37:1915-16赛季CBA联赛之深圳
日期:2016-03-29 18:52:38
5 [报告]
发表于 2014-08-27 11:24 |只看该作者
回复 4# humjb_1983

尝试在stackoverflow上发个帖吧。那边大牛多,我上次想注册注册不上。
关于你说和网上文章对不上的问题,应该是体系结构的差异,你看的应该是MSP单片机的GCC编译器。

类似的,下面这个贴提到P选项:
http://stackoverflow.com/questio ... ver-m-in-linux-kern

http://www.cs.virginia.edu/~clc5q/gcc-inline-asm.pdf
的4.11 Output substitutions提到了更多这类用法。

GCC手册提到相关于东西,但和你的不完全一样。
https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html
请看里头的6.42.2.3 Output Operands节,对应用X86的阔展,如下:
https://gcc.gnu.org/onlinedocs/g ... 386Operandmodifiers


   

论坛徽章:
9
辰龙
日期:2014-08-18 20:38:42未羊
日期:2014-09-04 08:50:45丑牛
日期:2014-09-06 00:12:55寅虎
日期:2014-12-22 20:50:56摩羯座
日期:2015-01-14 22:28:15巳蛇
日期:2015-01-23 20:39:272015年辞旧岁徽章
日期:2015-03-03 16:54:1515-16赛季CBA联赛之青岛
日期:2016-03-13 23:37:1915-16赛季CBA联赛之深圳
日期:2016-03-29 18:52:38
6 [报告]
发表于 2014-08-27 11:43 |只看该作者
回复 5# Tinnal

https://gcc.gnu.org/onlinedocs/g ... 386Operandmodifiers
这个说是应该是对的。
以下面的代码片段为列:
     int main()
     {
        int iInt = 1;
     
     top:
     
        asm volatile goto ("some assembler instructions here"
        : /* No outputs. */
        : "q" (iInt), "X" (sizeof(unsigned char) + 1)
        : /* No clobbers. */
        : top);
     }

没有带i386 Operand modifiers,则:
Operand        masm=att            masm=intel
%1                     $2                 2

如果带上i386 Operand modifiers,则
Operand        masm=att            masm=intel
%c1                     2                          2


c的功能为:Require a constant operand and print the constant expression with no punctuation. 说白了,就是永远不要在常量前面加$符。


   

论坛徽章:
0
7 [报告]
发表于 2014-08-27 11:50 |只看该作者
回复 4# humjb_1983


    %c用来表示使用立即数替换,但不使用立即数的语法,at&t汇编中表示立即数的语法前面有一个$,而用了%c后,就去掉了这个$。
例如你的例子中
int main()
{
asm(
         "cmp %%eax, %c[host_rsp] \n\t"
         ::[host_rsp]"i"(286331153) :
}
汇编过后(内联汇编部分):
        cmp %eax, 286331153
如果不加%c,生成的汇编就是
        cmp %eax, $286331153

这个%c应该主要是用在间接寻址的情况:
比如内嵌汇编:asm("lea %1(%2, %3, 1.....
它生成的汇编可能是:lea $-44(%ebx, %eax, 1....
这是语法错误,加上%c之后生成的汇编语法才是正确的:lea -44(%ebx, %ea, 1....

论坛徽章:
15
射手座
日期:2014-02-26 13:45:082015年迎新春徽章
日期:2015-03-04 09:54:452015年辞旧岁徽章
日期:2015-03-03 16:54:15羊年新春福章
日期:2015-02-26 08:47:552015年亚洲杯之卡塔尔
日期:2015-02-03 08:33:45射手座
日期:2014-12-31 08:36:51水瓶座
日期:2014-06-04 08:33:52天蝎座
日期:2014-05-14 14:30:41天秤座
日期:2014-04-21 08:37:08处女座
日期:2014-04-18 16:57:05戌狗
日期:2014-04-04 12:21:33技术图书徽章
日期:2014-03-25 09:00:29
8 [报告]
发表于 2014-08-27 12:38 |只看该作者
lucky12345 发表于 2014-08-27 11:50
回复 4# humjb_1983

非常感谢兄台,了解了,又涨姿势了。。。

论坛徽章:
15
射手座
日期:2014-02-26 13:45:082015年迎新春徽章
日期:2015-03-04 09:54:452015年辞旧岁徽章
日期:2015-03-03 16:54:15羊年新春福章
日期:2015-02-26 08:47:552015年亚洲杯之卡塔尔
日期:2015-02-03 08:33:45射手座
日期:2014-12-31 08:36:51水瓶座
日期:2014-06-04 08:33:52天蝎座
日期:2014-05-14 14:30:41天秤座
日期:2014-04-21 08:37:08处女座
日期:2014-04-18 16:57:05戌狗
日期:2014-04-04 12:21:33技术图书徽章
日期:2014-03-25 09:00:29
9 [报告]
发表于 2014-08-27 12:40 |只看该作者
Tinnal 发表于 2014-08-27 11:43
回复 5# Tinnal

https://gcc.gnu.org/onlinedocs/g ... 386Operandmodifiers

感谢Tinnal兄,兄弟这么用心真是让我很感动啊,{:3_200:} ,很专业、学到不少东西,看来有问题就得问!

论坛徽章:
1
IT运维版块每日发帖之星
日期:2015-12-20 06:20:00
10 [报告]
发表于 2015-09-26 22:33 |只看该作者
楼上的各位,能解释一下那段汇编的后半部分吗?就是栈的变化不太清楚。
开始在vmentry之前,栈是 DX | BP | CX | CX
然后当vmexit后,这两条是什么意思?
                "mov %0, %c[wordsize](%%" _ASM_SP ") \n\t"
                "pop %0 \n\t"

执行vmexit后,%0还是原先vmx 那个变量吗?此时栈是什么样?
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP