我编写了一个程序,试图读取和写入控制寄存器。
该程序编译正常,但是当内联汇编即将执行时,会产生分段错误。
代码:
void instructions(int val)
{
int i;
int value;
for(i = 0; i < val; i++)
__asm__("mov %cr0, %eax");
}
我使用了GDB并逐步执行每个汇编指令,发现在mov %cr0,%eax
处出现了段错误。请问有人知道这是什么问题吗?我编写了一个程序,试图读取和写入控制寄存器。
该程序编译正常,但是当内联汇编即将执行时,会产生分段错误。
代码:
void instructions(int val)
{
int i;
int value;
for(i = 0; i < val; i++)
__asm__("mov %cr0, %eax");
}
我使用了GDB并逐步执行每个汇编指令,发现在mov %cr0,%eax
处出现了段错误。请问有人知道这是什么问题吗?引用自Intel® 64和IA-32架构软件开发人员手册3-650 Vol. 2A关于控制寄存器的移动:
只有当前特权级为0时,才能执行此指令。
这意味着该指令只能在内核模式下执行。
一个最小的内核模块,记录cr0、cr2和cr3的内容,可能看起来像这样(32位代码路径未经测试):
/* hello.c */
#include <linux/module.h>
#include <linux/kernel.h>
int init_module(void)
{
#ifdef __x86_64__
u64 cr0, cr2, cr3;
__asm__ __volatile__ (
"mov %%cr0, %%rax\n\t"
"mov %%eax, %0\n\t"
"mov %%cr2, %%rax\n\t"
"mov %%eax, %1\n\t"
"mov %%cr3, %%rax\n\t"
"mov %%eax, %2\n\t"
: "=m" (cr0), "=m" (cr2), "=m" (cr3)
: /* no input */
: "%rax"
);
#elif defined(__i386__)
u32 cr0, cr2, cr3;
__asm__ __volatile__ (
"mov %%cr0, %%eax\n\t"
"mov %%eax, %0\n\t"
"mov %%cr2, %%eax\n\t"
"mov %%eax, %1\n\t"
"mov %%cr3, %%eax\n\t"
"mov %%eax, %2\n\t"
: "=m" (cr0), "=m" (cr2), "=m" (cr3)
: /* no input */
: "%eax"
);
#endif
printk(KERN_INFO "cr0 = 0x%8.8X\n", cr0);
printk(KERN_INFO "cr2 = 0x%8.8X\n", cr2);
printk(KERN_INFO "cr3 = 0x%8.8X\n", cr3);
return 0;
}
void cleanup_module(void)
{
}
# Makefile
obj-m += hello.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
test: all
sudo insmod ./hello.ko
sudo rmmod hello
dmesg | tail
u64
?至少在Intel 64的手册中,cr3
被记录在位0到63。 - corny%016lx
(或者如果将cr0 / cr2 / cr3转换为void *
,则可以使用%p
)。 - user786653cr0
吗?我可以读取它,但在写入时出现分段错误。 - Shuzheng