Unterprogramm vs. Makro
-
Hallo,
ich hab 2 Probleme mit denen ich mich auseinandersetzen muss:1. Bei Makros kann man im Gegensatz zu Unterprogrammen Parameter schreiben, dies wurde mir bei Unterprogrammen nicht erklärt. Geht das? (unabhängig von FAR und NEAR)
2. was soll ich verwenden? Makros oder Unterprogramme? Makros schreiben alles neu und Unterprogramme springen, aber was ist nun besser?
-
Original erstellt von pAngel:
1. Bei Makros kann man im Gegensatz zu Unterprogrammen Parameter schreiben, dies wurde mir bei Unterprogrammen nicht erklärt. Geht das? (unabhängig von FAR und NEAR)Klar geht das, C muss das ja auhc irgendwie hinbekommen
Es gitb sehr viele Varianten, wie man das machen kann, das üblichste ist vermutlich fastcall und cdecl, genaueres gibts unter http://bkausbk.netfirms.com/callconv.html
**
2. was soll ich verwenden? Makros oder Unterprogramme? Makros schreiben alles neu und Unterprogramme springen, aber was ist nun besser?**Makros nur für kleine Dinge um den Code übersichtlicher zu machen. Z.B. habe ich mir irgendwann mal Makros gemacht BEGINPROC und ENDPROC um den Anfang und das Ende einer Prozedur zusammenzufassen. Sobald es wirklich eine Funktion ist, sollte man ein Unterprogramm schreiben, denn du musst immer bedenken, dass der gesamte Code dort hinkopiert wird, gerade bei oft verwendeten Funktionen ist das ein riesiger, unnötiger Overhead. Spätestens bei rekursiven Funktionen klappt das sowieso nicht mehr. Deswegen Makros nur für kleine Dinge, ansonsten immer Funktionen.
-
ich würde makros nur verwenden wenn funktionen nicht möglich sind, weil funktionen typsicherheit haben, während man doch bei makros alles übergeben kann was die nötigen operatoren hat... und wer weiß was dann rauskommt...
my2c?nt
rapso->greetS();
-
hab's mit c++ verwechselt... dumm wenn man durch foren hoppelt... tsorri
*dumm*
rapso->rot();
-
hä? Hätte nicht gedacht, das es so kompliziert ist, Parameter bei Unterprogramme einzubauen. Übrigens kapier ich einfach nicht, was das "E" vor z.B. "AX" bedeutet. Hab schon in einem anderen Beitrag gefragt, da bekam ich die Antwort 32 Bit Register, nur, wie verwende ich das bzw. wann verwende ich das?
P.S.: Wenn C mit Assembler programmiert wurde, mit was wurde dann Assembler programmiert
. Mit Maschinencode? Wenn ja, mit was wurde Maschinencode entwickelt usw.
:p *gg*
[ Dieser Beitrag wurde am 07.04.2003 um 20:01 Uhr von pAngel editiert. ]
-
Original erstellt von pAngel:
hä? Hätte nicht gedacht, das es so kompliziert ist, Parameter bei Unterprogramme einzubauen. Übrigens kapier ich einfach nicht, was das "E" vor z.B. "AX" bedeutet. Hab schon in einem anderen Beitrag gefragt, da bekam ich die Antwort 32 Bit Register, nur, wie verwende ich das bzw. wann verwende ich das?Ui, DOS-Programmierer?
Im Zuge von 32-Bit wurden die Register erweitert, einfach ein E davorpacken, schon hast du ein 32-bit-Register. Sprich: AX, BX, CX, DX, SI, DI, SP, BP heißen im 32-Bit-Modus EAX, EBX, ECX, EDX, ESI, EDI, ESP, EBP.
Im Prinzip ist es garnicht so kompliziert mit den Parametern, hier mal cdecl auf 16 Bit:
Der Aufrufer pusht alle Parameter rückwärts auf den Stack und callt dann. Am Ende stellt er den Stack wieder her.
Der Aufgerufene kann über den Stack auf die Parameter zugreifen. Das Ergebnis wird in AX zurückgegeben (ST(0) für FPU).Beispiel eine Funktion mit zwei parametern, sei es mal subtrahiere, in C sähe das so aus:
int subtrahiere(int x, int y) { return x-y; }
Ein Aufruf sei weiter: subtrahiere(subtrahiere(3, 2), 1); (Ergebnis ist 0 ;))
So, nun in Assembler:
Der Aufruf: Parameter rückwärts auf den Stack pushen, call und am Ende aufräumen:push word 2 ; Parameter 2 Rückwärts! (rechts nach links) push word 3 ; Parameter 1 call subtrahiere ; Aufruf add sp, 4 ; denn wir haben 4 Bytes (2 words) gepusht push word 1 ; Parameter 2, zweiter Aufruf push ax ; denn das Ergebnis vom ersten Aufruf lag ja in ax call subtrahiere ; Aufruf add sp, 4 ; Stack richten, in ax liegt jetzt 12
Nun fehlt noch die Funktion. Damit man es nicht so schwer hat innerhalb der Funktion, benutzt man bp um eine Art Basis zu haben, bp nimmt dabei den Wert von sp an. Damit hat man eine Basis im Stack, während sp selber munter sich bewegen darf. Natürlich muss man den alten bp vorher sichern und am Ende wieder herstellen. Damit hat eine Funktion diesen Prolog/Epilog:
push bp ; alten bp retten mov bp, sp ; bp als Basis festsetzen ; hier die Funktion mov sp, bp ; sp wieder herstellen pop bp ; bp wieder herstellen ret ; Rücksprung
Nun bleibt noch die Frage, wie die Funktion Parameter benutzen kann. Aber die liegen ja auf dem Stack und da bp innerhlab der Funktion konstant bleibt, können wir bp super benutzen um auf die Parameter zuzugreifen. Schauen wir uns mal den Stack an, nachdem der Funktionsprolog abgelaufen ist:
+-------------------+ <-- BP+8 | Parameter 2 | +-------------------+ <-- BP+6 | Parameter 1 | +-------------------+ <-- BP+4 | Rücksprungadresse | +-------------------+ <-- BP+2 | Alter Wert von BP | +-------------------+ <-- BP
Ist also ganz einfach, für den ersten Parameter nehmen wir [bp+4], für den zweiten [bp+6] etc. Zu beachten ist noch, dass wenn wir einen far call machen, die Rücksprungadresse doppelt so groß ist (segment + adresse)
+-------------------+ <-- BP+10 | Parameter 2 | +-------------------+ <-- BP+8 | Parameter 1 | +-------------------+ <-- BP+6 | Rücksprungsegment | +-------------------+ <-- BP+4 | Rücksprungadresse | +-------------------+ <-- BP+2 | Alter Wert von BP | +-------------------+ <-- BP
Da liegen die Parameter also ab [bp+6], [bp+8] etc. Nun können wir also die Funktion zusammenbauen (Beispiel: near call)
push bp ; bp retten mov bp, sp ; Basis festsetzen mov ax, [bp+4] ; Parameter 1 in ax laden sub ax, [bp+6] ; Parameter 2 von ax abziehen. mov sp, bp ; sp wieder herstellen pop bp ; bp wieder herstellen ret
**
P.S.: Wenn C mit Assembler programmiert wurde, mit was wurde dann Assembler programmiert. Mit Maschinencode? Wenn ja, mit was wurde Maschinencode entwickelt usw.
:p *gg*
**Die ersten Rechner wurden in Maschinencode programmiert, sobald du einen Rechner mitsamt Assembelr je geschrieben hast, kannst du dadrin Compiler etc. entwerfen, aber auch Cross-Assembler für andree Rechner, d.h. du brauchst im Prinzip nur ein einziges Mal einen Assembelr in Maschinencode schreiben.
C wird heutzutage in C programmiert, d.h. du brauchst schon einen C-Compiler um einen neuen zu bauenAssembler werden heutzutage auch in C geschrieben. Ist aber alle snicht so schlimm, weil irgendwann mal jemand einen C-Compiler für den PC geschrieben hat, wie auch imemr kompiliert hat und man jetzt binaries für jedes System bekommt
Hope that helps
-
Assembler ist doch denk ich mal zu komplex, um es in C zu entwerfen, wie stellen die das an?
Außerdem: was bringt das mit den EAX? Man kann genausogut auch AX benutzen...
PS: hab halt ein Dos- Assembler- Tutorial
-
Original erstellt von pAngel:
Assembler ist doch denk ich mal zu komplex, um es in C zu entwerfen, wie stellen die das an?Assembler ist noch geradezu trivial zu kompilieren. Man hat kaum mit der Syntax zu wursten, wie es in C der Fall wäre. Man braucht halt nur große Tabellen um die ganzen Opcodes zu regeln. Das ist nicht soo schwer.
**
Außerdem: was bringt das mit den EAX? Man kann genausogut auch AX benutzen...
**Könnte man. Aber spätestens bei ESP/EBP/ESI/EDI hörts auf, denn im 32-Bit-Modus braucht man 32-bit-Adressne und die passen in ein 16-Bit-Register wie SI nunmal nicht rein
Im Übrigen sind 16-Bit für viele größere Rechnungen einfach nicht mehr genug (neben Speicherberechnungen), auf einem 32-Bit-System ist ein normales Register nunmal 32 Bit breit, man könnte sonst auch fragen, wozu AX benutzen, gibt doch AL
-
es geht darum, dass du mit 32bit - registern grössere zahlen benutzen kannst.
16bit : zahlen von 0 bis 2^16-1
32bit : zahlen von 0 bis 2^32-1
-
Naja, hab mal was in Sachen Makros ausprobiert:
Datei 1: STRING.LIB
PRINT MACRO STRING MESSAGE DB STRING, 10, 13, "$" MOV DX, OFFSET MESSAGE MOV AH, 09H INT 21H ENDM
Datei 2: AUSGABE.ASM
INCLUDE STRING.LIB DATA SEGMENT DATA ENDS STACK SEGMENT BYTE STACK DW 128 DUP (?) STACK ENDS CODE SEGMENT START: ASSUME SS:STACK, DS:DATA, ES:NOTHING, CS:CODE PRINT "Imagine all the people!" MOV AH, 4CH INT 21H CODE ENDS END START
Warum geht das irgendwie net richtig (bzw. wird mir lauter schrott ausgegeben, und nicht "Imagine all the people!")?
Und: ich kann "PRINT" nur einmal in "Ausgabe.asm" benutzen, weil dann die Fehler- Meldung kommt, dass der Offset Message bereits definiert wurde. Wie stelle ich das an?
[ Dieser Beitrag wurde am 08.04.2003 um 13:15 Uhr von pAngel editiert. ]
-
Hi.
Der Assembler setzt die Macros genau so, wie sie oben definiert sind ein... D.h. bei der Aufloesung deines Macros wird folgender Code produziert:
DATA SEGMENT DATA ENDS STACK SEGMENT BYTE STACK DW 128 DUP (?) STACK ENDS CODE SEGMENT START: ASSUME SS:STACK, DS:DATA, ES:NOTHING, CS:CODE MESSAGE DB "Imagine all the people!", 10, 13, "$" MOV DX, OFFSET MESSAGE MOV AH, 09H INT 21H MOV AH, 4CH INT 21H CODE ENDS END START
Wie man sieht, wird hierbei der Text mit "ausgefuehrt".
-
Original erstellt von Nobuo T:
Wie man sieht, wird hierbei der Text mit "ausgefuehrt".hä?
-
DB "Imagine all the people!", 10, 13, "$"
entspricht:
DB 49h, 6Dh, 61h, 67h, 69h, 6Eh, 65h, 20h, 61h, 6Ch, 6Ch, 20h, 74h, 68h, 65h, 20h, 70h, 65h, 6Fh, 70h, 6Ch, 65h, 21h, 0Ah, 0Dh, 24h
und das wiederum entspricht folgenden OpCodes:
dec cx
insw
popa
imul bp,[esi+65h],6120h
insb
insb
and [si+68h],dh
and gs:[bx+si+65h],dh
outsw
jo $+6Ch
and gs:[bp+si],cx
or ax,0BA24hDas alles wird in deinem code ausgefuehrt, bevor der Int 21h zum Textausgeben aufgerufen wird...
Dabei verschwindet zB. das erste Byte der Instruktion mov dx,offset MESSAGE in der Instruktion or ax,0BA24h (mov dx,????h ist 0BAh,??h,??h)
Somit gibts ein falsches Offset in dx und es wird noch ein bissel was im Segment 0000h (die Instruktionen mit gs) umgeschrieben...Hoffe das war jetzt verstaendlich.
[ Dieser Beitrag wurde am 08.04.2003 um 14:41 Uhr von Nobuo T editiert. ]
[ Dieser Beitrag wurde am 08.04.2003 um 14:45 Uhr von Nobuo T editiert. ]
-
hm... und was kann man dagegen machen?
[ Dieser Beitrag wurde am 08.04.2003 um 14:49 Uhr von pAngel editiert. ]
-
Man koennte zB. den Text ueberspringen.
PRINT MACRO STRING
jmp short @@PrintText
MESSAGE DB STRING, 10, 13, "$"
@@PrintText:
MOV DX, OFFSET MESSAGE
MOV AH, 09H
INT 21H
ENDMDabei ergibt sich natuerlich wieder das leidige Problem mit den doppelt definierten Symbolen, wenn Du versuchst 2 dieser Macros in einer proc unterzubringen... Hab fuer dieses Problem leider noch keine wirklich sinnvolle Loesung gefunden.
-
also sind diese Variablen oder Offsets in Assembler alle global?
Eine Lösung dafür wird also wirklich schwierig ...Übrigens geht das mit "JMP" auch nicht, aber ich weiß, was du meinst und warum es nicht geht ...
[ Dieser Beitrag wurde am 08.04.2003 um 20:11 Uhr von pAngel editiert. ]