【问题标题】:Why doesn't NASM initialize the register's value properly?为什么 NASM 不能正确初始化寄存器的值?
【发布时间】:2019-04-06 20:05:24
【问题描述】:

我想制作一个在没有 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。我该如何解决?

【问题讨论】:

  • 我怀疑 print_string_esi 被汇编为 16 位代码,但以 32 位模式执行。如果是这样,汇编器将插入一个操作数大小前缀(以在 16 位模式下访问 ebx),但在 32 位模式下执行时会导致它作为 16 位指令执行。

标签: assembly operating-system nasm


【解决方案1】:

因为 driver_print_string.asm 是在开头bits 16 之后包含的,所以会被编译为 32 位寻址的 16 位代码。但你从下面的 32 位代码中调用它。如果内联它,它会被编译为 32 位代码。只需在bits 32下方的某处包含此函数即可

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-11-19
    • 2012-08-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多