在 BIOS 级程序集中读取输入?

Reading Input in BIOS-Level Assembly?

我正在创建一个非常低级的应用程序,并且我已经准备好引导加载程序。我基本上必须重建 scanf() 函数,因为我不能在项目中使用任何库。可以读取输入的 Assembly 基本应用程序是什么?我可以处理将它读入 C char[] 或我想要的任何其他数据类型,我只需要弄清楚如何在没有任何系统调用的情况下读取输入。

看来您正在为实模式编写代码。你没有说你正在使用哪个 C 编译器,但你自己的回答表明你实际上处于实模式。我推荐 WATCOM's C compiler as it can generate true 16-bit code. If you are using GCC with the -m16 option I don't recommend it for 16-bit code. I have another Whosebug answer that discusses some .

DOS和BIOS中断信息的最佳来源Ralph Brown's Interrupt List. The information about getting a single keystroke via Int 16h/AH=00是:

KEYBOARD - GET KEYSTROKE

AH = 00h

Return:

AH = BIOS scan code
AL = ASCII character

此 BIOS 功能不会回显字符,因此另一个有用的 BIOS 功能是 Int 10h/AH=0eh 正在向终端显示单个字符:

VIDEO - TELETYPE OUTPUT

AH = 0Eh
AL = character to write
BH = page number
BL = foreground color (graphics modes only)

Return:

Nothing

Desc: Display a character on the screen, advancing the cursor and scrolling the screen as necessary

要在文本模式下打印一个字符,您可以将 BX 放入 0,即要在 AL 中打印的字符并调用中断。


使用上面的信息,您可以使用内联汇编围绕两个 BIOS 中断编写一些简单的包装器。在 GCC 中,您可以使用 Extended Inline Assembly templates。它们可能看起来像这样:

#include <stdint.h>

static inline void
printch (char outchar, uint16_t attr)
{
   __asm__ ("int [=14=]x10\n\t"
            :
            : "a"((0x0e << 8) | outchar),
              "b"(attr));
}

static inline char
getch (void)
{
   uint16_t inchar;

   __asm__ __volatile__ ("int [=14=]x16\n\t"
            : "=a"(inchar)
            : "0"(0x0));

   return ((char)inchar);
}

Watcom C 中,您可以使用 #pragma aux 创建函数:

#include <stdint.h>

void printch(char c, uint16_t pageattr);
char getch(void);

#pragma aux printch = \
    "mov ah, 0x0e" \
    "int 0x10" \
     parm [al] [bx] nomemory \
     modify [ah] nomemory

#pragma aux getch = \
    "xor ah, ah" \
    "int 0x16" \
     parm [] nomemory \
     modify [ah] nomemory \
     value [al]

使用这些基本函数,您只需编写一个函数,从用户那里获取字符串,在输入字符时回显字符,并将它们存储在缓冲区中。换行符的 ASCII 字符 getch returns 是 回车符 return \r (0x0d)。当我们达到请求的最大字符数或遇到换行符时,我们停止并使用 NUL 终止字符串。这样的函数可能如下所示:

/* Get string up to maxchars. NUL terminate string.
   Ensure inbuf has enough space for NUL.
   Carriage return is stripped from string.
   Return a pointer to the buffer passed in.
*/
char *getstr_echo(char *inbuf, int maxchars)
{
    char *bufptr = inbuf;

    while(bufptr < (inbuf + maxchars) && (*bufptr = getch()) != '\r')
        printch(*bufptr++, 0);

    *bufptr = '[=16=]';
    return inbuf;
}

如果您不想使用内联汇编,您可以创建一个汇编模块,其中 getchprintch 在纯汇编中完成。这比使用内联汇编生成的代码效率低,但更不容易出错。


getstr_echo 函数功能不完整,可用作您自己代码的起点。它不能正确处理 backspace.

之类的事情