我有下面的汇编代码,我想创建一个小的bootloader来进入32位保护模式。我试图创建一个小的bootloader来进入32位保护模式,一旦进入保护模式,我需要打印到VGA文本模式的视频存储器(0xb8000)来进行测试。一旦进入保护模式,我需要打印到VGA文本模式的视频存储器(0xb8000)以进行测试。我的代码无法工作。我从网络上的各种资源中找到了代码,了解到大多数有类似的代码,可以正常工作,比如这个例子。在保护模式下将字符打印到屏幕ASM . 我的代码不能用。
bits 16
mov ah, 0x00 ;Set up video mode
mov al, 0x03
int 0x10
gdt_start:
dq 0x0
gdt_code:
dw 0xFFFF
dw 0x0
db 0x0
db 10011010b
db 11001111b
db 0x0
gdt_data:
dw 0xFFFF
dw 0x0
db 0x0
db 10010010b
db 11001111b
db 0x0
gdtr:
dw 24
dd gdt_start
lgdt [gdtr]
cli
mov eax, cr0
or al, 1
mov cr0, eax
jmp 0x08:protectedMode
bits 32
protectedMode:
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov word [0xb8000], 0x0769
times 510 - ($-$$) db 0
dw 0xaa55
我用以下方法编译代码
nasm -fbin boot.asm -oboot.bin
然后用..:
qemu-system-x86_64 -fda boot.bin
它什么都不做。
当我用:
ndisasm boot.bin
它的输出结果如下。
为什么在加零之前的指令是:
mov dword [di], 0xb8000
当是
mov word [0xb8000], 0x0769
当你有这个数据块时。
gdt_start:
dq 0x0
gdt_code:
dw 0xFFFF
dw 0x0
db 0x0
db 10011010b
db 11001111b
db 0x0
gdt_data:
dw 0xFFFF
dw 0x0
db 0x0
db 10010010b
db 11001111b
db 0x0
gdtr:
dw 24
dd gdt_start
它位于执行路径中. 这个数据将作为代码被处理器执行,作为接下来的指令,在经过 int 0x10
. 把这个移低一点,然后... mov word [0xb8000], 0x0769
.
你还需要在执行该指令后添加一个无限循环,以防止执行过程中落到后面的任何垃圾中(如果你把它放在那里,那么GDT表)。
永远记住,汇编是非常低级的。无论你在代码中贴的是什么,无论是否有实际意义的指令,如果处理器有机会接触到它,都会被当作代码处理。它不会跳过数据,也不会在你写完最后一条指令后停止。
至于为什么指令反汇编是错误的,反汇编器不知道什么时候切换到32位模式。 它只是一个反汇编器,而不是模拟器,所以它看不到让CPU在32位模式下执行那部分指令的远期jmp的效果。
你可以在32位模式下拆解整个东西,然后(在拆解前发生一些乱七八糟的事情,让它与实际的指令边界恢复同步),它就会按照你的意图用这个来拆解。
ndisasm -b 32 boot.bin
... ;; some earlier mess of 16-bit code disassembled as 32
0000003B 8ED8 mov ds,eax
0000003D 8EC0 mov es,eax
0000003F 8EE0 mov fs,eax
00000041 8EE8 mov gs,eax
00000043 8ED0 mov ss,eax
00000045 66C70500800B0069 mov word [dword 0xb8000],0x769 ; correct disassembly
-07
0000004E 0000 add [eax],al
00000050 0000 add [eax],al