Search code examples
cassemblyinline-assemblybcc-compiler

Inline Assembly in BCC (Bruce's C Compiler) - How to use C variables?


I'm writing a C program under Real Mode. The program will be loaded to 0x2000:0x0000 address and run. DS register equals to CS, which is 0x2000. Also I'm debugging with bochs.

My goal is to print some text on the screen. So that I need inline assembly (for BIOS INT 10h).

Here is my test file:

asm("jmp _main");

void putchar(c) char c;
{
    asm("mov ah, 0x0e");
    asm("mov al, c");
    asm("xor bx, bx");
    asm("int 0x10");
}

void main ()
{
    asm("push cs");
    asm("pop ds");
    putchar('A');
    for(;;);
}

When I compiled it with this command...

bcc -W -0 -c test.c -o test.obj

...it's working. But when I'm trying to link it with...

ld86 -d isimsiz.obj -o kernel.bin

...it gave me this error:

undefined symbol: c

Why is this happening? How can I use C variables under BCC In-Line Assembly?

If you know a good tutorial about BCC, please leave a link. I couldn't find it on the internet :(

Thanks in advance.

PS: Here are the man pages of the respective compiler BCC and linker LD86.


Solution

  • bcc doesn't support referring to C variables. You need to write the whole function in assembly:

    void putchar(c)
    {
    #asm
         mov ah, 0x0e
         mov bx, sp
         mov al, [bx+2]
         xor bx, bx
         int 0x10
    #endasm
    }
    

    You might also want to check if __FIRST_ARG_IN_AX__ is defined:

    void putchar(c)
    {
    #asm
         mov ah, 0x0e
    #if !__FIST_ARG_IN_AX__
         mov bx, sp
         mov al, [bx+2]
    #endif
         xor bx, bx
         int 0x10
    #endasm
    }
    

    Note that in K&R-style functions, function parameters can't have types narrower than int, so while void putchar(c) char c; is syntactically correct, you can't do that. Incidentally, this is why the libc function putchar takes an argument of type int.

    If you really need to use variables, consider using a global variable:

    unsigned equipment;
    int has_floppy() {
    #asm
        int 0x11 ! get BIOS equipment list
        mov _equipment,ax
    #endasm
    
        return (_equipment & 1);
    }
    }
    

    You can look at the dev86 libc for examples on inline assembly in bcc.