我目前正在研究操作系统的低级组织.为了实现我想要了解Linux内核是如何加载的.
我无法理解的是从16位(实模式)到32位(保护模式)的转换.它发生在这个文件中.
该protected_mode_jump函数对稍后执行的32位代码执行各种辅助计算,然后启用调节器中的PE位CR0
movl %cr0, %edx
orb $X86_CR0_PE, %dl # Protected mode
movl %edx, %cr0
Run Code Online (Sandbox Code Playgroud)
然后执行长跳转到32位代码:
# Transition to 32-bit mode
.byte 0x66, 0xea # ljmpl opcode
2: .long in_pm32 # offset
.word __BOOT_CS # segment
Run Code Online (Sandbox Code Playgroud)
据我所知in_pm32,32位函数的地址在下面声明protected_mode_jump:
.code32
.section ".text32","ax"
GLOBAL(in_pm32)
# some code
# ...
# some code
ENDPROC(in_pm32)
Run Code Online (Sandbox Code Playgroud)
的__BOOT_CS扇区基是0(GDT被设定预先这里),因此这意味着,偏移应该是基本上绝对地址in_pm32的功能.
这就是问题所在.在机器代码生成期间,汇编器/链接器不应该知道in_pm32函数的绝对地址,因为它不知道在实模式下它将在内存中加载的位置(各种引导加载程序可以占用不同的空间量,以及实模式内核)在引导加载程序之后加载).
此外,链接器脚本(setup.ld在同一文件夹中)将代码的原点设置为0,因此看起来in_pm32地址将是从实模式内核开始的偏移量.它应该可以正常使用16位代码,因为CS寄存器设置正确,但是当发生长跳转时,CPU已经处于保护模式,因此相对偏移不应该起作用.
所以我的问题:.byte …