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-TutorialFuer 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 funktionierenvoid *__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