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
What C compiler do you use?
A 32-bit or even a 64-bit compiler?
(Because you simply use
gcc
and not something likex86-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:
... 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:The reason is that the compiler will internally do something like this:
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:
Why do you think that this is the location of
main
?