Ядро в c встроенной сборки
Привет, у меня снова проблема, я пытаюсь написать ядро на языке ассемблера GNU, но у меня есть некоторые проблемы. Мой файл ядра versuch.c
выглядеть так:
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");
}`
и мой загрузчик 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
когда я использую команды:gcc -c versuch.c
objcopy -O binary versuch.o versuch.bin
cat bootloader.bin versuch.bin>myOS.bin
qemu-system-i386 myOS.bin
Вы можете видеть, что он запускается через загрузчик до конца и выводит "soweit so gut", но не отображает текст versuch.c(kernel) "hallo". Может кто знает что я тут не так сделал!
Дело в том, что код ядра, который у меня был до этого, был слегка изменен на код выше, по крайней мере, напечатал символ после "soweit so gut", который показывает, что код ядра каким-то образом был выполнен
mov $0xe,%ah
mov $0x0,%bh
int $0x10
был запущен. Но когда я смотрю на hexcode из myOS.bin сейчас через objdump -Mi8086 -mi386 -bbinary -D myOS.bin
я получил:
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
какой mov ah,0x1000
xor bx,bx
чтение с диска часть загрузчика и
60: e9 9d 83 68 65 jmp 0x65688402
какой jmp 0x10000
часть и
27d: b4 0e mov $0xe,%ah
27f: b7 00 mov $0x0,%bh
281: cd 10 int $0x10
которая является записывающей частью, так или иначе, она должна перекрывать записывающую часть, но она находится в файле myOS.bin. И, как я сказал, когда мой код немного отличался от строки, он что-то выдал! Есть ли у вас какие-либо советы, что я мог бы изменить?
Я недавно изменил свой код ядра на versuch.c, а команда и код загрузчика остались прежними.
код ядра (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");
}
теперь он, кажется, переключается в режим видео, показывая мигающий курсор, но он не печатает 'Q'.
я наконец-то получил распечатать письмо со следующим кодом ядра: 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");
}
но когда я добавляю другую функцию, она снова не работает, что действительно странно.
Мой новый код ядра выглядит так:
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");
}
я использовал следующие команды:gcc kernel.c -m16 -c kernel.o -nostdlib -ffreestanding
ld -melf_i386 kernel.o -o versuch.elf
и я использую 64-битную машину Mint Linux, и я получаю сообщение об ошибке:no eh_frame_hdr_table will be created
1 ответ
Какой компилятор C вы используете?
32-битный или даже 64-битный компилятор?
(Потому что вы просто используете gcc
а не как то x86-16bit-gcc
Я думаю, что вы используете 32-битный или 64-битный компилятор.)
Это не сработает - вам придется переключиться в защищенный режим, чтобы иметь возможность запускать 32-битный код. Запуск 64-битного кода еще сложнее.
Даже когда вы используете "только" встроенную сборку, сам компилятор добавляет некоторые инструкции - и они являются 32-битными или 64-битными инструкциями!
Или вы действительно используете 16-битный компилятор?
В этом случае вам нужно быть очень осторожным: какую модель памяти вы используете и какие у нее побочные эффекты?
Пример: с использованием "близкой" модели памяти строка:
video=(char*)0xb8000;
... усечет адрес 0xb8000 до 16-битного значения (0x8000).
При использовании "далекой" модели памяти большинство компиляторов обычно воспринимают 0xb8000 как 0x000b:0x8000 (что соответствует линейному адресу 0x13000). Для этих компиляторов значение 0xb8000000 должно использоваться для доступа к 0xb800:0x0000 (линейный адрес 0xB8000).
С помощью objcopy
следующая строка определенно не будет работать:
kprintf(hello);
Причина в том, что компилятор внутренне будет делать что-то вроде этого:
kprintf((char *)0x12345);
0x12345 - это адрес, где хранится строка "привет". Однако этот адрес пока неизвестен, когда программа компилируется.
По этой причине объектный файл содержит некоторую информацию о том, что число 0x12345 должно быть заменено реальным адресом строки позже. Компоновщик сделает это, когда вы связываете программу. С помощью objcopy
однако эта информация просто теряется, и число остается 0x12345.
Кстати:
Ваша программа содержит строку:
jmp 0x1000:0x000
Почему вы думаете, что это место main
?