2016-12-18 3 views
0

Hallo, ich habe wieder einmal ein Problem Ich versuche, einen Kernel mit der GNU-Assemblersprache zu schreiben, aber ich habe ein paar Probleme. Meine Kernel-Datei versuch.c sehen wie folgt aus:Kernel in c Inline-Assembly

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"); 
}` 

und mein 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 

Wenn ich die Befehle: gcc -c versuch.c objcopy -O binary versuch.o versuch.bin cat bootloader.bin versuch.bin>myOS.bin qemu-system-i386 myOS.bin können Sie sehen, dass es läuft durch der Bootloader bis zum Ende druckt "soweit so gut" aus aber es zeigt nicht den versuch.c (kernel) Text "hallo". Vielleicht weiß jemand, was ich hier falsch gemacht habe!

Die Sache ist die, dass der Kernel-Code i vor dem hatte, war nur leicht ein Zeichen über zumindest ausgedruckt nach „soweit so gut“, um den Code geändert, die zeigt, dass die Code-Kernel irgendwie ausgeführt wurde und

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

wurde ausgeführt. Aber wenn ich am hexcode von myOS.bin nun einen Blick über objdump -Mi8086 -mi386 -bbinary -D myOS.bin i erhalten:

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 

, die die mov ah,0x1000xor bx,bx Plattenlese Teil des Bootloader ist und

60: e9 9d 83 68 65   jmp 0x65688402 

die der jmp 0x10000 Teil ist und

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

was der schreibende Teil ist, also muss es irgendwie den schreibenden Teil überspringen, aber es ist in der myOS.bin Datei. Und wie gesagt, als mein Code mit der Zeichenkette nur geringfügig anders war, hat er etwas ausgegeben! Hast du einen Ratschlag, was ich hätte ändern können?

Ich habe kürzlich meinen Kernel-Code versuch.c geändert, während der Befehl und der Bootloader-Code unverändert bleiben.

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"); 
} 

jetzt scheint es auf den Videomodus zu wechseln ein blinkender Cursor zeigt aber es tut out 'Q' drucken.

Ich habe endlich einen Brief mit folgendem Kernel-Code drucken: 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"); 
} 

aber wenn ich hinzufügen, eine andere Funktion ist es nicht mehr, dass wirklich seltsam arbeiten.

Mein neuer Kernel-Code sieht wie folgt aus:

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 die folgenden Befehle verwendet: gcc kernel.c -m16 -c kernel.o -nostdlib -ffreestanding ld -melf_i386 kernel.o -o versuch.elf und ich bin mit Mint Linux 64-Bit-Maschine und ich bekomme die Fehlermeldung: no eh_frame_hdr_table will be created

+0

Kommentare sind nicht für längere Diskussionen; Diese Konversation wurde [in den Chat verschoben] (http://chat.stackoverflow.com/rooms/130996/discussion-on-question-by-albert-kernel-in-c-inline-assembly). – Flexo

Antwort

2

Welchen C-Compiler benutzen Sie?

Ein 32-Bit- oder sogar ein 64-Bit-Compiler?

(Weil Sie einfach gcc verwenden und nicht so etwas wie x86-16bit-gcc Ich glaube, Sie verwenden eine 32-Bit oder 64-Bit-Compiler.)

Das wird nicht funktionieren - Sie werden zu geschützten Modus wechseln haben, um 32-Bit-Code ausführen zu können. Das Ausführen von 64-Bit-Code ist noch schwieriger.

Auch wenn Sie "nur" Inline-Assembly verwenden, fügt der Compiler selbst einige Anweisungen hinzu - und das sind 32-Bit- oder 64-Bit-Anweisungen!

Oder verwenden Sie wirklich einen 16-Bit-Compiler?

In diesem Fall müssen Sie sehr vorsichtig sein: Welches Speichermodell verwenden Sie und welche Nebenwirkungen haben diese?

Beispiel: Ein "in der Nähe" Speichermodell das Zeile:

video=(char*)0xb8000; 

... wird die Adresse 0xb8000 auf einen 16-Bit-Wert (0x8000) trunkieren.

Mit einem "fernen" Speichermodell jedoch wird 0xb8000 normalerweise als 0x000b: 0x8000 (was der linearen Adresse 0x13000 entspricht) von meisten Compilern gesehen. Für diese Compiler muss der Wert 0xb8000000 verwendet werden, um auf 0xb800: 0x0000 (lineare Adresse 0xB8000) zuzugreifen.

Mit objcopy die folgende Zeile wird auf jeden Fall nicht:

kprintf(hello); 

Der Grund dafür ist, dass der Compiler so etwas wie dies intern zu tun:

kprintf((char *)0x12345); 

0x12345 ist die Adresse, wo die Zeichenfolge " hallo "ist gespeichert. Diese Adresse ist jedoch noch nicht bekannt, wenn das Programm kompiliert wird.

Aus diesem Grund enthält die Objektdatei einige Informationen darüber, dass die Nummer 0x12345 später durch die reale Adresse der Zeichenfolge ersetzt werden muss. Der Linker wird dies tun, wenn Sie ein Programm verknüpfen. Mit objcopy jedoch ist diese Information einfach verloren und die Nummer bleibt 0x12345.

By the way:

Ihr Programm enthält die Zeile:

jmp 0x1000:0x000 

Warum denken Sie, dass dies die Lage von main ist?

+0

es weiß etwas wierd Charakter anstelle von "hallo" ist ein 65-Bit-Compiler – albert

+0

64-Bit-Compiler – albert

+1

Sie können versuchen, Ihren Code zu zerlegen, um zu sehen, was wirklich gemacht wird: 'objdump -Mi8086 -mi386 -bbinary -D versuch.bin '. Dann können Sie sehen, wie der vom 64-Bit-Compiler generierte Code wirklich aussieht ... –