X86 INT 10h未打印通过堆栈的字符

X86 INT 10h未打印通过堆栈的字符,x86,nasm,bootloader,X86,Nasm,Bootloader,我正在按照一本书中的说明去做。我正试图在QEMU上的i8086上编写一个简单的引导加载程序。 我使用BIOS中断(INT 10,电传模式下的E-Write文本)在我之前设置的位置打印出一个字符,也使用BIOS中断(INT 10,2-设置光标位置) 设置光标位置有效 我的目标是生成一个子例程“PutChar”,它将char作为参数,然后打印它。直接打印字符(即,mov al,'c')效果很好,这表明它确实可以工作 寄存器AL接受要打印的字符。 寄存器AH定义应使用INT 10h执行哪个函数 我在实

我正在按照一本书中的说明去做。我正试图在QEMU上的i8086上编写一个简单的引导加载程序。
我使用BIOS中断(INT 10,电传模式下的E-Write文本)在我之前设置的位置打印出一个字符,也使用BIOS中断(INT 10,2-设置光标位置)

设置光标位置有效

我的目标是生成一个子例程“PutChar”,它将char作为参数,然后打印它。直接打印字符(即,
mov al,'c'
)效果很好,这表明它确实可以工作

寄存器
AL
接受要打印的字符。
寄存器
AH
定义应使用INT 10h执行哪个函数

我在实际参数应该复制到AH的地方放了一个星号

然而,在某个地方我犯了一个我找不到的错误。我一次又一次地计算,如果我正确地引用了堆栈上的“A”,我甚至试过[bp]、[bp+8]和[bp+16],可以说是出于绝望

运行这些操作不会打印任何内容,甚至不会打印“奇怪的”ASCII字符,这让我相信引用的地址上没有任何内容。显然,我在某个地方搞错了,但在哪里呢

以下代码:

;********************
;A simple bootloader
;*******************
org 0x7c00
bits 16

start: 
  call MoveCursor
  push 'A' ; SP--, then put 'A' on stack. (8 bit only)
  call PutChar
  jmp boot


MoveCursor:
  mov bh, 0
  mov dh, 11
  mov dl, 10
  mov ah, 02h
  int 10h
  ret

PutChar:
  push bp ; SP--, SP--, then put Base Pointer on stack (16 bit)
  mov  bp, sp ;Copy Stack Pointer to Base Pointer
  *mov al, [bp+16] ;Since [bp] points to the old Base Pointer and the Base Pointer is 16 bits long, going back 16 bit would result in 'A', right?
  mov ah, 0eh
  int 10h
  pop bp 
  ret


boot:
  cli ;no interrupt
  cld ;all that we need to init
  hlt ;halt the system

;We have to be 512 bytes. Clear the rest of the bytes with 0
times 510 - ($-$$) db 0
dw 0xAA55

多亏了@Margaret Bloom,我才解决了这个问题。 事实上,我确实计算错了,而且我也没有考虑到
[bp+8]
实际上是指
bp
之后的8个字节,而不是我最初假设的

然后,我忘记了调用函数也会增加堆栈:当然是返回地址

因此,按以下顺序将值推送到堆栈上:

  • 'A'(8位,但由于无法在x86上推送8位,因此16位以小端格式推送)
  • 当前IP(16位)

  • BP(16位)(多亏@Margaret Bloom,我才解决了这个问题。 事实上,我确实计算错了,而且我也没有考虑到
    [bp+8]
    实际上是指
    bp
    之后的8个字节,而不是我最初假设的

    然后,我忘记了调用函数也会增加堆栈:当然是返回地址

    因此,按以下顺序将值推送到堆栈上:

  • 'A'(8位,但由于无法在x86上推送8位,因此16位以小端格式推送)
  • 当前IP(16位)

  • BP(16位)(调试时间!在PutChar中设置断点并检查BP指向的内容。
    [BP]
    =旧帧指针,
    [BP+02h]
    =返回地址,
    [BP+04h]
    =您的char.holy guacamole,这很有帮助。谢谢!@m0skit0引导加载程序以二进制格式组装,意思是(afai理解)没有符号可以让我在标签等处设置断点。但从长远来看,我肯定需要弄清楚这一点。@RnBandCrunk调试时间!在PutChar中设置断点并检查BP指向的内容。
    [BP]
    =旧帧指针,
    [BP+02h]
    =返回地址,
    [BP+04h]
    =你的char.holy鳄梨酱,这很有用。谢谢!@m0skit0引导加载程序是以二进制格式组装的,这意味着(afai理解)没有任何符号可以让我在标签等处设置断点。但从长远来看,我肯定需要解决这个问题。@RnBandCrunk很高兴看到你解决了问题并发布和回答:)在x86中,位永远不可寻址(尽管有一些指令处理位)。此外,
    push
    至少可推16位(尽管指令编码中的直接操作数为8位)。哦,您可以接受自己的答案。很好;)很高兴看到您解决了问题并发布和回答:)位在x86中永远不可寻址(虽然有一些指令处理位)。此外,
    push
    至少推送16位(尽管指令编码中的立即操作数为8位)。哦,您可以接受自己的答案。很好;)