扩展汇编语法在实模式下调用 bios 服务的困难
Difficulties with extended assembly syntax to call a bios service in real mode
我正在编写引导加载程序,引导扇区已经移交给第二阶段。从现在开始,我将使用 C 语言进行编程,而不是使用 x86 汇编语言进行所有编程。我的最终目标是制作比 u-boot 更简单但可以查看多重引导 header 并启动内核的东西。大部分操作都是在实模式下完成的。
我正在为这段代码苦苦挣扎。我的目标是等待击键并获取相应的 ASCII 字符被按下。
#include "keyboard.h"
char keyboard_getc(void)
{
char user_input;
wait_keystroke:
__asm__ __volatile__ goto ("clc;"
"movb %[bios_service], %%ah;"
"int [=10=]x16;"
"jnc %l[wait_keystroke];"
"movb %%al, %[char_input]"
: [char_input] "=rm" (user_input)
: [bios_service] "r" (0x00)
: "%ax", "cc"
: wait_keystroke
);
return user_input;
}
编译器如下侮辱我:
i386-elf-gcc -std=c99 -DDEBUG -O1 -c -g -march=i386 -m16 -ffreestanding -Wall -W -I../inc -o keyboard.o keyboard.c
keyboard.c: In function ‘keyboard_getc’:
keyboard.c:13:34: error: expected ‘:’ before ‘[’ token
: [char_input] "=rm" (user_input)
^
keyboard.c:7:1: warning: label ‘wait_keystroke’ defined but not used [-Wunused-label]
wait_keystroke:
^
make: *** [keyboard.o] Error 1
我尝试按照此文档进行操作 https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html 但我没有找到答案。
有人知道为什么吗?
Section 6.44.3.3 Goto Labels 在您链接的文档中说:
An asm goto statement cannot have outputs.
编译器错误试图告诉您这一点,尽管不是很清楚。
由于在这种情况下您不需要将标签放在 C 代码中,因此简单的解决方法是将其放入 asm 块中并使用普通的旧 goto
-less 内联 asm。为避免冲突,请使用本地标签。
PS:不需要mov
结果,可以使用"=a"
约束。 bios_service
也不需要是寄存器,您也不需要 clc
。这应该是您所需要的:
char keyboard_getc(void)
{
char user_input;
__asm__ __volatile__("1: movb %[bios_service], %%ah;"
"int [=10=]x16;"
"jnc 1b;"
: "=a" (user_input)
: [bios_service] "i" (0x00)
: "cc"
);
return user_input;
}
谢谢杰斯特的好建议。最后,我试图实现的代码如下:
char keyboard_getc(void)
{
char user_input;
__asm__ __volatile__("wait_keystroke: movb %[bios_service_wait_key_stroke], %%ah;"
"int [=10=]x16;"
"jc wait_keystroke;"
"movb %[bios_service_read_buffer], %%ah;"
"int [=10=]x16;"
: "=a" (user_input)
: [bios_service_wait_key_stroke] "i" (0x01),
[bios_service_read_buffer] "i" (0x00)
: "cc"
);
return user_input;
}
我正在编写引导加载程序,引导扇区已经移交给第二阶段。从现在开始,我将使用 C 语言进行编程,而不是使用 x86 汇编语言进行所有编程。我的最终目标是制作比 u-boot 更简单但可以查看多重引导 header 并启动内核的东西。大部分操作都是在实模式下完成的。
我正在为这段代码苦苦挣扎。我的目标是等待击键并获取相应的 ASCII 字符被按下。
#include "keyboard.h"
char keyboard_getc(void)
{
char user_input;
wait_keystroke:
__asm__ __volatile__ goto ("clc;"
"movb %[bios_service], %%ah;"
"int [=10=]x16;"
"jnc %l[wait_keystroke];"
"movb %%al, %[char_input]"
: [char_input] "=rm" (user_input)
: [bios_service] "r" (0x00)
: "%ax", "cc"
: wait_keystroke
);
return user_input;
}
编译器如下侮辱我:
i386-elf-gcc -std=c99 -DDEBUG -O1 -c -g -march=i386 -m16 -ffreestanding -Wall -W -I../inc -o keyboard.o keyboard.c
keyboard.c: In function ‘keyboard_getc’:
keyboard.c:13:34: error: expected ‘:’ before ‘[’ token
: [char_input] "=rm" (user_input)
^
keyboard.c:7:1: warning: label ‘wait_keystroke’ defined but not used [-Wunused-label]
wait_keystroke:
^
make: *** [keyboard.o] Error 1
我尝试按照此文档进行操作 https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html 但我没有找到答案。
有人知道为什么吗?
Section 6.44.3.3 Goto Labels 在您链接的文档中说:
An asm goto statement cannot have outputs.
编译器错误试图告诉您这一点,尽管不是很清楚。
由于在这种情况下您不需要将标签放在 C 代码中,因此简单的解决方法是将其放入 asm 块中并使用普通的旧 goto
-less 内联 asm。为避免冲突,请使用本地标签。
PS:不需要mov
结果,可以使用"=a"
约束。 bios_service
也不需要是寄存器,您也不需要 clc
。这应该是您所需要的:
char keyboard_getc(void)
{
char user_input;
__asm__ __volatile__("1: movb %[bios_service], %%ah;"
"int [=10=]x16;"
"jnc 1b;"
: "=a" (user_input)
: [bios_service] "i" (0x00)
: "cc"
);
return user_input;
}
谢谢杰斯特的好建议。最后,我试图实现的代码如下:
char keyboard_getc(void)
{
char user_input;
__asm__ __volatile__("wait_keystroke: movb %[bios_service_wait_key_stroke], %%ah;"
"int [=10=]x16;"
"jc wait_keystroke;"
"movb %[bios_service_read_buffer], %%ah;"
"int [=10=]x16;"
: "=a" (user_input)
: [bios_service_wait_key_stroke] "i" (0x01),
[bios_service_read_buffer] "i" (0x00)
: "cc"
);
return user_input;
}