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

时间:2018-09-12 16:30:46

标签: x86 nasm bootloader

我正在按照一本书中的说明进行操作。我正在尝试在QEMU的i8086上编写一个简单的引导程序。
我正在使用BIOS中断(INT 10,E-在电传模式下写入文本)在我预先设置的位置上打印出一个字符,同时也在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

1 个答案:

答案 0 :(得分:2)

感谢@Margaret Bloom,我解决了它。 我实际上没有计算错了,我也没有考虑到[bp+8]实际上是指bp之后的8个字节而不是就像我最初假设的那样。现在想想,字节只是逻辑上的-我的错误。

然后,我忘记了调用函数还会添加到堆栈中:当然是返回地址。

因此,按以下顺序将值压入堆栈:

  1. 'A'(8位,但是由于无法在x86上压入8位,因此16位将以小尾数法进行压入)
  2. 当前IP(16位)
  3. BP(16位)(<-SP现在在这里)

然后将SP保存到BP中,并使用BP引用我的参数'A'。 因为[BP]是我的SP,所以[BP + 2]是我的寄信人地址,最后[BP + 4]是我的参数。

请注意,正如我所说,+ 2表示2个字节而不是位。