Eine in ANSI-C/C++ kompilierte Datei booten



  • Guten Abend!

    ich bin auf der Suche nach einem Assemblerquelltext mit dem ich eine mit ANSI-C/C++ kompilierte Datei booten kann. Ich möchte kein OS schreiben, sondern eher eine Shell-Konsole mit dem ich Texte ausgeben und eingeben kann. Da ich mich mit ANSI-C++ besser auskenne als mit Assembler, wollte ich euch fragen, was ich beachten muss, wenn ich eine Bootdiskette unter Linux schreiben will.
    Ich habe einen CPU mit der x86_64 Architektur und weiß nur, wenn ich mit Linux eine Assembler-Datei übersetzen will, muss ich es mit den Format elf64 übersetzen und die Register AX, BX, CX, DX in RAX, RBX, RCX, RDX umbenennen.
    Also, wenn es einen Assembler-Programmierer(in) gibt, der/die sich nicht nur gut mit BIOS-Interrupts, sondern auch mit Linux/UNIX-Systeme auskennt, werde ich mich sehr freuen, wenn Der- oder Diejenige mir die Beispieldateien (boot.asm und shell.c oder shell.cpp) posten könnte.



  • Im Prinzip nennt man jedes Programm, dass du auf einem PC vom BIOS zum Selbstzweck bootest, OS.
    Wenn du also ein Programm schreiben willst, das ohne ein anderes Betriebssystem als Basis laeuft, willst du ein OS schreiben.
    Da ist es aber nicht einfach mit einem kleinen 200-Zeilen Asm-Bootloader getan. Das bedeutet auch erhebliche Einschraenkungen im Hinblick auf moegliche binaere Programmformate und Anwendbarkeit von Libs - die C und C++ Standard-Libs mit Spielzeugen wie cout oder printf laufen ohne ein passendes darunterliegendes OS z.B. nicht.

    Wenn du dich ernsthaft mit OS-Entwicklung beschaeftigen willst, kommst du nicht umhin, dich mit der CPU des Zielsystems und damit auch deren Programmierung via Assembler eingehend zu beschaeftigen.
    Evtl. hast du Spass daran, mit einem der zahlreichen einfachen "wie bastel ich mir mein Mini-OS"-C&P-Tutorials den Sprung ins kalte Wasser zu wagen? Klingt fast so. Es gibt darunter auch ein paar, die so weit gehen, eine in C geschriebene Datei zu starten. Einen Link habe ich leider gerade nicht zur Hand, aber da findest du sicher etwas, wwenn du dich in den FAQ oder google umsiehst.
    [edit]Ist zwar letztendlich sicher etwas anspruchsvoller, aber vielleicht interessiert dich auch Erhards OS-Tutorial

    Fuer Spielereien wie einen kleinen Prompt ohne naeheren Kontakt zur "Unterwelt des PCs" wuerde ich aber eher vorschlagen, dass du dir eine abgespeckte mini-Version eines Betriebssystems her nimmst, wie eine kleine, selbst angepasste Linux-Distri oder ein wenige KB grosses DOS und dein Programm von da aus per start-script starten laesst.

    stefan2008 schrieb:

    Ich habe einen CPU mit der x86_64 Architektur und weiß nur, wenn ich mit Linux eine Assembler-Datei übersetzen will, muss ich es mit den Format elf64 übersetzen und die Register AX, BX, CX, DX in RAX, RBX, RCX, RDX umbenennen.

    Das wuerde so sicher in die Hose gehen.



  • Mit Grub (+Patch?) gibt es zumindest die Möglichkeit elf64 binaries zu laden. Damit sparst du dir den bootloader und den Übergang in den protected und long mode. Trotzdem wirst du dann nicht daran vorbei kommen selbst sämtliche Grundfunktionalität selber zu bauen. Angefangen bei sachen wie malloc und printf bis zur kompletten standardbibliothek (oder das porten bestehender wie newlib) steckt darin viel arbeit.



  • Wie sehen die Quelltexte aus, wenn ich rein in Assembler schreibe? Mich würde es sehr interessieren, wie ich mit BIOS-Interrupts zwei Zeilen Texte ausgeben und mit eine beliebige Taste den Computer neu starten kann.
    Ich möchte sehr klein Anfangen. Aber es gib für Linux zum Thema Assembler kaum Beispiele. Es währe sehr toll, wenn einer mir einen sehr kompakten Quelltext mit Kommentaren und Makefile posten kann, in den ich sehen kann, welches Interrupt für Eingabe bzw. Ausgabe zuständig ist und wie man diese Dateien mit NASM unter Linux kompilieren und booten kann.
    Ich werde später dann, wenn mir einer Beispiele postet, diese Datei mit entsprechenden Interrupts erweitern und mit Bochs testen.



  • Wie gesagt: schau dir zB. Erhards OS-Tut an. Da wird auch erstmal ein Hello World in NASM gebastelt, mit Bochs getestet und dann erweitert. Das sollte sich auch in Linux so umsetzen lassen.



  • Manche nennen solch ein "OS" auch Firmware, da es kein OS im eigentlichen Sinn ist.



  • Ich habe ein Teil der untenstehenden Beispieldateien von http://lowlevel.brainsware.org/wiki/index.php/C-Kernel_mit_GRUB übernommen und an C++ angepasst. Aber ich habe mit dem Casten in Zeile 4 bei "kernel.cpp" ein Problem, was ich nicht verstehe.

    Makefile

    ASM			= nasm
    AFLAGS		= -f elf64
    
    CC			= g++
    CFLAGS		= -m64 -ffreestanding -nostdinc
    
    LD			= ld
    LFLAGS		= -T script.ld
    
    OBJECTS		= boot.o kernel.o
    
    build: *.o
    	$(ASM) $(AFLAGS) -o boot.o boot.asm
    	$(LD) $(LFLAGS) -o kernel.bin $(OBJECTS)
    
    %.o: %.cpp
    	$(CC) $(CFLAGS) -c $< -Wall
    

    boot.asm

    global loader
    extern main
    
    FLAGS		equ 0
    MAGIC		equ 0x1BADB002
    CHECKSUM	equ -(MAGIC + FLAGS)
    
    section .text
    	align	4
    
    MultiBootHeader:
    	dd		MAGIC
    	dd		FLAGS
    	dd		CHECKSUM
    
    loader:
    	mov		rsp, 0x200000
    	push	rax
    	push	rbx
    	call	main
    
    	cli
    	hlt
    

    kernel.cpp

    int main(void)
    {
    	const char *message = "Mein OS Ausgabe 0.01";
    	char *video = static_cast<char*>(0xB8000);
    
    	for(video += 4000; video != static_cast<char*>(0xB8000); video--)
    	{
    		*video = 0;
    	}
    
    	while(*message)
    	{
    		*video = *message;
    		video++;
    
    		*video = 0x07;
    		message++;
    		video++;
    	}
    
    	return 0;
    }
    

    script.ld

    ENTRY(loader)
    OUTPUT_FORMAT(elf64-x86_64)
    OUTPUT_ARCH(i386:x86-64)
    
    SECTIONS
    {
    	. = 0x00100000;
    
    	.text :
    	{
    		*(.text)
    	}
    
    	.rodata :
    	{
    		*(.rodata)
    	}
    
    	.data :
    	{
    		*(.data)
    	}
    
    	.bss :
    	{
    		_sbss = .;
    		*(COMMON)
    		*(.bss)
    		_ebss = .;
    	}
    }
    


  • Was hat die untenstehende Meldung zu bedeuten?

    g++ -m64 -ffreestanding -nostdinc -c kernel.cpp -Wall
    nasm -f elf64 -o boot.o boot.asm
    ld -T script.ld -o kernel.bin boot.o kernel.o
    kernel.o:(.eh_frame+0x12): undefined reference to `__gxx_personality_v0'
    


  • Undefined references to internal run-time library functions, such as __gxx_personality_v0, are also a symptom of linking C++ object files with gcc instead of g++. Linking the same object file with g++ supplies all the necessary C++ libraries and will produce a working executable

    http://www.network-theory.co.uk/docs/gccintro/gccintro_54.html

    siehe auch: http://ipucu.enderunix.org/view.php?id=1862&lang=en



  • Ich glaube die Links von Erhard bringen wenig, weil du gar nicht mit gcc linkst. Der entscheidene Unterschied zwischen dem Linken mit g++ und gcc, ist dass g++ noch libstd++ dazu linkt.

    Ich würde sagen, es gibt in diesem Fall mehrere Alternativen:
    - Exceptions deaktivieren. Das geht mit dem Parameter -fno-exceptions für gcc.
    - Das Symbol __gxx_personality_v0 definieren. Solange keine Exceptions auftreten, sollte das funktionieren

    void *__gxx_personality_v0;
    

    - Auf C++ verzichten und nur C nehmen.
    - Einen Cross Compiler samt C++-Bibliothek erstellen, und diese Bibliothek dazu linken.



  • Ich habe den Quelltext als C-Datei gespeichert und kompiliert und zusammen mit der Assemblerdatei boot.o gelingt. Es hat funktioniert ohne Fehlermeldung. Danach habe ich mit dd ein Image für meine Diskette erstellt und die GRUB-Dateien drauf kopiert und in /usr/sbin/grub die nötigen Anweisungen eingegeben. Als ich dann die Diskette auf mein Notebook booten wollte, kam die folgende Meldung:

    Datenträger entfernen
    Neustart: Taste drücken
    

    Also irgendwas muss ich vergessen oder übersehen haben.

    Makefile

    ASM			= nasm
    AFLAGS		= -f elf64
    
    CC			= gcc
    CFLAGS		= -m64 -ffreestanding -nostdinc
    
    LD			= ld
    LFLAGS		= -T script.ld
    
    OBJECTS		= boot.o kernel.o
    
    build: *.o
    	$(ASM) $(AFLAGS) -o boot.o boot.asm
    	$(LD) $(LFLAGS) -o kernel.bin $(OBJECTS)
    
    %.o: %.c
    	$(CC) $(CFLAGS) -c $< -Wall
    
    install:
    	dd if=/dev/zero of=floppy.img bs=1024 count=1440
    	/sbin/mke2fs -F floppy.img
    	mount -o loop floppy.img /media/DISC/
    	cp kernel.bin /media/DISC/
    	mkdir /media/DISC/grub
    	cp /boot/grub/stage1 /media/DISC/grub
    	cp /boot/grub/stage2 /media/DISC/grub
    	cp menu.lst /media/DISC/grub
    	/usr/sbin/grub
    	dd if=floppy.img of=/dev/fd0
    	umount /media/DISC
    

    menu.lst

    default 0
    timeout 10
    
    title Mein kleines OS
    kernel /kernel.bin
    root (fd0)
    

    /usr/sbin/grub

    device (fd0) floppy.img
    root (fd0)
    setup (fd0)
    quit
    

Anmelden zum Antworten