免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
123下一页
最近访问板块 发新帖
查看: 13451 | 回复: 25

[C] c中内嵌汇编movl cr3出错 [复制链接]

论坛徽章:
0
发表于 2012-10-06 04:25 |显示全部楼层
什么问题?
  1. int b;
  2. __asm__ __volatile__ ("movl %%cr3, %0" : "=r" (b));
复制代码
Error: suffix or operands invalid for `mov'

我movl %%eax就没问题

是不是跟cr3寄存器有关?读不了?

论坛徽章:
3
15-16赛季CBA联赛之山东
日期:2016-10-30 08:47:3015-16赛季CBA联赛之佛山
日期:2016-12-17 00:06:31CU十四周年纪念徽章
日期:2017-12-03 01:04:02
发表于 2012-10-06 09:09 |显示全部楼层
Linux kernel 2.6.28:

首先, 内核里面切换进程空间是通过switch_mm, 于是:
src/linux-2.6.28/arch/x86/include/asm# grep 'switch_mm' -nr .
得到:
  1. ./mmu_context_32.h:13:static inline void switch_mm(struct mm_struct *prev,
  2. ./mmu_context_64.h:14:static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
复制代码
进去看, 发现switch_mm是通过load_cr3来切换页目录的, 于是:
src/linux-2.6.28/arch/x86/include/asm# grep 'load_cr3' -nr .
得到:
  1. ./mmu_context_32.h:29:                load_cr3(next->pgd);
  2. ./mmu_context_32.h:46:                        load_cr3(next->pgd);
  3. ./mmu_context_64.h:26:                load_cr3(next->pgd);
  4. ./mmu_context_64.h:41:                        load_cr3(next->pgd);
  5. ./processor.h:184:static inline void load_cr3(pgd_t *pgdir)
复制代码
很显然load_cr3定义在processor.h 184行. 发现load_cr3调了write_cr3, 于是:
src/linux-2.6.28/arch/x86/include/asm# grep 'write_cr3' -nr .
得到:
  1. ./pgtable-3level.h:120:                write_cr3(pgd);
  2. ./tlbflush.h:20:        write_cr3(read_cr3());
  3. ./system.h:220:static inline void native_write_cr3(unsigned long val)
  4. ./system.h:280:#define write_cr3(x)        (native_write_cr3(x))
  5. ./processor.h:186:        write_cr3(__pa(pgdir));
  6. ./paravirt.h:230:        void (*write_cr3)(unsigned long);
  7. ./paravirt.h:676:static inline void write_cr3(unsigned long x)
  8. ./paravirt.h:678:        PVOP_VCALL1(pv_mmu_ops.write_cr3, x);
复制代码
嗯, write_cr3调用了一个通用的宏, 就是PVOP_VCALL1:
cat paravirt.h | grep '#define .*PVOP_VCALL1' -n
  1. 559:#define PVOP_VCALL1(op, arg1)       
复制代码
于是:
vim paravirt.h +559:
  1. #define PVOP_VCALL1(op, arg1)                                                \
  2.         __PVOP_VCALL(op, "", "", "0" ((unsigned long)(arg1)))
复制代码
这个宏是__PVOP_VCALL的包装, 好吧, 那么看__PVOP_VCALL:
  1. #define __PVOP_VCALL(op, pre, post, ...)                                \
  2.         ({                                                                \
  3.                 PVOP_VCALL_ARGS;                                        \
  4.                 PVOP_TEST_NULL(op);                                        \
  5.                 asm volatile(pre                                        \
  6.                              paravirt_alt(PARAVIRT_CALL)                \
  7.                              post                                        \
  8.                              : PVOP_VCALL_CLOBBERS                        \
  9.                              : paravirt_type(op),                        \
  10.                                paravirt_clobber(CLBR_ANY),                \
  11.                                ##__VA_ARGS__                                \
  12.                              : "memory", "cc" VEXTRA_CLOBBERS);                \
  13.         })
复制代码
=======================================================
很抱歉, 因为2.6.28内核需要处理32, 64位x86构架以及SMP的原因导致了上面的一系列抽象, 最终的宏是那么XX, 我已经不知道该如何吐槽.

=======================================================

那么在Linux kernel 2.4.0里面switch_mm是什么样子涅? 如下:
  1. static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk, unsigned cpu)
  2. {
  3.     ...
  4.     asm volatile("movl %0, %%cr3": :"r"(__pa(next->pgd)));
  5.     ...
  6. }
复制代码
=======================================================

那么LZ的语法似乎是对的. LZ的内嵌部分只有指令部和输出部, 这个no problem.
而gcc编译时应该不知道这代码是拿来干嘛的, 是内核涅还是应用程序代码的一部分? 而且cc1不负责汇编代码识别, 那是gas的事情.编译器cc1只要看嵌入汇编语法木有错, 那么就没有理由报错.
gas汇编器也木有理由报错, 因为gas也不知道这代码拿来干嘛用的.
那么可能的问题是, LZ的语法有错, 或者这用法不符合Intel的规定. 仔细检查吧LZ.
总之一句话, 如果语法和用法没错, 编译期是不可能报错的, 因为编译期根本不知道你拿这段代码干嘛.

=======================================================

顺便, 这样的代码即使编译通过, 在应用层是绝对不可能运行的. 因为毫无疑问访问cr3是特权级代码. 想看cr3究竟指向了哪个物理地址是吧? 也很easy, 写个内核模块驱动, insmod就木有问题了.

=======================================================

论坛徽章:
3
15-16赛季CBA联赛之山东
日期:2016-10-30 08:47:3015-16赛季CBA联赛之佛山
日期:2016-12-17 00:06:31CU十四周年纪念徽章
日期:2017-12-03 01:04:02
发表于 2012-10-06 09:36 |显示全部楼层

LZ确定没有任何别的地方有错? 报错确实是在编译期?

1. 手动调cc1(gcc -S xx.c -o xx.s), 如果这步都错, 那绝对是嵌入语法错误.

2. 调gas(gcc -c xx.c -o xx.o), 这步错, 证明汇编器不承认上述语法.
那么汇编器不承认语法的可能性只能是cr3不能读了 -- 不过我老实说觉得这很夸张, 应该不至于吧, 能写不能读? 要翻Intel手册了吗...

3. 链接器就更不可能报错了... 应用层的话系统默认链接脚本, 如果用途不是应用, 那么可能要手写链接脚本(内核模块是不用的, 因为内核的build system已经处理好了).

LZ试试罢? 在线等结论.

论坛徽章:
3
15-16赛季CBA联赛之山东
日期:2016-10-30 08:47:3015-16赛季CBA联赛之佛山
日期:2016-12-17 00:06:31CU十四周年纪念徽章
日期:2017-12-03 01:04:02
发表于 2012-10-06 10:41 |显示全部楼层
回复 1# ethantsien


    擦... 突然想起, CPU是64位的吧? 那么cr3还是32位么? 那么你movl木有问题么? movl 和 movq是不同的指令后缀.

论坛徽章:
0
发表于 2012-10-06 13:19 |显示全部楼层
本帖最后由 ethantsien 于 2012-10-10 22:27 编辑
captivated 发表于 2012-10-06 10:41
回复 1# ethantsien


我觉得跟命令没关系

论坛徽章:
0
发表于 2012-10-06 13:39 |显示全部楼层
用户模式下是无法读取cr3寄存器,既然没有系统调用能用,那么要进入内核模式,只能写驱动了

论坛徽章:
3
15-16赛季CBA联赛之山东
日期:2016-10-30 08:47:3015-16赛季CBA联赛之佛山
日期:2016-12-17 00:06:31CU十四周年纪念徽章
日期:2017-12-03 01:04:02
发表于 2012-10-06 14:15 |显示全部楼层
回复 5# ethantsien


    嗯. 我的意思是说, 你那代码编译期是不应该出错的. 出错应该是运行时不能访问的事情才对. 如果编译期报错, 那么就是指令语法有问题了. 所以我才猜那个. 因为我也没看到你语法**错.

论坛徽章:
3
15-16赛季CBA联赛之山东
日期:2016-10-30 08:47:3015-16赛季CBA联赛之佛山
日期:2016-12-17 00:06:31CU十四周年纪念徽章
日期:2017-12-03 01:04:02
发表于 2012-10-06 14:17 |显示全部楼层
我勒个去! "哪_里_有"居然是T_M_D_敏-感-词?

论坛徽章:
0
发表于 2012-10-06 14:26 |显示全部楼层
captivated 发表于 2012-10-06 14:15
回复 5# ethantsien


编译期间出错

论坛徽章:
59
2015年亚洲杯之约旦
日期:2015-01-27 21:27:392015年亚洲杯之日本
日期:2015-02-06 22:09:41拜羊年徽章
日期:2015-03-03 16:15:432015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:50:282015元宵节徽章
日期:2015-03-06 15:50:392015年亚洲杯之阿联酋
日期:2015-03-19 17:39:302015年亚洲杯之中国
日期:2015-03-23 18:52:23巳蛇
日期:2014-12-14 22:44:03双子座
日期:2014-12-10 21:39:16处女座
日期:2014-12-02 08:03:17天蝎座
日期:2014-07-21 19:08:47
发表于 2012-10-06 14:32 |显示全部楼层
**
มั้้้้้้้้้้้้้้มั้้้้้้้้้้้้้้มั้้้้้้้้้้้้้้มั้้้้้้้้้้้้้้มั้้้้้้้้้้้้้้มั้้้้้้้้้้้้้้มั้้้้้้้้้้้้้้มั้้้้้้้้้้้้้้มั้้้้้้้้้้้้้้มั้้้้้้้้้้้้้้มั้้้้้้้้้้้้้้มั้้้้้้้้้้้้้้มั้้้้้้้้้้้้้้มั้้้้้้้้้้้้้้มั้้้้้้้้้้้้้้มั้้้้้้้้้้้้้้มั้้้้้้้้้้้้้้มั้้้้้้้้้้้้้้มั้้้้้้้้้้้้้้มั้้้้้้้้้้้้้้มั้้้้้้้้้้้้้้มั้้้้้้้้้้้้้้มั้้้้้้้้้้้้้้มั้้้้้้้้้้้้้้มั้้้้้้้้้้้้้้มั้้้้้้้้้้้้้้มั้้้้้้้้้้้้้้มั้้้้้้้้้้้้้้มั้้้้้้้้้้้้้้มั้้้้้้้้้้้้้้มั้้้้้้้้้้้้้้มั้้้้้้้้้้้้้้มั้้้้้้้้้้้้้้มั้้้้้้้้้้้้้้มั้้้้้้้้้้้้้้มั้้้้้้้้้้้้้้มั้้้้้้้้้้้้้้มั้้้้้้้้้้้้้้มั้้้้้้้้้้้้้้มั้้้้้้้้้้้้้้มั้้้้้้้้้้้้้้มั้้้้้้้้้้้้้้มั้้้้้้้้้้้้้้มั้้้้้้้้้้้้้้มั้้้้้้้้้้้้้้มั้้้้้้้้้้้้้้
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP