s0l*_*0li 27 x86 assembly operating-system protected-mode bootloader
我很难理解简单的引导装载程序是如何工作的.我正在谈论的引导加载程序是麻省理工学院"操作系统工程"课程中的一个.
首先,让我向您展示BIOS执行的一段汇编代码:
[f000:fec3] 0xffec3: lidtw %cs:0x7908
[f000:fec9] 0xffec9: lgdtw %cs:0x7948
[f000:fecf] 0xffecf: mov %cr0,%eax
[f000:fed2] 0xffed2: or $0x1,%eax
[f000:fed6] 0xffed6: mov %eax,%cr0
[f000:fed9] 0xffed9: ljmpl $0x8,$0xffee1
Run Code Online (Sandbox Code Playgroud)
从它的外观来看,此代码设置中断表和描述符表,然后打开保护模式.
转到启动加载程序代码 -
# Switch from real to protected mode, using a bootstrap GDT
# and segment translation that makes virtual addresses
# identical to their physical addresses, so that the
# effective memory map does not change during the switch.
lgdt gdtdesc
movl %cr0, %eax
orl $CR0_PE_ON, %eax
movl %eax, %cr0
# Jump to next instruction, but in 32-bit code segment.
# Switches processor into 32-bit mode.
ljmp $PROT_MODE_CSEG, $protcseg
Run Code Online (Sandbox Code Playgroud)
另一件我不明白的事情 - 当我用gdb跟踪引导加载程序的执行时,我看到正在执行以下指令(这是来自引导加载程序代码的ljmp指令):
ljmp $0x8,$0x7c32
Run Code Online (Sandbox Code Playgroud)
但当我查看.asm文件时,我看到以下内容:
ljmp $0xb866,$0x87c32
Run Code Online (Sandbox Code Playgroud)
完全迷失在这里 - 为什么.asm文件中写的指令和执行的指令是不同的?我有一个预感,这与保护模式以及它如何转换地址有关,但我并没有真正得到它.
我将不胜感激任何帮助!
ugh*_*fhw 26
某些BIOS实现在进入引导加载程序之前进入保护模式.大多数人没有.BIOS有可能在短时间内切换到保护模式,并在进入引导加载程序之前切换回来,这将允许它使用保护模式的一些好处(例如32位是默认地址大小).引导加载程序应处于实模式的原因是大多数BIOS功能仅在实模式下工作,因此您需要处于实模式才能使用它们.
ljmp指定除了要跳转到的地址之外还要切换到的代码段.它们非常相似(至少在GAS中)汇编器会将带有2个操作数的jmp切换为ljmp.
ljmp是改变cs寄存器的唯一方法之一.这需要完成以激活保护模式,因为cs寄存器需要包含GDT中代码段的选择器.(如果你想知道,改变cs的其他方法是远程调用,远程返回和中断返回)
请参阅第1项.要么BIOS切换回实模式,否则此引导加载程序将无法使用此BIOS.
请参阅第3项.它更改cs以指定32位代码段,因此处理器进入32位模式.
当您查看.asm文件时,指令被解释为地址大小为32位,但GDB将其解释为地址大小为16位.指令地址处的数据为0xEA 32 7C 08 00 66 B8.EA是跳远操作码.在32位地址空间中,地址将使用接下来的四个字节指定,地址为0x87C32,但在16位地址空间中,仅使用2个字节,地址为0x7C32.地址后面的2个字节指定所请求的代码段,在32位模式下为0xB866,在16位模式下为0x0008.0x66 B8是下一条指令的开始,它将一个16位立即值移入ax寄存器,可能是为保护模式设置数据段.