Ядро в 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.cobjcopy -O binary versuch.o versuch.bincat bootloader.bin versuch.bin>myOS.binqemu-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,0x1000xor 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 -ffreestandingld -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?

Другие вопросы по тегам