了解 nasm 用于在电传打字机模式下输出字符的程序集

understanding nasm assembly for outputting characters in teletype mode

我正在阅读这篇关于操作系统编程的精彩文章

http://www.cs.bham.ac.uk/~exr/lectures/opsys/10_11/lectures/os-dev.pdf

第 12 页有一个简单的引导程序。

如果我理解正确,显示的代码是您必须在 NASM 中写入的代码,以使 BIOS 打印出字符。

我不明白的是:

它说

we need interrupt 0x10 and to set ah to 0x0e (to indicate tele-type mode)
and al to the ASCII code of the character we wish to print.

但是第一条指令是:

mov ah , 0x0e ;int 10/ ah = 0eh -> scrolling teletype BIOS routine

我不明白该行的评论。为什么第一行代码不说:

mov ah, 0xeh
int 0x10

如果这就是你需要做的?

感谢帮助!

评论仅用于上下文,说明 AH=0x0e 因为它表示调用 INT 0x10.

时的滚动电传 BIOS 例程

为了简单起见,您可以将 int XXX 指令视为 "execute function XXX" 指令。在这种特殊情况下,如果您不首先使用您选择的字节加载 AL 寄存器,则每次出现 INT 0x10 时都会打印该寄存器中的任何字节。这就是为什么 AH 最初加载 0x0e 用于滚动电传打字例程,然后 AL 每次加载一个字节以显示 执行之前INT 0x10 指令。

在一些简单的注释伪代码中:

#AH=0x0e is the scrolling teletype BIOS routine when used with int 10h.
AH := 0x0e

#AL is the byte to display.
AL := 'H'

#Execute the scrolling teletype BIOS routine (AH=0x0e), displaying 'H' (AL='H').
INT 0x10

虽然 Chrono 给了你一个答案,但我不太确定它是否能回答你的问题。您似乎在问为什么评论说的是一回事而代码似乎做的是另一回事。

基本前缀和后缀

几十年前,很多参考资料 material 和一些反汇编程序使用与您今天可能看到的略有不同的默认符号来表示十进制、十六进制、八进制和二进制基数。他们将基数指定为值的最后一个字符(后缀)。常见的后缀有:

b = binary    10101010b      (decimal 170)    base 2
d = decimal   170d           (decimal 170) \  both d and t mean base 10 
t = decimal   170t           (decimal 170) /
h = hex       0AAh           (decimal 170)    base 16
o = octal     252o           (decimal 170)    base 8

如果一个数字不包含字母字符,则假定它是以 10 为基数的十进制。所以这也适用:

no alphabetic character      170             decimal   170

大多数汇编器会接受这些后缀中的大部分,但它们也会支持将基数定义为前缀。如果值不以字母字符结尾,而是以 0 后跟一个字母开头,则该字母表示基数。常见的前缀基础是:

b = binary    0b10101010     (decimal 170)    base 2
d = decimal   0d170          (decimal 170) \  both d and t mean base 10 
t = decimal   0t170          (decimal 170) /
h = hex       0xAA           (decimal 170)    base 16
o = octal     0o252          (decimal 170)    base 8

大多数现代汇编器都支持指定为前缀或后缀的形式。某些汇编器可能不支持某些前缀和后缀,例如 t

如果您指定带有前缀 base 的数字,则在整个文件中坚持使用前缀。如果您指定带有后缀基数的数字,则在整个文件中坚持使用后缀。你可以把它们混在一起,但最好在一个文件中保持一致。

解释 int 10/ah = 0eh

这是什么意思:

int 10/ ah = 0eh -> scrolling teletype BIOS routine
  • int 10 不包含字母,因此它是 十进制 10(或 十六进制 a ).
  • 0eh 以字母结尾,不以 0 和字母开头,因此 h 是后缀。 h表示十六进制。所以0eh十六进制0e(或者十进制14)。

如果将其放入 BIOS 的汇编代码中,它看起来像(使用十六进制后缀):

mov ah, 0eh      ; Decimal 14
int 0ah          ; Decimal 10. The 0 in front makes sure the assembler knows we don't mean register ah! 

使用前缀(本例中为十六进制):

mov ah, 0xe      ; Decimal 14
int 0xa          ; Decimal 10 

或者如果你想使用十进制(没有前缀或后缀):

mov ah, 14       ; Decimal 14
int 10           ; Decimal 10

但是您现在可能会说 嘿等等! 那是 错误的 因为 BIOS 视频中断是 0x10 (或者16十进制)你是对的!我们刚刚了解到 评论是错误的 或者充其量 非常 模棱两可。评论应该说:

int 10h / ah = 0eh -> scrolling teletype BIOS routine

您不妨联系评论/代码的作者,让他们知道他们的评论不准确。他们写的代码是正确的。

如果汇编程序支持它们,我更喜欢前缀 0x0b0o 而不是后缀 hbo 因为某些后缀可能构成寄存器名称,或其他标识符和符号。使用后缀时,如果您有一个必须以字母开头的值(即:十六进制的 A 到 F),请在开头添加 0,让汇编器知道您代表的是一个值。例如 AAh 必须写成 0AAh,而 Bh 必须写成 0Bh.