本文内容分析于2023年12月18日。今整理成文。
先看源代码:kern/mpentry.S:76:
asm
# Call mp_main(). (Exercise for the reader: why the indirect call?)
movl $mp_main, %eax
call *%eax灵魂提问:why the indirect call?
直接调用的call指令,使用%eip相对寻址。而call指令的偏移量,是在链接时确定的。但mpentry.S链接地址和运行地址不一样(复制到0x7000再执行),这使得链接时确定的偏移量在运行时是错误的。因此,只能使用间接调用,将mp_main的绝对地址加载到%eax中,然后call *%eax。
知道了原理,就可以改动链接脚本,使mpentry_start到mp_main通过call指令直接调用。
上面两句汇编改成:
asm
# Call mp_main(). (Exercise for the reader: why the indirect call?)
movl $mp_main, %eax
call *%eax
call true_mp_main // [!code ++]链接脚本kern/kernel.ld:
txt
.text : AT(0x100000) {
*(.text .stub .text.* .gnu.linkonce.t.*)
PROVIDE(true_mp_main = mp_main + (0xF0100000 + mpentry_start - 0x7000)); // [!code ++]
*(.text .stub .text.* .gnu.linkonce.t.*)
}