how to set control register 0 (cr0) bits in x86-64 using gcc assembly on linux

£可爱£侵袭症+ 提交于 2020-12-29 04:00:59

问题


I am using the following code to set the cr0 bit to disable cache. When I compile this

#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;
}

I am getting error saying that the operands are invalid for mov.

Can anyone please point me to a good gcc x86-64 guide for doing these kinds of things? Also what exactly is wrong with the above code?


回答1:


Ok, so finally I wrote the following kernel module. Am not sure it is right, since I don't observe the drastic slowdown which should accompany when you disable cache. But this compiles and inserts properly.

Any pointers will be helpful.

Thanks!

#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);



回答2:


You cannot do operations like this from user code and even running as root is user code.

You will need to make this into a driver module and load it using insmod.




回答3:


I think you don't see the "drastic slowdown" because you have multiple cores, right? I made some experiments and it seems to me that setting CD in %cr0 only affects the processor your are running the module on.

Make sure that you run your code on all cores where you want to disable caching. You could, for example, create a /proc/cachedisable file where a read triggers your code. Then use

taskset -c cpu_number cat /proc/cachedisable

to disable the caches on CPU cpu_number. Do the same with /proc/cacheenable and you have everything you need. This works for me and there is no need to alter the MTRRs, which is pretty complicated. If you have multiple processors then you can disable caching on only one of them and perform your experiments on this cpu. Then the rest of the system remains usable.




回答4:


Try this: "mov %%cr0, %%eax \n"

A simple % is interpreted as user argument (I think).

You should read this




回答5:


The code compiles OK for me on 32-bit x86 bit not on x86-64 - this is with gcc 4.2.1 on Mac OS X:

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

No errors or warnings.

$ 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'
$

So I guess there are deeper issues than just the mov %eax,%cr0 instruction here with asm on x86-64.

Looking at the x86-64 ISA it seems that you probably need something like this for 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;
}

I don't know if this works but it at least compiles/assembles OK:

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


来源:https://stackoverflow.com/questions/3962950/how-to-set-control-register-0-cr0-bits-in-x86-64-using-gcc-assembly-on-linux

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!