In C++ geschriebenes programm ausführen



  • hallo assembler gemeinde

    ich versuche gerade meine ersten kleinen schritte in assembler. dabei habe ich einen bootloader aus dem internet zum testen benutzt und war erfreut, dass der text dann wirklich auf meinem bildschirm erschien. das war für mich ein grosser moment 🕶 🕶

    ich komme eigentlich aus dem C++ bereich, jedoch möchte ich gerne auch assembler lernen weil es mich sehr fasziniert. nun stelle ich mir gerade die frage, wie ich durch den bootloader ein programm laden kann, welches in purem C++ code geschrieben wurde, also sogar ohne die STL.

    das programm welches in C++ geschrieben wurde, macht nur ein paar pointer gesteuerte aufgaben, errechnet ein paar zahlenwerte und gibt das ergebnis zurück da es ja keine direkte textausgabe ermöglichen würde. nun stellen sich mir drei fragen:

    a) wie kann ich mit assembler (dem bootloader) ein C++ geschriebenes programm ausführen?
    b) wie muss das C++ programm compiliert/gelinkt werden, damit es auch ohne ein betriebssystem auskommt. (sehr wichtig)
    c) wie kann ich im assembler code den rückgabewert abfangen?

    wenn ihr mir auch nur eine dieser drei fragen beantworten könnt, würde mir das schon helfen. für jede hilfe bin ich dankbar. hier noch der assembler code:

    include 'emu8086.inc'
    
    ORG 7C00h
    JMP start
    
    msg  DB 'Welcome to micro-os', 13, 10,
         DB 'Loading...', 0
    
    start:
    
    MOV     AX, 07C0h
    MOV     SS, AX
    MOV     SP, 03FEh
    
    PUSH    CS
    POP     DS
    
    MOV     AH, 00h
    MOV     AL, 03h
    INT     10h
    
    LEA     SI, msg
    CALL    print_string
    
    MOV     AH, 02h
    MOV     AL, 10
    MOV     CH, 0
    MOV     CL, 2
    MOV     DH, 0
    
    MOV     BX, 0800h   
    MOV     ES, BX
    MOV     BX, 0
    
    INT     13h
    
    JMP     0800h:0000h
    
    DEFINE_PRINT_STRING
    
    END
    

    ich verwende den emu8086 und den MASM.



  • Praktische Beispiele in Form von Codes und Makefiles kann ich dir nicht geben, da ich dazu nichts rumliegen habe.
    Da du sehr allgemein fragst, kann ich ausserdem auch nur ebenso ungenau und allgemein antworten. Ich gehe davon aus, dass du mit dem 8086-emu nur im RealMode arbeitest.

    zu a) Du laedst das Programm mittels entsprechender BIOS-Funktionen (siehe int 13h, Funktionen 0 und 2) in den Speicher und springst dann an den Einstiegspunkt deines Programms. Wenn du hinterher im Assemblercode weitermachen willst am besten per call.

    zu b) Keine (Standard-)Libs verwenden und in ein einfaches Binaerformat (nach Moeglichkeit keine Header) linken. Compilieren musst du fuer den richtigen Prozessor (hier wohl 8086) und Prozessor-Modus (RealMode).
    Wie das genau geht, haengt vom Linker und Compiler ab. Mainstream-Tools wie das Visual-Studio-Gedings von MS koennen das idR. gar nicht.
    Den Einstiegspunkt (die main-Funktion) kannst du sinnvollerweise nach offset 0 deines Programms packen. Sollte allgemein funktionieren, indem das die 1. Funktion (gar nichts im Quelltext davor angelegt) in der 1. eingelinkten Datei ist. Die main-Funktion nimmt dann natuerlich keine Parameter, es sei denn du uebergibst im Assemblercode irgendwas ueber den Stack.

    zu c) idR. geben Hochsprachen int-Rueckgabewerte von Funktionen in ax zurueck.

    Ich rate uebrigens fuer so ein Low-Level-Vorhaben von C++ ab. Nimm besser erstmal C, Objekte brauchst du so weit eh nicht.



  • hallo Nobuo T und danke für dein posting. wie genau würde das laden den funktionieren, wenn die cpp_app.bin datei ganz "normal" auf der floppy disk geschrieben wurde und der assembler bootloader im bootsektor? aus wikipedia habe ich sowas:

    AH = 0
    DL = 00
    
    AH = 2
    AL = ??Sektorenanzahl??
    DL = ??Laufwerknummer??
    DH = ??Seiten/Kopf-Nummer??
    CH = ??Spur-/Zylindernummer??
    CL = ??Sektornummer??
    ES:BX = ??Adresse des Lesepuffers??
    

    stimmt das? und welche werte müssen an die stellen die noch unklar sind? es soll dann cpp_app.bin durch den bootloader in den arbeitsspeicher geschrieben werden und int main() aufgerufen werden. int main() ist ja prinzipiel der standard einsprungspunkt.



  • Ja, was du nachgeschlagen hast ist korrekt. Als Interruptnachschlagewerk ist aber http://www.ctyme.com/rbrown.htm Wikipedia vielleicht vorzuziehen.
    Wenn du unter "ganz normal" auf die Diskette kopieren, ein Kopieren mit dem Windows Explorer o.Ae. verstehst, brauchst du eine minimale Implementierung eines FAT Dateisystem-Treibers. Dazu hilft auch Wikipedia und als praktisches Beispiel ist der DOS Disketten-Bootloader nicht schlecht.
    Ich wuerde fuer den Anfang eher vorschlagen, das Dateisystem der Diskette komplett zu zerschiessen (da duerfte nach dem Aufspielen des Bootloaders eh nicht mehr viel mit funktionieren) und dein Binary in die naechsten freien Sektoren zu packen. Das geht bei echten Disketten mit Tools wie rawrite, ansonsten ka, wie du dein image erstellst.

    Dazu kann es sicher auch nicht schaden, sich mal ueber CHS zu informieren.



  • okay danke. eine frage noch schnell zu assembler allgemein. ich lese oft das gefragt wird, welches betriebssystem man verwendet. für mich stellt sich nun die frage: gibt es betriebssystem-abhängige assembler-erweiterungen? ich dachte eigentlich immer assembler code ist assembler code, basta. 🙂

    sprich, assembler ist ja die maschinensprache der CPU und co. warum redet man dann teilweise von betriebssystemen? wie "bezeichnet" man das nackte assembler (welches mich interessiert und ich lernen möchte)? und:

    a) welche computer komponenten verstehen den maschinencode? CPU, BIOS, alle?

    b) welche komponente wird immer als erstes angesprochen und leitet, falls notwendig, den rest an weitere komponenten weiter? ich tendiere stark zum BIOS, dann CPU..?

    c) ist assembler eigentlich wirklich "der maschinencode"? ich dachte bisher eigentlich das im endeffekt alles binär interpretiert wird, also das selbst assembler in binär code übersetzt wird.

    d) wenn dem so ist, wie wäre dann der interrupt int 10h in binärform zu interpretieren? damit ich mir ein bild davon machen kann, was dass BIOS eigentlich wirklich als ausgangsdaten bekommt.

    e) Int 10/AH=07h - VIDEO - SCROLL DOWN WINDOW. wie ist das zu verstehen? wenn ich "scrollen" höre denke ich gleich an ein betriebssystem. weis das BIOS oder der grafikchip schon auf der hardware ebene was scrollen ist? ich dachte sowas erledigt ein BS mit schwerstarbeit.

    f) ist es wirklich so einfach, buchstaben auf den bildschirm zu zaubern? ist untenstehender code wirklich die letzte meile zwischen mensch-maschine, um zeichen auf den bildschirm zu bekommen? mit letzte meile meine ich, es ist wirklich die oberste hardware nahe gränze, höher geht es nicht. ein cout bei C++ würde schlussendlich in assembler inetwa auch so ausschauen wie unten gezeigt?

    PUSH    AX     
    PUSH    SI      
    
    next_char:      
            MOV     AL, [SI]
            CMP     AL, 0
            JZ      printed
            INC     SI
            MOV     AH, 0Eh 
            INT     10h
            JMP     next_char
    printed:
    
    POP     SI     
    POP     AX      
    
    RET
    


  • Der Assemblercode an sich bleibt unabhaengig vom Betriebssystem gleich, mit der Ausnahme, dass man bestimmte Befehle in Betriebssystemen, die im Protected Mode (alle Multitasking-Systeme wie Windows, Linux, usw.) laufen, nicht benutzen darf.
    Allerdings aendert sich wie bei anderen nicht maschinenunabhaengigen Sprachen wie c++ (im Gegensatz zu zB. Java) auch bei Assembler natuerlich je nach Betriebssystem, fuer das Programmiert wird, die API, dh. die Schnittstellen mit dem Betriebssystem. Ein "nacktes" Assembler gibt es nicht. Du kannst wie gesagt entweder Programme in Assembler, C oder sonstwas fuer ein Betriebssystem schreiben, dh. ein Programm, das sich an Standards des Betriebssystems haelt und dessen APIs benutzt oder eben selbst in Assembler etc. ein Betriebssystem schreiben. Dann hast du keine APIs, die du benutzen kannst und bist auf dem System "der Boss". Macht prinzipiell aber keinen Unterschied, ist beides Assembler, c oder was auch immer.

    zu a) Maschinencode, dh. was der Assembler fuer die CPU (MASM zB.) ausspuckt, laeuft immer auf der CPU. Das ist also iaR. auch das einzige Teil, das den Maschinencode "versteht".

    zu b) Das BIOS ist nur ein Stueck Software. Ein Programm (Maschinencode fuer die CPU und Daten), das auf einem ROM-Chip liegt. Tut also von sich aus absolut gar nichts.
    Dieses Programm stellt eine Art grundlegendes Mini-Betriebssystem dar, das nach dem Einschalten automatisch als erstes gestartet wird. Das Ding testet und initialisiert dann schnell die Hardware, startet je nach Einstellungen irgendeinen Bootsektor und stellt Funktionen wie den int 10h und int 13h zur Verfuegung. Daher der Name Basic I/O System.
    Schlag mal nach, was eine CPU, ein Betriebssystem und ein BIOS ist.

    zu c) Richtig. Assembler ist eine ziemlich direkte und "niedrige" Abstraktion des Maschinencodes in Form von Mnemonics. Jedes Mnemonic entspricht ziemlich genau einem bestimmten Maschinenbefehl, also den Binaeren Daten. Der Assembler macht dann nicht viel mehr, als die Syntax zu pruefen und die Mnemonics durch die jeweiligen Codes zu ersetzen. Kannst du auch mal nachschlagen. 😉 Bei Wikipedia ist das alles bestimmt recht schoen erklaert.

    zu d) Wie gesagt, das BIOS bekommt in der Hinsicht nichts als Ausgangsdaten, das BIOS ist die Ausgangsdaten. 😃
    int 10h muesste AFAIR in Maschinencode die 2 Bytes CD 10 sein. Wie der Befehlssatz in Binaerform aussieht, steht in jeder besseren Befehlsreferenz. Der x86-Befehlssatz ist aber ziemlich wuest...

    zu e) Diese Funktion scrollt AFAIR den Text auf dem Bildschirm irgendwie rum (habe den Quark nie benutzt).
    Und im Grunde wissen sowohl das BIOS (das diese Funktion bereitstellt) als meist auch der Grafikchip was damit anzufangen... Allerdings implementiert so ein BIOS (Grafikkarten haben uebrigens ihr eigenes BIOS als eine Art auf der Hardware direkt mitgelieferten Treiber) AFAIK idR. keine Unterstuetzung fuer so abgefahrene Sachen wie Hardwareunterstuetzung von Scrolling etc.

    zu f) Du meinst die unterste Ebene? Nein, da wie gesagt das BIOS auch nur eine Software ist. Software-Interrupt-Aufrufe (int-Befehl) sind eigentlich nichts anderes als Funktionsaufrufe. Die CPU springt an eine voreingestellte Stelle im Speicher und fuehrt den dort stehenden Code, in diesem Fall des Graka-BIOS, aus.
    Tatsaechlich waere die unterste Ebene das direkte Schreiben in den Textbuffer. Das ist ein Speicherbereich, aus dem die Grafikhardware beim Bildschirmzeichnen liest, was gerade so auf dem Bildschirm stehen sollte.
    C++ ist wie gesagt eine recht abstrakte oder "hohe" Sprache. cout ist Verglichen mit der niedlichen Prozedur in deinem Assemblercode ein reichlich kompliziertes Ungetuem aus zig internen verschachtelten Prozeduren und Funktionen und meilenweit von der untersten Hardwareebene entfernt.


Anmelden zum Antworten