如何在linux上使用gcc汇编在x86-64中设置控制寄存器0(cr0)位

时间:2010-10-18 20:06:59

标签: linux gcc x86-64 inline-assembly

我使用以下代码将cr0位设置为禁用缓存。 当我编译这个

#include <stdio.h>

int main()
{
        __asm__("pushl  %eax\n\t"
                "mov    %cr0,%eax;\n\t"
                "orl    $(1 << 30),%eax;\n\t"
                "mov    %eax,%cr0;\n\t"
                "wbinvd\n\t"
                "popl   %eax"
);

        return 0;
}

我收到错误,说操作数对mov无效。

任何人都可以指点我做一个好的gcc x86-64指南来做这些事吗? 以上代码究竟出了什么问题?

5 个答案:

答案 0 :(得分:8)

好的,最后我写了以下内核模块。我不确定它是否正确,因为我没有观察到禁用缓存时应该伴随的急剧减速。但是这会正确编译和插入。

任何指针都会有所帮助。

谢谢!

#include <linux/init.h>
#include <linux/module.h>
MODULE_LICENSE("Dual BSD/GPL");
static int hello_init(void)
{
        printk(KERN_ALERT "Hello, world\n");
        __asm__("push   %rax\n\t"
                "mov    %cr0,%rax;\n\t"
                "or     $(1 << 30),%rax;\n\t"
                "mov    %rax,%cr0;\n\t"
                "wbinvd\n\t"
                "pop    %rax"
);
        return 0;
}
static void hello_exit(void)
{
        printk(KERN_ALERT "Goodbye, cruel world\n");
        __asm__("push   %rax\n\t"
                "mov    %cr0,%rax;\n\t"
                "and     $~(1 << 30),%rax;\n\t"
                "mov    %rax,%cr0;\n\t"
                "wbinvd\n\t"
                "pop    %rax"
);
}
module_init(hello_init);
module_exit(hello_exit);

答案 1 :(得分:4)

我认为你没有看到“急剧放缓”,因为你有多个核心,对吧? 我做了一些实验,在我看来,在%cr0中设置CD只会影响运行该模块的处理器。

确保在要禁用缓存的所有核心上运行代码。例如,您可以创建一个/ proc / cachedisable文件,其中读取会触发您的代码。然后使用

taskset -c cpu_number cat /proc/cachedisable

禁用CPU cpu_number上的缓存。使用/ proc / cacheenable执行相同操作,即可获得所需的一切。这对我有用,没有必要改变MTRR,这是非常复杂的。如果您有多个处理器,那么您只能在其中一个处理器上禁用缓存并在此cpu上执行实验。然后系统的其余部分仍然可用。

答案 2 :(得分:3)

您不能从用户代码执行此类操作,甚至以root身份运行也是用户代码。

您需要将其转换为驱动程序模块并使用insmod加载它。

答案 3 :(得分:1)

试试这个:     “mov %% cr0,%% eax \ n”

一个简单的%被解释为用户参数(我认为)。

您应该阅读this

答案 4 :(得分:0)

代码在32位x86位上编译好,而不是在x86-64上 - 这是在Mac OS X上使用gcc 4.2.1:

$ gcc -Wall -m32 cr0.c -o cr0
$

没有错误或警告。

$ gcc -Wall -m64 cr0.c -o cr0
/var/folders/.../cce0FYAB.s:9:suffix or operands invalid for `push'
/var/folders/.../cce0FYAB.s:10:suffix or operands invalid for `mov'
/var/folders/.../cce0FYAB.s:12:suffix or operands invalid for `mov'
/var/folders/.../cce0FYAB.s:14:suffix or operands invalid for `pop'
$

所以我猜这里有更深层次的问题,而不仅仅是x6-64上asm的mov %eax,%cr0指令。

看看x86-64 ISA似乎你可能需要x86-64这样的东西:

#include <stdio.h>

int main()
{
        __asm__("pushq  %rax\n\t"
                "movq    %cr0,%rax\n\t"
                "orl    $(1 << 30),%eax\n\t"
                "movq    %rax,%cr0\n\t"
                "wbinvd\n\t"
                "popq   %rax"
);

        return 0;
}

我不知道这是否有效,但它至少可以编译/组装好:

$ gcc -Wall -m64 cr0.c -o cr0
$