Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly QEMU上的BIOS int 10h打印垃圾_Assembly_Nasm_X86 16_Bootloader_Bios - Fatal编程技术网

Assembly QEMU上的BIOS int 10h打印垃圾

Assembly QEMU上的BIOS int 10h打印垃圾,assembly,nasm,x86-16,bootloader,bios,Assembly,Nasm,X86 16,Bootloader,Bios,我在编写x86实模式汇编程序时遇到了一个问题,该程序在QEMU中作为引导加载程序运行。我正试图通过BIOS中断0x10打印文本。我的代码是: print: pusha .loop: mov AL, [SI] cmp AL, 0 je .end call printChar inc SI jmp .loop .end: popa ret printChar: pusha mov AH, 0x0E mo

我在编写x86实模式汇编程序时遇到了一个问题,该程序在QEMU中作为引导加载程序运行。我正试图通过BIOS中断0x10打印文本。我的代码是:

print:
    pusha
.loop:
    mov AL, [SI]
    cmp AL, 0
    je .end
    call printChar
    inc SI
    jmp .loop
.end:
    popa
    ret

printChar:
    pusha
    mov AH, 0x0E
    mov BH, 0
    mov BL, 0x0F
    int 0x10
    popa
    ret
我使用
[ORG 0x7c00]
作为原点。我测试了printChar标签,并用AL中的一些字母对其进行了调用,结果很好。当我尝试将内存地址加载到消息时,如下所示:

loadMsg      db "Loading",0
mov SI, loadMessage
call print
我在QEMU仿真器上得到像“U”这样的垃圾作为输出。昨天,我写了一个非常类似的代码,完全没有问题。是什么导致了我的问题?如何解决?

这是一个问题:

loadMsg    db "Loading",0
mov        SI, loadMessage
call    print
除非程序跳过“加载”文本,否则它将执行这些字节可能(或可能不)表示的任何指令。类似这样的东西可以修复它:

    jmp      print_msg
    loadMsg    db "Loading",0
print_msg:
    mov        SI, loadMessage
    call    print
我最近在Stackoverflow的回答中写了一些,可能对你有用。可能的提示1适用于您的问题:

当BIOS跳转到您的代码时,您不能依赖具有有效或预期值的CS、DS、ES、SS、SP寄存器。它们应该在引导加载程序启动时进行适当设置。您只能保证引导加载程序将从物理地址0x00007c00加载并运行,并且引导驱动器号已加载到DL寄存器中


基于printChar工作的事实,并且写出整个字符串并不意味着DS:SI没有指向字符串所在的内存中的正确位置。通常的原因是,当BIOS跳转到引导加载程序时,开发人员错误地认为CS和/或DS寄存器设置正确。必须手动设置。如果原点为0x7c00,则需要将DS设置为0。在16位实模式下,使用公式
计算物理内存地址(当BIOS引导加载第一个扇区(512字节)时,段引导加载程序在物理内存地址0x7c00处加载)您需要告诉NASM您的代码将从位置0x7c00开始,以便它知道如何正确生成内存中数据的偏移量。因为您不能保证DS包含引导加载程序跳转到您的代码时预期的段-您需要手动设置它。真的谢谢,这很有帮助。因此,由于我没有正确设置DS,它只使用了DS:SI,这可以是机器上BIOS喜欢的任何内容。我有一点怀疑,将SS设置为0,SP设置为0X7C00,您没有将堆栈放入0000:7C00?并且堆栈不会开始“覆盖”引导加载程序?很高兴你解决了DS问题。至于SS:SP是0000:7C00。堆栈的工作方式(在16位实模式下)SP先减2,然后在SS:SP处写入a值。这意味着SS:SP为0000:0x7c00时的第一次推送将减至0000:0x7BFE,然后向该位置写入一个2字节的字。由于减量先发生,因此它不会写入代码的顶部。您可以将SS:SP放置在几乎没有配置的任何位置你的数据和代码都是合法的-我只是用0x0000:0x7c00作为例子。老兄,你太棒了。我试图找到一个关于堆栈如何工作的答案,找到将堆栈放在内存中的位置,你的答案非常完美。因此堆栈的工作方式“有点向后”,它在添加值之前从SP中减去,例如,如果我将SP设置为7E00h(7C00h+512d)然后将stat覆盖我的引导加载程序(从末尾开始,假设BIOS在0000:7C00加载了我的引导加载程序).@rcgldr如果您不可能在有缺陷的8088上运行,则不需要它。如果您可能要在这样的硬件上运行,则如果您有足够的空间,则使用它是合理的。@rcgldr:我很清楚,它会禁用它,直到下一条指令结束(在真正的8088/8086硬件上)它应该禁用任何段寄存器(不仅仅是SS)的中断.这一点随着80286+而改变,因为它只针对SS。我特别提到了buggy 8088是有原因的。我的代码针对的是可能存在的更广泛的硬件。从80年代中期开始,我就在真实的8088硬件上进行汇编语言开发,我也解释了一个众所周知的错误。1987年的《PC》杂志刊登了一篇文章:。哦,我的错。我很抱歉仍在学习,这部分只是一个例子。我没有在代码中放入任何数据声明;)我没有按照惯例将数据放入代码中,但阅读您所说的内容非常有意义,为什么不将数据放入代码段,因为数据将被执行,而它对处理器来说是垃圾
xor ax, ax       ; set AX to zero
mov ds, ax       ;     DS = 0  
mov ax, cs
mov ds, ax       ; Make DS=CS
    BITS  16
    ORG   0x7c00
    GLOBAL main

main:
    xor ax, ax        ; AX = 0
    mov ds, ax        ; DS = 0
    mov bx, 0x7c00

    cli               ; Turn off interrupts for SS:SP update
                      ; to avoid a problem with buggy 8088 CPUs
    mov ss, ax        ; SS = 0x0000
    mov sp, bx        ; SP = 0x7c00
                      ; We'll set the stack starting just below
                      ; where the bootloader is at 0x0:0x7c00. The
                      ; stack can be placed anywhere in usable and
                      ; unused RAM.
    sti               ; Turn interrupts back on

    mov SI, loadMsg
    call print

    cli
.endloop:
    hlt
    jmp .endloop      ; When finished effectively put our bootloader
                      ; in endless cycle

print:
    pusha
.loop:
    mov AL, [SI]      ; No segment on [SI] means implicit DS:[SI]
    cmp AL, 0
    je .end
    call printChar
    inc SI
    jmp .loop
.end:
    popa
    ret

printChar:
    pusha
    mov AH, 0x0E
    mov BH, 0
    mov BL, 0x0F
    int 0x10
    popa
    ret

; Place the Data after our code
loadMsg db "Loading",0

times 510 - ($ - $$) db 0   ; padding with 0 at the end
dw 0xAA55                   ; PC boot signature