kernel in c inline assembly

560 views Asked by At

Hi i have once again a problem i try to write a kernel with the GNU assembly language but i have some trouble. My kernel file versuch.c look like that:

 void kprintf( char hello[])
   {
   /*char* video=(char*)0xb8000;
 for(int i=0;hello[i]!='\0';i++)
{
    video[i*2]=hello[i];

    video[i*2+1]=0x06;

}*/
    asm("mov %0,%%si"::""(hello));
    //asm("mov 'a',%al;");
    asm("call Schreibe;"    
        "Schreibe:;"
        "lodsb;"
        "cmp $0x00,%al;"
        "je Schreibeende;"
        "mov $0x0e,%ah;"
        "mov $0x00,%bh;"
        "int $0x10;"
        "jmp Schreibe;"
        "Schreibeende:;"
        "ret");

}

void main()
{
    asm("jmp    0x10000");
    char hello[]="hallo";
    kprintf(hello);
    asm(".rept 512;"
        " hlt ;"
        ".endr");
}`

and my bootloader bootloader.asm:

org 0x7c00
bits    16



    section .text

xor ax,ax
mov ss,ax
xor sp,sp

;xor ax,ax
;mov es,ax 
;mov ds,ax


mov [bootdrive],dl


mov bh,0
mov bp,zeichen

mov ah,13h
mov bl,06h
mov al,1
mov cx,6
mov dh,010h
mov dl,01h

int 10h

load:
mov dl,[bootdrive]
xor ah,ah
int 13h
jc load

load2:
mov ax,0x1000
mov es,ax
xor bx,bx

mov ah,2
mov al,1
mov cx,2
xor dh,dh

mov dl,[bootdrive]
int 13h
jc load2


mov ax,0
mov es,ax

mov bh,0
mov bp,zeichen3

mov ah,13h
mov bl,06h
mov al,1
mov cx,13
mov dh,010h
mov dl,01h

int 10h

mov ax,0x1000
mov es,ax
mov ds,ax
jmp 0x1000:0x000

zeichen db  'hello2'
zeichen3 db 'soweit so gut'
bootdrive db 0
times   510 - ($-$$)    hlt
dw  0xaa55

when i use the commands: gcc -c versuch.c objcopy -O binary versuch.o versuch.bin cat bootloader.bin versuch.bin>myOS.bin qemu-system-i386 myOS.bin you can see that it runs through the bootloader to the end printing out "soweit so gut" but it doesnt display the versuch.c(kernel) text "hallo". Maybe someone knows what i did wrong here!

The thing is that the kernel code i had before which was just slightly changed to the code above at least printed out a character after "soweit so gut" which shows that the kernel code was somehow executed and

mov $0xe,%ah
mov $0x0,%bh
int $0x10

was run. But when i look at the hexcode from myOS.bin now via objdump -Mi8086 -mi386 -bbinary -D myOS.bin i get:

 28:    b8 00 10 8e c0          mov    $0xc08e1000,%eax
  2d:   31 db                   xor    %ebx,%ebx
  2f:   b4 02                   mov    $0x2,%ah
  31:   b0 01                   mov    $0x1,%al
  33:   b9 02 00 30 f6          mov    $0xf6300002,%ecx
  38:   8a 16                   mov    (%esi),%dl
  3a:   76 7c                   jbe    0xb8
  3c:   cd 13                   int    $0x13

which is the mov ah,0x1000 xor bx,bx disk reading part of the bootloader and

60: e9 9d 83 68 65          jmp    0x65688402

which is the jmp 0x10000 part and

 27d:   b4 0e                   mov    $0xe,%ah
 27f:   b7 00                   mov    $0x0,%bh
 281:   cd 10                   int    $0x10

which is the writing part, so somehow it must overjump the writing part but it is in the myOS.bin file. And as i said when my code was just slightly different with the string, it did put out something! Do you have any advice what i could have changed?

i recently changed my kernel code versuch.c while the command and the bootloader code remains the same.

kernel code(versuch.c):

void kprintf()
{
    char* video=(char*)0xb8000;
    for(int i=0;video[i]!=0;i++)
    {
        video[i*2]=0x00;
        video[i*2+1]=0x06;
    }
}
void main()
{
    asm("jmp    0x10000");
    asm("mov    $0x1000,%eax;"
        "mov    %eax,%es;"
        "mov    %eax,%ds");
    asm("mov    $0x0e,%ah;"
        "mov    $0x00,%bh;"
        "mov    'Q',%al;"
        "int $0x10");
    asm(".rept 512;"
        " hlt ;"
        ".endr");
}

now it seems to switch to the video mode showing a blinking cursor but it doesnt print out 'Q'.

i finally got to print a letter with the following kernel code: versuch.c:

void kprintf()
{
    char* video=(char*)0xb8000;
    for(int i=0;video[i]!=0;i++)
    {
        video[i*2]=0x00;
        video[i*2+1]=0x06;
    }
}
void main()
{
    asm("jmp    0x10000");
    asm("mov    $0x1000,%eax;"
        "mov    %eax,%es;"
        "mov    %eax,%ds");
    asm("mov $0x0e,%ah");
    asm("mov $0x00,%bh");
    asm("mov %0,%%al":: "" ('T'));
    asm("int $0x10");
    asm(".rept 512;"
        " hlt ;"
        ".endr");
}

but when i add another function its not working again that really strange.

My new kernel code looks like this:

asm("jmp main");



void main()
{
    char* video=(char*)0xb000;
    for(int i=0;video[i]!=0;i++)
        video[i]=0x07;
    asm("mov    $0x1000,%eax;"
        "mov    %eax,%es;"
        "mov    %eax,%ds");
    char string[]="hall0";
    //kprintf(string);
    for(int i=0;i<5;i++)
    {

    asm("mov $0x0e,%ah");
    asm("mov $0x00,%bh");
    asm("mov %0,%%al":: "" ('a'));
    asm("int $0x10");
    }

    asm(".rept 512;"
        " hlt ;"
        ".endr");
}

i used the following commands: gcc kernel.c -m16 -c kernel.o -nostdlib -ffreestanding ld -melf_i386 kernel.o -o versuch.elf and i am using Mint Linux 64 bit machine and i get the error message: no eh_frame_hdr_table will be created

1

There are 1 answers

12
Martin Rosenau On

What C compiler do you use?

A 32-bit or even a 64-bit compiler?

(Because you simply use gcc and not something like x86-16bit-gcc I think you use a 32-bit or 64-bit compiler.)

This won't work - you'll have to switch to protected mode to be able to run 32-bit code. Running 64-bit code is even more difficult.

Even when you use "only" inline assembly the compiler itself will add some instructions - and they are 32-bit or 64-bit instructions!

Or do you really use a 16-bit compiler?

In this case you'll have to be very careful: Which memory model do you use and what side effects do this have?

Example: Using a "near" memory model the line:

video=(char*)0xb8000;

... will truncate the address 0xb8000 to a 16-bit value (0x8000).

Using a "far" memory model however 0xb8000 is typically seen as 0x000b:0x8000 (which is equal to the linear address 0x13000) by most compilers. For these compilers the value 0xb8000000 has to be used to access 0xb800:0x0000 (linear address 0xB8000).

Using objcopy the following line definitely won't work:

kprintf(hello);

The reason is that the compiler will internally do something like this:

kprintf((char *)0x12345);

0x12345 is the address where the string "hello" is stored. However this address is not known, yet, when the program is compiled.

For this reason the object file contains some information about the fact that the number 0x12345 must be replaced by the real address of the string later. The linker will do this when you link a program. Using objcopy however this information is simply lost and the number remains 0x12345.

By the way:

Your program contains the line:

jmp 0x1000:0x000

Why do you think that this is the location of main?