NASM为什么不能正确初始化寄存器的值?

时间:2019-04-06 20:05:25

标签: assembly operating-system nasm

我想制作一个在没有BIOS的情况下在屏幕上打印字符串的驱动程序(在保护模式下)。我正在使用QEMU(使用qemu-system-x64_86)和NASM。

我正在尝试将0xb8000地址移到ebx中,但是出了点问题,这是第二个引导加载程序阶段的代码,在这里我试图切换到PM并调用驱动程序函数:

bits 16
org 0x7e00

jmp main

%include "./lib/gdt.inc"
%include "./lib/driver_print_string.asm"    ; THE function


main:
    cli                       ; disable interrupts
    xor ax, ax                ; null segments
    mov ds, ax
    mov es, ax
    mov ss, ax
    mov sp, 0x07c0            ; the stack is under 0x7c00
    sti                       ; enable interrupts

call installGDT           ; installing GDT!!!

; ENTERING PM MODE!
cli
mov eax, cr0
or eax, 1
mov cr0, eax

jmp 0x8:final_stage


; =============================================================
; FINAL STAGE!
bits 32

final_stage:
    cli

    mov ax, 0x10
    mov ds, ax
    mov es, ax
    mov ss, ax

    mov esp, 0x07c0

dr_calling:
    mov esi, sty

    call print_string_esi


jmp $


sty: db "The driver is working!", 0

times 512 - ($ - $$) db 0

gdt.inc:

bits 16

installGDT:
    cli
    pusha
    lgdt [toc]
    sti
    popa
    ret

;*******************************************
; Global Descriptor Table (GDT)
;*******************************************

gdt_data:
    dd 0                ; null descriptor
    dd 0

; gdt code:             ; code descriptor
    dw 0FFFFh           ; limit low
    dw 0                ; base low
    db 0                ; base middle
    db 10011010b            ; access
    db 11001111b            ; granularity
    db 0                ; base high

; gdt data:             ; data descriptor
    dw 0FFFFh           ; limit low (Same as code)
    dw 0                ; base low
    db 0                ; base middle
    db 10010010b            ; access
    db 11001111b            ; granularity
    db 0                ; base high

end_of_gdt:
toc:
    dw end_of_gdt - gdt_data - 1    ; limit (Size of GDT)
    dd gdt_data             ; base of GDT

和driver_print_string.asm:

print_string_esi:
    mov ebx, 0xb8000

    mov byte [ebx], 'x'
    mov byte [ebx+1], 0x7       

    jmp $

但是没有任何效果。如果我在QEMU命令行中写了“信息寄存器”,它告诉我EBX = 00008000,但是为什么不是b8000?如果我执行此更改的dr_calling函数:

dr_calling:
    mov esi, sty
    mov ebx, 0xb8000

    mov byte [ebx], 'x'
    mov byte [ebx+1], 0x7

    jmp $

一切正常,QEMU显示EBX = 000b8000。我该如何解决?

1 个答案:

答案 0 :(得分:1)

因为driver_print_string.asm包含在bits 16的开头,所以它将被编译为具有32位寻址的16位代码。但是您可以从下面的32位代码中调用它。如果您内联它,它将被编译为32位代码。只需在bits 32

下方的某个位置添加此函数