我正在看一些视频学习i386的系统内核编程,我知道一些进入保护模式的步骤:
在一个.code16
文件中,首先我需要打开A20 Address Line
并更改CR0
寄存器,然后我需要将ljmp
转换成一个.code32
代码。
现在,我正在考虑.code16
机器代码和.code32
机器代码之间的区别
以下是我的问题:
1.在保护模式下使用.code16
代码是否有效?
.code16
机器码和汇编程序生成的.code32
机器码有什么区别
1.我发现在我设置CR0
寄存器之后和ljmp之前执行.code16
代码是有效的,这是为什么?
1.我的老师告诉我.code16
的意思是“生成指定为16位模式的代码”,.code32
的意思是“生成指定为32位模式的代码”,那么这是什么意思呢?
很抱歉我的无知,我是这方面的绿色
1条答案
按热度按时间kognpnkq1#
汇编程序生成的.code16机器码和.code32机器码有什么区别?
在16位模式(真实的模式和16位保护模式)和32位保护模式下,CPU对代码字节的解释不同。
主要区别在于指令前缀
66
与67
(十六进制)得含义相反:在16位模式下,CPU默认使用16位寄存器和常量,i8086型寻址模式,前缀
66
告诉CPU使用32位寄存器和常量;前缀67
告诉CPU使用i80386类型的寻址模式:在32位保护模式中,情况正好相反:
“生成指定为16/32位模式的代码”...那么这是什么意思呢?
如果程序中有一行是
mov ecx,[eax]
,汇编程序将以.code32
模式写入8b 08
,以.code16
模式写入66 67 8b 08
。...因为在32位模式下运行时,CPU将
8b 08
解释为mov ecx,[eax]
,而在16位模式下运行时,CPU将66 67 8b 08
解释为mov ecx,[eax]
。在保护模式下使用.code16代码是否有效?
关于“16位保护模式”我已经写过了。
实际上,不存在“16位保护模式”,只有一个“保护模式”。在保护模式下,您可以在GDT(或LDT)中创建16位和32位描述符。
要在保护模式下执行16位代码,必须创建一个16位代码描述符(在GDT或LDT中),并对该代码执行
ljmp
。(要将32位CPU从保护模式切换回真实的模式,需要在保护模式下执行16位代码。)
请注意,16位代码(以及堆栈)的描述符的大小必须小于等于64 KiB。这意味着您无法创建一个描述符来描述整个4 GiB内存(就像32位代码一样),但可能需要为位于内存不同部分的代码创建多个描述符。
我发现在设置CR 0寄存器之后和ljmp之前执行.code16代码是有效的,这是为什么?
在内部,段寄存器(
cs
、ds
...)* 看起来 * 大约为80位长,但这80位中只有16位对程序员可见。cs
寄存器的一个“隐藏”位指定CPU是执行16位还是32位代码。(在保护模式下,该位从GDT或LDT读取。)根据我在阅读所谓的“虚幻模式”时所读到的一些信息,i80386 CPU内部的“真实模式”和“保护模式”之间的主要区别似乎是,当改变段寄存器的值时,段寄存器的“隐藏”位在两种模式中的修改方式不同。(中断处理等方面也有区别...)
如果为真,则设置或清除
CR0
的位0(几乎)没有任何影响,直到段寄存器被更改(通过执行ljmp
、mov ds,ax
...或中断)。