【问题标题】:Assembly BIOS call not working装配 BIOS 调用不起作用
【发布时间】:2017-07-12 16:13:30
【问题描述】:

我正在使用一个简单的程序集 sn-p 来使用 BIOS 作为引导加载程序的一部分将字符打印到屏幕上。这是引导加载程序代码。

[org 0x7c00]

[bits 16]

%include "a20_check.asm"


mov ah, 0x0e
mov al, 'H'
int 0x10

times 510 - ($-$$) db 0
dw 0xaa55 

这是 a20_check.asm 函数的代码,取自 osdev.org

[bits 16]


; Returns: 0 in ax if the a20 line is disabled (memory wraps around)
;          1 in ax if the a20 line is enabled (memory does not wrap around)

check_a20:
pushf
push ds
push es
push di
push si

cli

xor ax, ax ; ax = 0
mov es, ax

not ax ; ax = 0xFFFF
mov ds, ax

mov di, 0x0500
mov si, 0x0510

mov al, byte [es:di]
push ax

mov al, byte [ds:si]
push ax

mov byte [es:di], 0x00
mov byte [ds:si], 0xFF

cmp byte [es:di], 0xFF

pop ax
mov byte [ds:si], al

pop ax
mov byte [es:di], al

mov ax, 0
je check_a20__exit

mov ax, 1

check_a20__exit:
pop si
pop di
pop es
pop ds
popf

ret

问题似乎出在最后一个标签中,check_a20__exit。如果我注释掉ret,那么字符就会打印到屏幕上。否则不打印。

谁能给我解释一下这个问题?

【问题讨论】:

  • 也许你应该在 "mov ax, 1" 之后写一个跳转代码,它跳转到 "check_a20__exit" 最后一行之外的代码 我的理论是你的代码没有从该行跳转到 "check_a20__exit" “je check_a20__exit”这导致“je check_a20__exit”之后的代码被执行,它也执行“check_a20__exit”,因为“check_a20__exit”只是一个标签,而不是c ++中的函数。因此,我们在没有先前匹配跳转的情况下调用了 ret 语句。在“je check_a20__exit”指令之前检查零标志的值。
  • 运行此代码的硬件环境是什么? "mov ax,0" 试图通过使累加器寄存器为零来设置零标志。
  • 代码正在使用 i386 架构的 qemu 仿真运行。
  • @SahilSingh : MOV 指令不会改变标志。
  • @SahilSingh je check_a20__exit 的标志由 cmp byte [es:di], 0xFF 设置。 “A20”的代码并非微不足道,除非你真的很了解这些东西,否则不要试图猜测它是如何工作的。顺便说一句,ax init to 0/1 可以用无分支方式重写:sbb ax,axinc ax

标签: assembly x86 bootloader bios x86-16


【解决方案1】:

如果您考虑自己对故障排除的描述,然后查看您是如何包含代码的,那么问题应该是显而易见的。

  • 首先,包含用于检查 A20 行的代码
  • 该代码以ret 结尾
  • 接下来我们找到在屏幕上打印字符的代码
  • 最后我们有了空填充

显然,ret 将尝试使用当前位于 SP 的任何内容并在那里切换执行路径...但您从未调用过任何内容,因此这些数据只是垃圾。

删除ret 允许它“落入”您的打印代码。

【讨论】:

  • 除了您在打印字符后提到的内容之外,它们继续执行未指定的代码(可能会徘徊记忆)。应该放置某种无限循环来避免这种情况。
猜你喜欢
  • 2018-12-22
  • 2016-11-13
  • 1970-01-01
  • 1970-01-01
  • 2014-09-01
  • 2017-01-19
  • 1970-01-01
  • 1970-01-01
  • 2017-02-27
相关资源
最近更新 更多