【发布时间】:2019-03-11 05:49:26
【问题描述】:
当我必须设置 EIP 寄存器时,程序没有跳转到正确的位置。我期待jmp *%ecx 使用 LEA 跳转到内存中的正确位置,将 EIP 设置为 0xC0100000 左右(标签:StartInHigherHalf)。我不认为kmain 是必要的,因为问题是在它被调用之前。反正我要发了。
我尝试在 QEMU 上使用 -d cpu 标志对其进行调试,并且在跳转(被 HLT 阻止)之前表示 ECX 未使用 LEA 函数加载。 LEA 指令是否有可能不执行?为什么会这样?我该如何解决?
引导.S:
.set ALIGN, 1<<0
.set MEMINFO, 1<<1
.set FLAGS, ALIGN | MEMINFO
.set MAGIC, 0x1BADB002
.set CHECKSUM, -(MAGIC + FLAGS)
.set KERNEL_VIRTUAL_BASE, 0xC0000000
.set KERNEL_PAGE_NUMBER, (KERNEL_VIRTUAL_BASE >> 22)
.section .multiboot
.align 4
.long MAGIC
.long FLAGS
.long CHECKSUM
.section .data
.align 0x1000
BootPageDirectory:
.quad 0x00000083
.rept KERNEL_PAGE_NUMBER - 1
.quad 0
.endr
.quad 0x00000083
.rept 0x400 - KERNEL_PAGE_NUMBER - 1
.quad 0
.endr
.set STACKSIZE, 0x4000
.global __start__
.set __start__, (setup)
setup:
mov $(BootPageDirectory - KERNEL_VIRTUAL_BASE), %ecx
mov %ecx, %cr3
mov %cr4, %ecx
or $0x00000010, %ecx
mov %ecx, %cr4
mov %cr0, %ecx
or $0x80000000, %ecx
mov %ecx, %cr0
lea StartInHigherHalf, %ecx
jmp *%ecx
StartInHigherHalf:
movl $0, (BootPageDirectory)
invlpg (0)
mov $(stack + STACKSIZE), %esp
push %eax
push %ebx
call _init
call kmain
cli
1: hlt
jmp 1
.section .bss
.align 32
.lcomm stack, STACKSIZE
.global gdtFlush
.extern gp
gdtFlush:
lgdt (gp)
mov $0x10, %eax
mov %eax, %ds
mov %eax, %es
mov %eax, %gs
mov %eax, %fs
mov %eax, %ss
ljmp $0x08, $setcs
setcs:
ret
linker.ld:
ENTRY(__start__)
OUTPUT_FORMAT(elf32-i386)
SECTIONS {
. = 0xC0100000;
.text ALIGN(0x1000) : AT(ADDR(.text) - 0xC0000000) {
*(.multiboot)
*(.text)
}
.rodata ALIGN(0x1000) : AT(ADDR(.rodata) - 0xC0000000) {
*(.rodata*)
}
.data ALIGN(0x1000) : AT(ADDR(.data) - 0xC0000000) {
*(.data)
}
.bss ALIGN(0x1000) : AT(ADDR(.bss) - 0xC0000000) {
_sbss = .;
*(COMMON)
*(.bss)
_ebss = .;
}
}
kmain.c:
#include <kernel/tty.h>
#include <kernel/log.h>
#include <kernel/stack-protector.h>
#include <kernel/gdt.h>
__attribute__ ((noreturn));
void kmain(void) {
gdtInstall();
initializeTerminal();
char c;
char *buffer = &c;
char *start = buffer;
char str[] = "Hello, kernel World!";
atomicallyLog(1, 1, str, buffer);
kprintf(start, 1);
}
【问题讨论】:
-
如果您只是在
kmain返回后才查看ecx的值,您为什么认为它仍然具有LEA 设置的值?为什么不在 LEA 指令上设置断点?这似乎不是任何东西的 minimal reproducible example,因为您没有显示kmain的 asm,也没有显示您实际看到的与预期看到的任何数值。 -
如果执行到达
hlt/jmp循环,那么jmp *%ecx可能正在按您的预期工作,否则您可能不会结束。你真的只看ecx就像你在第二段中所说的那样吗?如果是这样,您为什么不使用调试器在其他东西破坏它之前更早地查看 ECX? -
ECX 以 0x80000011 的值到达跳转点,因为在我使用该值设置 cr0 之前。要运行 QEMU,我只需传递“-cdrom MyOSName.iso”,而对于调试,我也传递“-d cpu”。
标签: assembly x86 paging bootloader osdev