Mein erstes Assemblerprogramm
-
Hi Leute!
Ich hab bzw. ich sollte heute mein erstes lauffähiges Assemblerprogram geschrieben haben; leider nicht ohne Fehler.
Meine Aufgabe: Mein Programm soll Ausdruck berechnen: ERG = (A-B) + C
Den Code assembliere, linke und debugge ich mit dem Borland TASM TLINKER und TDEBUGGER. Wenn ich als erstes Debugger drüber laufen lasse, sagt er mir es gibt einen Error. Ich weiß aber nicht wo es den haben soll. Könnt ihr mir helfen?
Mein Code:
%noctls ; keine Listing Steueranweisung %noincl ; keine "Include-Dateien" ausgeben INCLUDE macros.asm ASSUME DS:Daten, CS:CODE ; Segment "Daten" wird Datensegment, "Code" wird Codesegment ;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Daten SEGMENT ; hier beginnt das Segment mit dem Namen DATEN A DW 20h B DW 20h C DW 0h Text DB "Ergebnis" ERG DW 0 DB "Flag:" O_Flag DB 0 DB "Zahl:" Zahl DW 3421h ENDS ; hier endet das Datensegment ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ CODE SEGMENT ; hier beginnt das Segment mit dem Name CODE Anfang: mov AX,Daten ; Die Segmentadresse "Daten" kommt in AX mov DS,AX ; "Daten" kommt in DS mov AX,A mov BX,B sub AX,BX jo Overflow mov BX,C add AX,BX ; (A-B)+C jo Overflow mov ERG,AX ; Speichere Ergebnis inc Zahl mov AX,A ; A*2 mov BX,A add AX,BX mov A,AX mov AX,B ; B*2 mov BX,B add AX,BX mov B,AX mov AX,C ; C*2 mov BX,C add AX,BX mov C,AX jmp Anfang Overflow: mov O_Flag Terminate_Program ; Rückkehr zum Betriebssystem ENDS ; hier endet das Code-Segment ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ END Anfang ; hier endet das Assemblerprogramm ; das Programm wird an der Adresse Anfang gestartet
-
Die Fehlernachricht die mir Debuuger bringt lautet so:
Error in Line56: Too few operands to instruct
Warning in Line 56: Argument needs type overrideIch kann leider mit diesen Meldungen wenig anfangen....
-
die Fehlermeldung sagt doch was falsch ist!
-
Danke!
Hab ich jetzt auch gesehen. Laut meiner Aufgabe, soll ich nach dem das Programm einen Overflow erreicht hat in O_Flag eine 1 schreiben. Es fehlt also ",1".
Eine Frage hab ich noch. Bei meiner Aufgabe wird gesagt, man soll das Ergebnis in die Variable ERG speichern. Wie geht das? Ich hab immer gedacht, man kann nur in den Registern (AX,BX,CX,DX) speichern...
Wenn das Programm nun bis zu einem Overflow das Ergebnis berechnet, möchte ich das es mir die Ergebnisse auf dem Bildschirm ausgibt. Wie mache ich das? Bzw. das ist wahrscheinlich unsinn, da man nix sehen wird, da vorher das Programm terminieren wird, oder?
Kannst du mir sagen was da gemeint ist?
-
Sorry, ich sehe gerade das ich ja das eigentlich programmiert habe. Ich speichere den Wert nach der kompletten Berechnung vom Register AX in die Variable ERG.
-
die beiden Anweisungen
inc Zahl
und
mov O_Flagsind nicht ganz unproblematisch. Was passiert denn da genau?
Außerdem fehlt noch ein Systemaufruf zum Beenden des Programms.
Und obwohl der Turbo Debugger eine recht gute Hilfe ist, empfiehlt sich der Einstieg in Asm eher über Debug und Fasm. Wenn du deine ersten Gehversuche mit debug (in jedem Windows dabei) machst, merkst du gleich, was auf unterster ebene geht, und was nicht, und du weißt, wie modernere Assembler wie Masm32, Masm, Nasm, Yasm, Fasm, oder gas dir die Arbeit erleichtern, und worin sie sich unterscheiden. Wenn du ein guter Hochsprachenprogrammierer bist, dann lohnt sich auch ein Blick auf den pädagogisch gemachten Assembler HLA. In älteren Assemblerbüchern steht zwar immer noch Tasm-Code, aber ab einem bestimmten Schulungslevel ist es leicht, Tasm Programme z.B. nach seinem inoffizellen und gut optimierten Nachfolgerassembler Fasm zu übertragen.
-
Danke Nachtfeuer für deine Hilfe!
Wie gesagt (und wie du wahrscheinlich schon erkannt haben wirst...), bin ich blutiger Anfänger in Bezug auf Assemblerprogrammierung. Genau genommen bin ich auch in Hochsprachen wie C oder C++ blutiger Anfänger. Ich befinde mich momentan im ersten Semester eines Technischen Informatik Studiums. Unser Professor zieht die Vorlesung zu Assemblerprogrammierung aber anhand von TASM auf. Deswegen verwende ich diesen Assemblierer.
Nun zu deinen erwähnten Anweisungen.
In meiner Aufgabe steht auch noch, dass ich nach jedem Durchlauf das Programms eine Zählvariable um eins hochzählen lassen soll, wenn kein Overflow entstanden ist. Laut Aufgabe sollen wir dafür eben den Befehl des inkrementierens (inc) benutzen und das Ergebnis des inc-Befehls in die Variable "Zahl" schreiben. Was an diesem Befehl nun problematisch sein soll weiß ich leider nicht und kann ich mir gerade auch selber nicht so vorstellen. In unseren Befehlssatzdatenblättern die wir zur Verfügung gestellt bekommen haben, steht zu einer etwaigen Problemtik diesen Befehls leider auch nichts.
Dementsprechend verhält es sich mit dem Befehl "mov O_Flag". Hier sollen wir laut Aufgabe nachdem ein Overflow aufgetreten ist eine 1 schreiben. Da der Assemblierer aber erst nach dem ein Overflow aufgetreten ist (zumindestens an den prägnanten Stellen an denen ein Overflow auftreten kann; falls ein Overflow auftritt springt er ja dann mit dem Befehl JO an die Marke "Overflow"), an der Marke "Overflow" weiterliest, schreibt er auch erst dann eine 1 in die Variable O_Flag. Ich weiß ebenfalls nicht was daran problematisch sein soll.
Du schreibst:
Und obwohl der Turbo Debugger eine recht gute Hilfe ist, empfiehlt sich der Einstieg in Asm eher über Debug und Fasm. Wenn du deine ersten Gehversuche mit debug (in jedem Windows dabei) machst, merkst du gleich, was auf unterster ebene geht, und was nicht, und du weißt, wie modernere Assembler wie Masm32, Masm, Nasm, Yasm, Fasm, oder gas dir die Arbeit erleichtern, und worin sie sich unterscheiden.
Kannst du vielleicht genauer drauf eingehen? Findest du ich sollte bzw. muss mit dem Windowseigenen Debugger arbeiten um einen wirklich guten Einstieg in Assembler zu bekommen? Was sind die anderen Debugger? Was können die besser als der TASM? So wie ich das verstehe ist der FASM die Weiterentwicklung des TASM, oder?
-
Sorry, jetzt hab ich eine Frage vergessen: Ich möchte nun mal einen Overflow herbeiführen, damit ich im Debugger sehe wie das Overflowflag gesetzt wird. Wie mache ich das geschicktesten bzw. wie muss ich die Zahlen wählen, damit z.B. nach der Addition das O-Flag gesetzt wird?
-
bandchef schrieb:
Sorry, jetzt hab ich eine Frage vergessen: Ich möchte nun mal einen Overflow herbeiführen, damit ich im Debugger sehe wie das Overflowflag gesetzt wird. Wie mache ich das geschicktesten bzw. wie muss ich die Zahlen wählen, damit z.B. nach der Addition das O-Flag gesetzt wird?
z.B: mit einem Byte lassen sich maximal 256 Zahlen darstellen (0 bis 255)
mov al, 255 add al, 7 ; Überlauf O-Flag wird gesetzt!
-
Mein Code sieht jetzt so aus:
Daten SEGMENT ; hier beginnt das Segment mit dem Namen DATEN A DW 255h B DW 1h C DW 2h Text DB "Ergebnis" ERG DW 0 DB "Flag:" O_Flag DB 0 DB "Zahl:" Zahl DW 0h ENDS ; hier endet das Datensegment ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ CODE SEGMENT ; hier beginnt das Segment mit dem Name CODE Anfang: mov AX,Daten ; Die Segmentadresse "Daten" kommt in AX mov DS,AX ; "Daten" kommt in DS mov AX,A mov BX,B sub AX,BX jo Overflow mov BX,C add AX,BX ; (A-B)+C jo Overflow mov ERG,AX ; speichere Ergebnis
Die gefährliche Stelle ist ja hier jetzt eigentlich die Addition. Er addiert aber trotzdem brav +2 und geht über die 255 drin...
Was mach ich falsch?
-
@ Otto8 Nein, das stimmt nicht, hier wird das Carryflag gesetzt.
Es ist vielleicht nicht so schlecht, wenn du die Tasm Progamme aus dem Unterricht erstmal versuchst, nach debug umzusetzten. Was zu schwierig ist, wie z.B. inc Zahl, das läßt du es erstmal bleiben.
Wie die Flags reagieren, kannst du dir super in debug.exe (oder debug.com) anschauen. Wenn man im Konsolenfenster von debug ist, und den blinkenden Unterstrich sieht, dann kann man z.B. ? eingeben und bestätigen um die Liste der Kurzbefehle zu sehen.
mit r kannst du dir die Register anzeigen lassen
mit rax oder rbx oder rip usw. kannst du werte in die Register laden
mit e 100 schreibst du Hexcodes in den Speicher bei Adresse 100. (es erscheint eine Art Hexeditor)(Leertaste weiter, Return zum Hinausgehen)
Beispiel: gib ein e100 und dann 29 (Leertaste) d8 (Enter)
und dann gib ein: r
Normalerweise sieht man u.a. den asm Befehl sub ax,bx
dann lädst du den Wert 8000 nach Ax mit rax:
dann lädst du den Wert 1 nach bx mit rbxmit t kannst du den Code schrittweise durchgehen, also mach einmal t
(und dann schau dir die Register an, und die Flags)
dann stellst du den Instructionpointer zurück auf 100 mit ripjetzt kannst du andere Werte in die Register laden, alles nochmal wie eben machen, nur mit anderen Zahlen, und die Flags beobachten
mit dem buchstaben a kannst du assemblerbefehle direkt eingeben.
Den Professor würde ich einfach mal fragen, ob es nicht möglich wäre, den Kurs mit Fasm fortzusetzten. Für Fasm sprechen mehrere Gründe, u.a. einfache Syntax, Einsteigerfreundlich, 64bit und SSE Unterstützung. Man kann ja den Fasmcode trotzdem mit dem Turbodebugger anschauen, aber in der Regel reicht debug.
Gegen Tasm spricht: veraltete Syntax, kommerzielles Produkt, vergriffen.
-
Ich hab hier nochmal ein Programm das auf meinem Übungszettel steht.
Hier der Code:
;*************************************************************************************** %noctls ; Listing-Steueranweisungen werden nicht im Listing ausgegeben %noincl ; Include-Dateien werden nicht im Listing ausgegeben INCLUDE MACROS.ASM ASSUME CS:CODE, DS:DATA ;-------------------------------------------------------------------------------------------- MKAND EQU 0FFh ; Multiplikand ist Konstante mit Wert 255 MKATOR EQU 0FFh ; Multiplikator ist Konstante mit Wert 255 ;--------------------------------------------------------------------- DATA SEGMENT PROD DD 00000000h MPROD DD 0h DATA ENDS ;--------------------------------------------------------------------- CODE SEGMENT START: mov AX,DATA ; Die Segmentadresse "Daten" kommt in AX mov DS,AX ; "Daten" kommt in DS mov CX,0FFh ; 255 wird in CX geschrieben -> Abbruchkriterium für LOOP Marke1: mov AX,MKAND ; MKAND wird in AX geschrieben mov BX,MKAND ; MKAND wird in AX geschrieben add ax,bx ; AX und BX werden addiert LOOP Marke1 Terminate_Program ; Rückkehr zum Betriebssystem ENDS END Start
Wenn ich das Programm jetzt assembliere kommen keine Fehler. Wenn ich es linken lasse, dann sagt er mir "Bad Object Code". Ich hab das jetzt mal ignoriert und trotzdem mit dem debuggen weitergemacht und da meldet er mir, dass das Programm nicht geöffnet werden kann.
Was ist daran jetzt falsch?
Das Programm soll eine Multiplikation aufgrund wiederkehrender Addition durchführen. Es soll mir die Werte 255 mit 255 multplizieren. Der LOOP Befehl funktioniert ja so, indem man ihm in das Register CX die Anzahl der Schleifendurchläufe angibt. Das hab ich ja mit 0FFh getan. Ich weiß echt nicht was falsch ist; ich schau mir jetzt das Programm schon fast seit 1h an...
Kannst du mir helfen? Danke!
-
Ich hab jetzt nochmal meinen Code überarbeitet. Jetzt tu er (denke ich) schon mal das was er soll, nämlich addieren. Er bringt mir aber jetzt in der Zeile 32 einen Fehler das der Typ eines Operanden nicht passen soll. Ich weiß aber nicht was damit gemeint ist, da ich nicht blicke wo der Fehler liegen soll. MPROD ist ja im Datensegment korrekt geschrieben...; an AX kann's auch nicht liegen, da steht ja mein Ergebnis drin...
;*************************************************************************************** %noctls ; Listing-Steueranweisungen werden nicht im Listing ausgegeben %noincl ; Include-Dateien werden nicht im Listing ausgegeben INCLUDE MACROS.ASM ASSUME CS:CODE, DS:DATA ;-------------------------------------------------------------------------------------------- MKAND EQU 0FFh ; Multiplikand ist Konstante mit Wert 255 MKATOR EQU 0FFh ; Multiplikator ist Konstante mit Wert 255 ;--------------------------------------------------------------------- DATA SEGMENT PROD DD 00000000h MPROD DD 00000000h DATA ENDS ;--------------------------------------------------------------------- CODE SEGMENT START: mov AX,DATA ; Die Segmentadresse "Daten" kommt in AX mov DS,AX ; "Daten" kommt in DS mov CX,0C7h ; 255 wird in CX geschrieben -> Abbruchkriterium für LOOP mov AX,MKAND ; MKAND wird in AX geschrieben mov BX,MKAND ; MKAND wird in BX geschrieben add AX,BX ; AX und BX werden addiert Marke1: ; Marke1 der LOOP-Schleife add AX,BX ; wiederholte Addition LOOP Marke1 ; LOOP-Schleife mov MPROD,AX ; Speichern des Ergebnisses in MPROD Terminate_Program ; Rückkehr zum Betriebssystem ENDS END Start
-
So, ich glaub ich hab das Problem jetzt selbst gelöst. MPROD ist als DD angegeben DD hat aber 4Byte; AX hat aber nur 2Byte deswegen gibts nen typ konflikt
-
otto8 schrieb:
mov al, 255 add al, 7 ; Überlauf O-Flag wird gesetzt!
mov al, 127 add al, 1 ; Überlauf O-Flag wird gesetzt!
^^ So geht das.