为什么此汇编代码无法打印到 VGA 文本模式显存?
Why does this assembly code not working to print to VGA text mode video memory?
我有以下汇编代码。我正在尝试创建一个小型引导加载程序以进入 32 位保护模式。进入保护模式后,我需要打印到 VGA 文本模式视频内存 (0xb8000) 以进行测试。我的代码不起作用。我从网络上的各种资源中找到了代码,并了解到大多数代码都有类似的代码可以正常工作,比如这个例子: 。我的代码不起作用:
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 table 如果您将其放在那里)。
永远记住汇编是非常底层的。无论您在代码中坚持什么,无论是否实际有意义的指令,如果处理器到达它,都将被视为代码。它不会跳过数据,也不会在您编写的最后一条指令后停止。
至于指令反汇编错误的原因,反汇编程序不知道什么时候切换到32位模式。它只是一个反汇编器,而不是一个模拟器,所以它看不到在 32 位模式下获取 CPU 执行该部分的 far 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
我有以下汇编代码。我正在尝试创建一个小型引导加载程序以进入 32 位保护模式。进入保护模式后,我需要打印到 VGA 文本模式视频内存 (0xb8000) 以进行测试。我的代码不起作用。我从网络上的各种资源中找到了代码,并了解到大多数代码都有类似的代码可以正常工作,比如这个例子:
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 table 如果您将其放在那里)。
永远记住汇编是非常底层的。无论您在代码中坚持什么,无论是否实际有意义的指令,如果处理器到达它,都将被视为代码。它不会跳过数据,也不会在您编写的最后一条指令后停止。
至于指令反汇编错误的原因,反汇编程序不知道什么时候切换到32位模式。它只是一个反汇编器,而不是一个模拟器,所以它看不到在 32 位模式下获取 CPU 执行该部分的 far 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