- 论坛徽章:
- 3
|
回复 9# ethantsien
嗯. 那么LZ的结论呢, 是什么? 我可以十分肯定确定以及一定地保证, 这种东西如果不是语法或者用法问题, 绝对不会在编译期报错.
被你逼着去查Intel说明书第三卷了.
以下内容出自Intel说明书第三卷Chapter2 Section2.5, 控制寄存器.
2.5 CONTROL REGISTERS
Control registers (CR0, CR1, CR2, CR3, and CR4; see Figure 2-6) determine operating mode of the processor and the characteristics of the currently executing task. These registers are 32 bits in all 32-bit modes and compatibility mode.In 64-bit mode, control registers are expanded to 64 bits. The MOV CRn instructions are used to manipulate the register bits. Operand-size prefixes for these instructions are ignored. The following is also true:
• Bits 63:32 of CR0 and CR4 are reserved and must be written with zeros. Writing a nonzero value to any of the upper 32 bits results in a general-protection exception, #GP(0).
• All 64 bits of CR2 are writable by software.
• Bits 51:40 of CR3 are reserved and must be 0.
• The MOV CRn instructions do not check that addresses written to CR2 and CR3 are within the linear-address or physical-address limitations of the implemen-tation.
• Register CR8 is available in 64-bit mode only.
... 剩下的不再copy了, 请LZ自己去查.
简略的大体意思是, 控制寄存器cr0 -- cr4, 在64位长模式中都是64位, 在兼容32位模式下则为(可见)32位. MOV CRn指令用于操作寄存器位. 这些指令的操作数尺寸前缀被忽略.
==========================================================
接下来是关于LZ的语法或者用法分析. 我们知道movl或者movq只是汇编器为了方便使用者给的助记符. 这些助记符会被落实到实际的二进制指令上面. 汇编器中同样一个MOV指令, 翻译成为二进制指令后可能根本是不一样的指令.
那么Intel的二进制指令格式是怎么样的呢? x86是变长指令集, 其二进制指令格式如下(关于这个指令格式, LZ可以看Richard Blum所著《汇编语言程序设计》, 亦或, 直接参看Intel说明书前面两卷. 本人很讨厌看manual, 因此本人是看的前者. 一般来说程序员感兴趣的只是第三卷, 因为第三卷才是关于CPU编程模型Programming Model的):
指令前缀 操作码 ModR/M SIB 移位 数据元素
这个指令中各部分占多少bits不是我们关心的内容; 总之一个指令的最长长度不会超过15字节(Intel是变长复杂指令集构架, 也就是其指令集每个指令长度是不确定的). 稍微关心下指令前缀的作用:
1. 锁定前缀和重复前缀(锁总线保证原子操作, 以及串操作常用的重复功能)
2. 段覆盖/段超越前缀(还记得8086吧, 就是起那个作用的. 顺便, 即使64位CPU, cs ds ss等仍为16 bits, 它们在应用层出场机会已经几乎为0, 操作系统是要用的, 因为操作系统要把所有的段的段基址都设定为0, 从而使这个段式管理透明.)
3. 操作数长度覆盖前缀
4. 地址长度覆盖前缀
没错, 我们要关心的是3和4, 这两个前缀会指定操作数的长度和地址长度.
==========================================================
综合上面两个, 以及看说明书和指令格式说明之后, 我们可以确定的事情是, movl movq, 转换为真正的二进制指令后, 其指令的前缀部分关于操作数尺寸之类的被忽略. 但它是说长度被忽略, 并不代表长度不确定, 因为cr3的长度就是那个长度, 代表使用者自己要用对.
那么LZ的报错在编译期, 这要考查LZ的系统环境. 如果LZ是64位系统, 用的也是64位编译器, 那么gas会判定cr3是64 bits, 应该mov到一个能够存储64bits的变量中去. 你声明的是int b, 这显然不能够存储64 bits(64位Linux系统采用LP模式, 指针长度和long类型变量长度相同). 所以LZ可以试试声明b为unsigned long. 关于movl还是movq, LZ也可以试试 -- 改改看能不能编译通过是不, 举手之劳. 关于LZ的报错提示, 也很明显地指出是你的汇编指令后缀(mov + l还是mov + q啦)或者是你某个操作数有问题(有问题的操作数不一定就是cr3嘛).
==========================================================
虽然, 我很闲得淡腾地刷贴, 但是, 本人也要声明一个. 以上结论仅供参考. 我不做完全的正确性保证. 当然, 本人的引用是有正确性保证的. 另外, 我对自己编译期和运行期应该哪个地方报错之类的事情是很有自信的 -- 如果确实还有别的因素, 请CU的达人指教, 欢迎之至.
|
|