0

I am programming a boot loader, the boot sector has already handed over to the second stage. From now on, I am programming in C instead of programming everything in x86 assembly. My final goal is to make something simpler than u-boot but something that can look at the multiboot header and launch the kernel. Most of the operation are done in real mode.

I am struggling with this piece of code. I aim at waiting a key stroke and getting the corresponding ASCII char that was pressed.

#include "keyboard.h"

char keyboard_getc(void)
{
    char user_input;

wait_keystroke:
    __asm__ __volatile__ goto ("clc;"
                               "movb %[bios_service], %%ah;"
                               "int $0x16;"
                               "jnc %l[wait_keystroke];"
                               "movb %%al, %[char_input]"
                               : [char_input] "=rm" (user_input)
                               : [bios_service] "r" (0x00)
                               : "%ax", "cc"
                               : wait_keystroke
                               );

   return user_input;
}

The compiler is insulting me as below :

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

I tried to follow this documentation https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html but I didn't find the answer.

Does somebody have an idea why ?

Matthieu
  • 3
  • 2

2 Answers2

1

Section 6.44.3.3 Goto Labels in the documentation you linked says:

An asm goto statement cannot have outputs.

The compiler error is trying to tell you that, albeit not in a very clear way. Since in this case you don't need the label to be in the C code, the simple fix is to put it into the asm block and use plain old goto-less inline asm. To avoid collisions, use a local label.

PS: you don't need to mov the result, you can use an "=a" constraint. The bios_service doesn't need to be a register either, and you don't need the clc. This should be all you need:

char keyboard_getc(void)
{
    char user_input;

    __asm__ __volatile__("1: movb %[bios_service], %%ah;"
                               "int $0x16;"
                               "jnc 1b;"
                               : "=a" (user_input)
                               : [bios_service] "i" (0x00)
                               : "cc"
                               );

   return user_input;
}
Jester
  • 56,577
  • 4
  • 81
  • 125
0

Thanks for your good advice Jester. Finally, the code I was trying to implement is the following :

char keyboard_getc(void)
{
    char user_input;

    __asm__ __volatile__("wait_keystroke: movb %[bios_service_wait_key_stroke], %%ah;"
                         "int $0x16;"
                         "jc wait_keystroke;"
                         "movb %[bios_service_read_buffer], %%ah;"
                         "int $0x16;"
                         : "=a" (user_input)
                         : [bios_service_wait_key_stroke] "i" (0x01),
                           [bios_service_read_buffer] "i" (0x00)
                         : "cc"
                         );

    return user_input;
}
Matthieu
  • 3
  • 2