Problem mit Kompiler für OS



  • Hi Leute,
    ich habe mit vor kurzem den ersten Teil des Tutorials von Erhard Henkes durch gelesen. Nach mehr maligen lesen, ahbe ich auch alles mehr oder weniger verstanden. Die Beispiele habe ich dann auch ohne große Probleme in einer virtuellen Maschine zum laufen gebracht. Nun wollte ich mit Hilfe dieses Tutorials ein eigenes kleines OS auf die Beine stellen. So weit so gut. Als ich dann aber den CKernel kompilieren wollte, merkte ich dass djgpp unter meinem 64bit Vista nicht läuft. Es kommt dann immer so eine Meldung, dass die Anwendung nicht 64bit kompatible sei. Also habe ich es dann mit MinGW probiert. Das kompilieren klappte auch ohne Probleme. Aber dann kam es zu den Linkerproblemen, die ja auch im Tutorial erwähnt wurden und hier im Forum auch ohe Ergebniss disskutiert wurden. 😞
    Es muss doch auch noch andere Möglichkeiten geben, so ewtas zum laufen zu bekommen. Andere Tools, ... ich hoffe mir kann eienr helfen, würde das gelernte nämlich gerne mal ausprobieren.
    Ich bedanke mich schon mal im voraus für Hilfe.



  • Hobby Programmierer schrieb:

    Hi Leute,
    ich habe mit vor kurzem den ersten Teil des Tutorials von Erhard Henkes durch gelesen. Nach mehr maligen lesen, ahbe ich auch alles mehr oder weniger verstanden. Die Beispiele habe ich dann auch ohne große Probleme in einer virtuellen Maschine zum laufen gebracht. Nun wollte ich mit Hilfe dieses Tutorials ein eigenes kleines OS auf die Beine stellen. So weit so gut. Als ich dann aber den CKernel kompilieren wollte, merkte ich dass djgpp unter meinem 64bit Vista nicht läuft. Es kommt dann immer so eine Meldung, dass die Anwendung nicht 64bit kompatible sei. Also habe ich es dann mit MinGW probiert. Das kompilieren klappte auch ohne Probleme. Aber dann kam es zu den Linkerproblemen, die ja auch im Tutorial erwähnt wurden und hier im Forum auch ohe Ergebniss disskutiert wurden. 😞
    Es muss doch auch noch andere Möglichkeiten geben, so ewtas zum laufen zu bekommen. Andere Tools, ... ich hoffe mir kann eienr helfen, würde das gelernte nämlich gerne mal ausprobieren.
    Ich bedanke mich schon mal im voraus für Hilfe.

    http://www.nondot.org/sabre/os/articles/TheBootProcess/ da der erste Link "http://www.nondot.org/sabre/os/files/Booting/CompilingBinaryFilesUsingACompiler.pdf"


  • Mod

    Das kompilieren klappte auch ohne Probleme. Aber dann kam es zu den Linkerproblemen, die ja auch im Tutorial erwähnt wurden und hier im Forum auch ohe Ergebniss disskutiert wurden. 😞

    Oh, sorry. Das Problem (historische Entwicklung: aout --> coff --> elf) wurde inzwischen im zweiten Ansatz gelöst. Ich werde da eine Anmerkung machen (für die 64-Bit-Vista-Fraktion).
    http://www.henkessoft.de/OS_Dev/OS_Dev1.htm#mozTocId29572

    Das ist alles hier beschrieben:
    http://www.henkessoft.de/OS_Dev/OS_Dev2.htm#mozTocId42018

    Als Start verwendet man folgenden Bootloader und kernel.asm (nur noch 32 bit):

    bootloader:

    org 0x7C00  ; set up start address of bootloader
    
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ; setup a stack and segment regs ;
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    
        xor ax, ax
        mov ds, ax
        mov es, ax
        mov ss, ax
        mov sp, ax
    
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ; read kernel from floppy disk ;
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    
        mov [bootdrive], dl ; boot drive stored by BIOS in DL.
                            ; we save it to [bootdrive] to play for safety.
    
    load_kernel:
        xor ax, ax         ; mov ax, 0  => function "reset"
        int 0x13         
        jc load_kernel     ; trouble? try again
    
        mov bx, 0x8000     ; set up start address of kernel
    
        ; set parameters for reading function
        ; 8-bit-wise for better overview
        mov dl,[bootdrive] ; select boot drive
        mov al, 59         ; read n sectors
        mov ch,  0         ; cylinder = 0
        mov cl,  2         ; sector   = 2
        mov dh,  0         ; head     = 0
        mov ah,  2         ; function "read" 
        int 0x13         
        jc load_kernel     ; trouble? try again
    
        ; show loading message
        mov si,loadmsg
        call print_string
    	call Waitingloop
    
    ;;;;;;;;;;;;;
    ; A20-Gate  ;
    ;;;;;;;;;;;;;	
    
        in  al, 0x92      ; switch A20 gate via fast A20 port 92
        cmp al, 0xff      ; if it reads 0xFF, nothing's implemented on this port
        je .no_fast_A20
    
        or  al, 2         ; set A20_Gate_Bit (bit 1)
        and al, ~1        ; clear INIT_NOW bit (don't reset pc...)
        out 0x92, al
        jmp .A20_done
    
    .no_fast_A20:         ; no fast shortcut -> use the slow kbc...
        call empty_8042 
    
        mov al, 0xD1      ; kbc command: write to output port
        out 0x64, al
        call empty_8042
    
        mov al, 0xDF      ; writing this to kbc output port enables A20
        out 0x60, al
        call empty_8042
    
    .A20_done:
    
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ; Load GDT, switch to PM, and jump to kernel ;
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;		
    
        cli               ; clear interrupts
        lgdt [gdtr]       ; load GDT via GDTR (defined in file "gtd.inc")	
    
        mov eax, cr0      ; switch-over to Protected Mode
        or  eax, 1        ; set bit 0 of CR0 register
        mov cr0, eax      ;	
    
        jmp 0x8:0x8000    ; this is a 16-bit-FAR-Jmp, but CS is loaded with "index" 8 in GDT 
                          ; hence, the code will be interpreted as 32 bit from here on
    					  ; the address can be found in the linker script (phys)
    
    ;;;;;;;;;
    ; Calls ;
    ;;;;;;;;;
    
    print_string:
        mov ah, 0x0E      ; VGA BIOS fnct. 0x0E: teletype
    .loop:   
        lodsb             ; grab a byte from SI
        test al, al       ; NUL?
        jz .done          ; if the result is zero, get out
        int 0x10          ; otherwise, print out the character!
        jmp .loop
    .done:
        ret
    
    empty_8042:
        call Waitingloop
        in al, 0x64
        cmp al, 0xff      ; ... no real kbc at all?
        je .done
    
        test al, 1        ; something in input buffer?
        jz .no_output
        call Waitingloop
        in al, 0x60       ; yes: read buffer
        jmp empty_8042    ; and try again
    
    .no_output:
        test al, 2        ; command buffer empty?
        jnz empty_8042    ; no: we can't send anything new till it's empty
    .done:
    ret
    
    Waitingloop:                   
        mov cx,0xFFFF
    .loop_start:
        dec cx     
        jnz .loop_start
        ret       
    
    ;;;;;;;;;;;;
    ; Includes ;
    ;;;;;;;;;;;;
    
    %include "gdt.inc"
    
    ;;;;;;;;
    ; data ;
    ;;;;;;;;
    
        bootdrive db 0    ; boot drive
        loadmsg db "bootloader message: loading kernel ...",13,10,0
    
        times 510-($-$$) hlt
        db 0x55
        db 0xAA
    

    kernel.asm:

    [Bits 32]
    section .text          ; ld needs that for coff format
    
    [global KernelStart]
    KernelStart:
        mov    ax, 0x10
        mov    ds, ax      ; data descriptor --> data, stack and extra segment
        mov    ss, ax           
        mov    es, ax
        xor    eax, eax    ; null desriptor --> FS and GS
        mov    fs, ax
        mov    gs, ax
        mov    esp, 0x200000 ; set stack below 2 MB limit
    
    [extern _main]         ; entry point in ckernel.c
    	call _main ; ->-> C-Kernel
        jmp $
    

    Ab dann geht es mit dem C-Kernel weiter. 👍

    makefile:

    SOURCES = kernel.asm $(filter-out boot.asm kernel.asm ,$(wildcard *.asm *.c))
    OBJECTS = $(addsuffix .o,$(basename $(SOURCES)))
    
    ASFLAGSBIN= -O32 -f bin
    ASFLAGSOBJ= -O32 -f elf
    NASM = nasmw
    
    CFLAGS=	-O -ffreestanding -fleading-underscore    
    CC= i586-elf-gcc
    
    LDFLAGS= -T kernel.ld -Map kernel.map -nostdinc
    LD= i586-elf-ld
    
    all: boot.bin ckernel.bin
    	make -s image	
    
    boot.bin: boot.asm
    	$(NASM) $(ASFLAGSBIN) $< -o $@
    
    %.o: %.asm
    	$(NASM) $(ASFLAGSOBJ) $< -o $@
    
    ckernel.bin: $(OBJECTS)
    	$(LD) $(LDFLAGS) $+ -o $@ 
    
    process.asm: initrd.img	
    
    image:
    	cmd /c copy /b boot.bin + ckernel.bin MyOS    
    	del *.o
    	del *.bin
    	cmd /c rename MyOS MyOS.bin
    
    #    $<		Erste Abhängigkeit
    #    $+		Liste aller Abhängigkeiten	
    #    $@		Name des Targets
    


  • Super. Dann werde ich das mal versuchen zum laufen zu bekommen. Danke!



  • Ich habe das jetzt mal versucht, aber ich weis nicht, wie ich das makefile aufrufen soll. Und eine kernel.map habe ich auch nicht. Und wie das Linkskript sein soll, weis ich auch nicht. Gibt es irgendwo eine Anleitung für "dumme"? Das mit dem kompilieren in der .bat Datei habe ich ja hinbekommen. Aber wie ich das jetzt mit dem makefile machen soll, weis ich leider nicht.


  • Mod

    Gibt es irgendwo eine Anleitung für "dumme"?

    Ich arbeite dran. 😉

    OK, das schaffst Du alles auf Dauer, ist in Summe leider nicht ganz unkompliziert, lohnt sich aber sich damit zu beschäftigen.

    Also das makefile muss an deine Situation angepasst werden (einiges weg lassen) und wird mit mingw32-make ab Version 3.81 aufgerufen:
    http://sourceforge.net/projects/mingw/files/

    make/makefile:
    http://www.c-howto.de/tutorial-makefiles.html
    http://www.ijon.de/comp/tutorials/makefile.html
    http://www.cs.umd.edu/class/spring2002/cmsc214/Tutorial/makefile.html

    Das Linkerskript kernel.ld sollte so aussehen:

    OUTPUT_FORMAT("binary")
    ENTRY(KernelStart)
    phys = 0x00008000;
    SECTIONS
    {
      .text phys  : {
        *(.text)
      }
      .data  : {
        *(.data)
      } 	
      .rodata  : {
        *(.rodata)
      }
      .bss  :  { 					
        *(.bss)
      }
    }
    

    ... ist übrigens das gleiche wie das hier:

    OUTPUT_FORMAT("binary")
    ENTRY(KernelStart)
    SECTIONS
    { 
      . = 0x00008000;
      .text   : { *(.text)   } 
      .data   : { *(.data)   } 	
      .rodata : { *(.rodata) }
      .bss    : { *(.bss)    }  
    }
    

    was ich "ordentlicher" finde.

    Linkerskript:
    http://tutorial.proggen.org/doku.php?id=kernel:tut:used_linkerscript
    http://www.henkessoft.de/OS_Dev/OS_Dev2.htm#mozTocId920304 (Ende des Kernels bestimmen)

    Das kernel.map wird automatisch erzeugt durch das makefile:
    LDFLAGS= -T kernel.ld -Map kernel.map
    Ist eine brauchbare Sache, da Du exakt siehst, wo etwas gelandet ist, also wie Dein Kernel im Speicher aufgebaut ist.

    Wenn Du nicht klar kommst, ziehst Du dir diese zip-Datei:
    http://www.henkessoft.de/OS_Dev/Downloads/20090703_61.zip
    ... und schaust Dir das alles genau an.

    Du hast hier jeweils auch in den User-Verzeichnissen makefiles.
    Das läuft so, dass im Verzeichnis user_program program.asm zu program.elf umgesetzt wird.
    Im Verzeichnis init_rd_img wird dieses Programm in initrd.img ins Filesystem eingebaut.
    Das Image initrd.img wird mittels "incbin" in den Kernel transferiert (siehe process.asm) und dort weiter verarbeitet (-> RAM Disk / VFS -> elf-exec-File laden und in den User-Bereich schieben).

    Falls Du Fragen hast helfe ich gerne weiter. 🙂



  • Ich habe mir jetzt folgende .bat Datei erstellt.

    SET PATH=C:\MinGW\bin;C:\msys\1.0\bin;C:\crosstools-complete\crosstools-complete\i586-elf\bin;C:\Programme\NASM;%PATH%
    mingw32-make makefile
    pause
    

    Und dieses Makefile

    SOURCES = kernel.asm $(filter-out boot.asm kernel.asm ,$(wildcard *.asm *.c))
    OBJECTS = $(addsuffix .o,$(basename $(SOURCES)))
    
    ASFLAGSBIN= -O32 -f bin
    ASFLAGSOBJ= -O32 -f elf
    NASM = nasmw
    
    CFLAGS=    -O -ffreestanding -fleading-underscore    
    CC= i586-elf-gcc
    
    LDFLAGS= -T kernel.ld -Map kernel.map -nostdinc
    LD= i586-elf-ld
    
    all: boot.bin ckernel.bin
    	make -s image     
    
    boot.bin: boot.asm
    	$(NASM) $(ASFLAGSBIN) $< -o $@
    
    %.o: %.asm
    	$(NASM) $(ASFLAGSOBJ) $< -o $@
    
    ckernel.bin: $(OBJECTS)
    	$(LD) $(LDFLAGS) $+ -o $@
    
    image:
    	cmd /c copy /b boot.bin + ckernel.bin MyOS    
    	del *.o
    	del *.bin
    	cmd /c rename MyOS MyOS.bin
    
    #    $<        Erste Abhängigkeit
    #    $+        Liste aller Abhängigkeiten   
    #    $@        Name des Targets
    

    Ansonsten habe ich noch boot.asm, kernel.asm und ckernel.c in meinem Ordner. Wenn ich jetzt aber die .bat Datei ausführe, meldet mingw32-make: Nothing to be done for 'makefile'. Was habe ich da falsch gemacht, bzw. nicht beachtet?


  • Mod

    Nothing to be done for 'makefile'.

    makefile ist im Gegensatz zu Batch-Dateien aufgabenorientiert. Bei Fehlern bricht es ab, und wenn alles schon besteht, macht es nichts und meldet dies.

    Zieldateien löschen, und schauen, ob diese erstellt werden.

    Übrigens sollte man - zumindest ab und zu - auch -Wall bei CCFLAGS einbauen, um zu sehen, was noch so an Ungereimtheiten existiert (manchmal z.B. UCHAR/CHAR).



  • Ich habe jetzt alle Sachen gelöscht, die er erstellen soll. Aber es kommt immer noch die selbe Meldung. Man muss doch aber die .c Dateien nicht selber kompilieren, oder?



  • Also so wie ich das gerade sehe, liegt es am "mingw32-make makefile".

    Versuch es mal so:

    SET PATH=C:\MinGW\bin;C:\msys\1.0\bin;C:\crosstools-complete\crosstools-complete\i586-elf\bin;C:\Programme\NASM;%PATH%
    mingw32-make
    pause
    

    Denn make öffnet das makefile im aktuellen Ordner ja eigentlich schon standardmäßig.


  • Mod

    Klappt's?



  • So, ich habe das von Deli1 mal ausprobiert. Scheint zu gehen, jetzt gibt es da nur noch irgendwelche Fehler, was das kompilieren mit nasm angeht, werde mich gleich mal darum kümmern, sobald ich etaws mehr weis, oder auch nicht, melde ich micht wieder.



  • So, das mit dem Assembler habe ich gelöst, war ein falscher Name schuld. Bei mir heißt er nämlich nasm und nicht nasmw. Jetzt häge ich gerade beim Kompilerproblem fest. Er meldet folgendes:

    process _begin: CreateProcess(NULL, i586-elf-gcc  -O -ffreestanding -fleading-unde
    rscore -c -o ckernel.o ckernel.c, ...) failed
    


  • So, irgendwie geht das jetzt, aber das makefile und die .bat verhalten sich noch etwas eigenartig. Da werde ich wohl noch mal dran arbeiten müssen. Aber immerhin bekomme ich jetzt mein HobbyOS.bin.

    EDIT: Seltsame Verahlten habe ih ihm gerade abgewöhnt. Als letztes will ich jetzt noch von C zu C++ umsteigen. Wenn das geht, poste ich hier mal das abgeänderte makefile


  • Mod

    Aber immerhin bekomme ich jetzt mein HobbyOS.bin.

    Gut!

    das makefile und die .bat verhalten sich noch etwas eigenartig.

    make/makefile ist ein mächtiges Gespann, aber es macht auf Dauer Spaß damit zu fahren. Dran bleiben. 👍
    Kaum hat man beim OSDEV eine Sache gelöst, steht die nächste Herausforderung ins Haus. Lieber erst mal einfach anfangen und kleine Ziele setzen.



  • a) Warum benutzt ihr Makefiles in einem neuen Projekt und nicht eine der moderneren Alternativen

    b) Wieso nicht die Autotools?



  • Das mit C++ habe ich verworfen, ist mir zu kompliziert. Ich benutzte jetzt nur C, ist ja sowie so die Standartsprache für OSDev.
    Hier nun meine .bat Datei und das komplette makefile. Ich hoffe, es wird irgendwem Helfen, der vielleicht das selbe Problem hat wie ich.
    Bat:

    SET PATH=C:\MinGW\bin;C:\crosstools-complete\crosstools-complete\bin;C:\Programme\NASM;%PATH%
    mingw32-make
    pause
    

    Makefile:

    SOURCES = kernel.asm $(filter-out boot.asm kernel.asm ,$(wildcard *.asm *.c))
    OBJECTS = $(addsuffix .o,$(basename $(SOURCES)))
    
    ASFLAGSBIN= -O32 -f bin
    ASFLAGSOBJ= -O32 -f elf
    NASM = nasm
    
    CFLAGS=	   -O -ffreestanding -fleading-underscore    
    CC= i586-elf-gcc
    
    LDFLAGS= -T kernel.ld -Map kernel.map -nostdinc
    LD= i586-elf-ld
    
    all: boot.bin ckernel.bin image     
    
    boot.bin: boot.asm
    	$(NASM) $(ASFLAGSBIN) $< -o $@
    
    %.o: %.asm
    	$(NASM) $(ASFLAGSOBJ) $< -o $@
    
    ckernel.bin: $(OBJECTS)
    	$(LD) $(LDFLAGS) $+ -o $@
    
    image:
    	cmd /c copy /b boot.bin + ckernel.bin HobbyOS.bin    
    
    #    $<        Erste Abhängigkeit
    #    $+        Liste aller Abhängigkeiten   
    #    $@        Name des Targets
    


  • Jetzt kommt der nicht in den CKernel. Auf dem Bildschirm steht immer nur diese bootloadermesage. Der CKernel:

    void k_clear_screen()
    {
    	char* vidmem = (char*) 0xb8000;
    	unsigned int i=0;
    	while(i<(80*2*25))
    	{
    		vidmem[i] = ' ';
    		i++;
    		vidmem[i] = 0x07;
    		i++;
    	};
    };
    
    unsigned int k_printf(char* message, unsigned int line)
    {
    	char* vidmem = (char*) 0xb8000;
    	unsigned int i = line*80*2;
    
    	while(*message!=0)
    	{
    		if(*message==0x2F)
    		{
    			*message++;
    			if(*message==0x6e)
    			{
    				line++;
    				i=(line*80*2);
    				*message++;
    				if(*message==0){return(1);};
    			};
    		};
    		vidmem[i]=*message;
    		*message++;
    		++i;
    		vidmem[i]=0x7;
    		++i;
    	};
    	return 1;
    };
    
    inline void outportb(unsigned int port,unsigned char value)
    {
        asm volatile ("outb %%al,%%dx"::"d" (port), "a" (value));
    };
    
    void update_cursor(int row, int col)
    {
    	unsigned short	position=(row*80) + col;
    	// cursor LOW port to vga INDEX register
    	outportb(0x3D4, 0x0F);
    	outportb(0x3D5, (unsigned char)(position&0xFF));
    	// cursor HIGH port to vga INDEX register
    	outportb(0x3D4, 0x0E);
    	outportb(0x3D5, (unsigned char)((position>>8)&0xFF));
    };
    
    // Hauptprogramm
    int main()
    {
    	k_clear_screen();
    	k_printf("Welcome to HenkesSoft OS.", 0);
    	k_printf("The C kernel has been loaded.", 2);
    	update_cursor(3, 0);
    
    	// Endlosschleife des OS
    	/*while(0)
    	{
    
    	};*/
    
    	return 0;
    };
    

    Was habe ich da wieder falsch gemacht?


  • Mod

    Zeige mal das Linkerskript und den Sprung nach _main in Assembler.


  • Mod

    a) Warum benutzt ihr Makefiles in einem neuen Projekt und nicht eine der moderneren Alternativen
    b) Wieso nicht die Autotools?

    http://de.wikipedia.org/wiki/GNU_Build_System

    Hat jemand Erfahrungen damit?



  • Linkskript:

    OUTPUT_FORMAT("binary")
    ENTRY(KernelStart)
    SECTIONS
    {
      . = 0x00008000;
      .text   : { *(.text)   }
      .data   : { *(.data)   }    
      .rodata : { *(.rodata) }
      .bss    : { *(.bss)    }  
    }
    

    Kernel.asm:

    [Bits 32]
    section .text          ; ld needs that for coff format
    
    [global KernelStart]
    KernelStart:
        mov    ax, 0x10
        mov    ds, ax      ; data descriptor --> data, stack and extra segment
        mov    ss, ax          
        mov    es, ax
        xor    eax, eax    ; null desriptor --> FS and GS
        mov    fs, ax
        mov    gs, ax
        mov    esp, 0x200000 ; set stack below 2 MB limit
    
    [extern _main]         ; entry point in ckernel.c
        call _main ; ->-> C-Kernel
        jmp $
    

Anmelden zum Antworten