为什么此汇编代码无法打印到VGA缓冲区

I have the following assembly code. I'm trying to create a small bootloader to go into protected mode. I need to print stuff to VGA from 32 bits mode for testing purposes but it doesn't work. I found the code from various ressources around the web and found out that most of them have a similar code which works properly like this example: Printing characters to screen ASM in protected mode

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

它输出以下结果:

enter image description here

为什么在附加零之前执行指令

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
    

    it's located in the path of execution. This data will be executed as code by the processor as the next instructions after int 0x10. Move this lower, after 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