【问题标题】:WRMSR on x86_64 64bit RCX register value is wrongly setx86_64 64bit RCX 寄存器值上的 WRMSR 设置错误
【发布时间】:2014-02-24 06:51:03
【问题描述】:

我想写入PMC1寄存器,所以我想设置RCX为188。

最后附上我用来使用 WRMSR 指令的代码。问题是我将 eax 和 ecx 值(64 位)传递到宏中,但 %rcx 寄存器始终设置为 eax 值。

#define RTXEN_WRITE_MSR(eax, ecx)     __asm__ __volatile__(\
                                "movq %0, %%rax\n\t"\
                                "xorq %%rdx, %%rdx\n\t"\
                                "xorq %%rcx, %%rcx\n\t"\
                                "movq %1, %%rcx\n\t"\
                                "wrmsr"\
                                :\
                                :"r" (eax), "r" (ecx)\
                                :\
                                )


uint64_t eax = 0x14f2e
uint64_t edx = 0x188

printk("eax:%#018lx, edx:%#018lx\n", eax, edx);
RTXEN_WRITE_MSR(eax, ecx);

当 RTXEN_WRITE_MSR(eax, ecx) 执行时,内核崩溃! 注册信息如下:

(XEN) CPU:    1
(XEN) RIP:    e008:[<ffff82c4c02166b1>] setread_perf_counter+0x251/0x4c0
(XEN) RFLAGS: 0000000000010046   CONTEXT: hypervisor
(XEN) rax: 0000000000014f2e   rbx: ffff8308558f7718   **rcx: 0000000000014f2e**
(XEN) rdx: 0000000000000000   rsi: 000000000000000a   rdi: ffff82c4c0270640
(XEN) rbp: 0000000000000001   rsp: ffff83086bec7cd8   r8:  0000000000000004
(XEN) r9:  0000000000000004   r10: 0000000000000004   r11: 0000000000000400
(XEN) r12: 0000000000014f2e   r13: 0000000200000000   r14: ffff83086bec7dd8
(XEN) r15: 00000000000000fb   cr0: 000000008005003b   cr4: 00000000001426f0
(XEN) cr3: 000000008ce6a000   cr2: ffff880115ca32a0
(XEN) ds: 002b   es: 002b   fs: 0000   gs: 0000   ss: e010   cs: e008

谁能帮我看看我的代码有什么问题?

【问题讨论】:

    标签: c assembly msr


    【解决方案1】:

    您知道您可以让您的编译器立即在正确的寄存器中传递您的参数吗?

    asm volatile (
        "wrmsr"
        :
        : "a" ((uint32_t)eax)
        , "c" ((uint32_t)ecx)
        , "d" ((uint32_t)0)
    );
    

    uint32_t 的类型转换确保编译器将使用 32 位寄存器变体(eaxecxedx)。

    您可以在此处找到英特尔寄存器的约束修饰符:http://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html#Machine-Constraints

    附带说明:如果您在 asm 中使用寄存器,那么您需要告诉编译器您正在这样做。您需要将您使用的所有寄存器和编译器不知道的所有寄存器放入第三个冒号之后的clobber寄存器列表中。

    【讨论】:

    • 嗨@Sergey L。谢谢你的建议。但我认为我的代码只是将变量放入通用寄存器,然后将值从通用寄存器移动到 %eax、%ecx 等。我不知道为什么它不起作用。顺便说一句,因为我使用的寄存器在 dest。和源,我不需要把它们放到clobber列表中,这会导致编译错误。
    • @MikeXu:但是如果编译器决定将变量“ecx”放入寄存器 rax、rcx 或 rdx 会怎样?那你的逻辑就不行了。我认为您需要将 rax、rdx 和 rcx 放入 clobber 列表中。恕我直言,SergeyL 的解决方案是最干净的。
    • 嗨@AndreasH。你能给我一个链接吗?我遵循手册“mindfruit.co.uk/2012/11/…”。 BTW,我也用了关键字Volatile,不知道为什么编译器会优化它
    • 编译器没有优化。您必须看到,程序集中的 %1 将被替换为寄存器名称(因为您通过了“r”约束)。但是您可能会在执行移动之前丢弃此寄存器(请注意,编译器不知道您正在修改程序集中的某些寄存器)。或者尝试将 ecx 传递为“m”(即内存引用)
    • @MikeXu:关键是,您不知道编译器为 %1 选择了哪个寄存器。它可以是 rax、rdx 或 rcx,您实际上是在程序集中对其进行修改。但是编译器不知道,因为它不解析程序集。
    猜你喜欢
    • 1970-01-01
    • 2013-07-04
    • 1970-01-01
    • 1970-01-01
    • 2018-06-16
    • 1970-01-01
    • 2012-08-26
    • 2014-10-16
    相关资源
    最近更新 更多