Forum: PC Hard- und Software ax-Wert übergeben an andere Routine mit bx


von Peter B. (funkheld)


Lesenswert?

Hallo, guten Tag.
Wie kann man bitte einen Wert an eine andere Routine übergeben.

In add1 wird ein Wert an ax übergeben.
In Add2  wird wird ein Wert an bx übergeben und ax und bx werden 
addiert.
Und den Wert von Add2 möchte ich dann nutzen.

Wie kann das bitte funktionieren?

Danke.

--------------------------
.model medium, basic
.stack 200h
.386
.code

public Add1
Add1 proc
   push bp
   mov  bp, sp
   mov  ax, [bp+6]
   pop  bp
   ret  2
Add1 endp

public Add2
Add2   PROC
   push bp
   mov bp,sp
   mov bx,[bp+6]
   pop bp

   add ax,bx

   RET 2
Add2  ENDP

end
------------------------

von Ben B. (Firma: Funkenflug Industries) (stromkraft)


Lesenswert?

Hä?

Welchen Wert von add2?

Den Kram hast Du doch nie selbst geschrieben... die Funktionen machen so 
überhaupt keinen Sinn, zumindest erkenne ich den aus den Schnipseln 
nicht. Was soll das Gewurstel mit dem Stack?

add2 zerstört jedenfalls erstmal den Inhalt von AX und BX, AX evtl. 
gewollt, BX wird nicht gesichert.

von Programmierer (Gast)


Lesenswert?

Kann irgendwer mal Mitleid haben und dem Kerl einen Haufen 
x86-Assembler-Bücher schicken... Ist ja nicht mit anzusehen wie er sich 
jeden Fitzel einzeln erfragt.

von Ben B. (Firma: Funkenflug Industries) (stromkraft)


Lesenswert?

Bei ADD AX,BX wird AX mit dem Ergebnis überschrieben.

Wenn man die Summanden in AX und BX behalten möchte, muß man etwas mehr 
Aufwand betreiben. Bspw. sowas wie

MOV AX, summand1
MOV BX, summand2

MOV DX, AX
ADD DX, BX

Danach hat man das Ergebnis in DX, AX und BX bleiben erhalten.

Und Vorsicht, wenn die Summe größer als 65535 ist, läuft DX über bzw. 
das höchstwertige Bit landet im Übertragsflag.

von rbx (Gast)


Lesenswert?

Peter B. schrieb:
> Und den Wert von Add2 möchte ich dann nutzen

Schreib doch einfach, in welcher Weise genau und unter welchen genauen 
Umständen, eventuell gibt es dann auch genauere Antworten.

Schmunzeln kann ich mir hier nicht verkneifen, weil die Frage ein wenig 
an Haskell erinnert, und da die Frage nach Monaden heraufbeschwört, die 
für sich nicht so einfach zu beantworten wäre.
(Da würde ich aber schreiben: einfach (erstmal) die (dazu) gängige 
Grammatik auswendig lernen.)

von oerks (Gast)


Lesenswert?

Was nuetzt ihm die Grammatik wenn er die Rechtschreibung nicht kennt.

von Thomas Z. (usbman)


Lesenswert?

Ben B. schrieb:
> Den Kram hast Du doch nie selbst geschrieben... die Funktionen machen so
> überhaupt keinen Sinn, zumindest erkenne ich den aus den Schnipseln
> nicht. Was soll das Gewurstel mit dem Stack?

natürlich hat er das nicht selbst geschrieben. Er hat ja den typischen 
Prolog/epilog eines compilers. ich würde behaupten Add1 sieht so aus
uint16_t Add1(uint16_t param) { return param; }

Bei Add2 ist AX undefinert weshalb er vermutlich einen Weg sucht AX zu 
laden

Da er aber nicht versteht wie die Parameterübergabe auf dem Stack 
funktioniert kommt dann halt so ein sinloses Codeschipsel.

.386 ist ja nur ein weiters Zeichen dass er nicht weiss was er macht.

Thomas

von oerks (Gast)


Lesenswert?

> .386

Wenn er erst .586 entdeckt wirds lustig.

von Thomas Z. (usbman)


Lesenswert?

folgender c code
1
uint16_t Add2(uint16_t v1,v2)
2
{
3
   return v1 + v2;
4
}

entspricht in etwa diesem Assembler code. Immer unter der Vorraussetzung 
dass der compiler near code erzeugt. und die Funktion selbst die 
parameter vom stack holt.
1
public Add2
2
Add2   PROC near
3
   push bp      ; prolog
4
   mov bp,sp
5
6
   mov bx,[bp+6]; erster parameter
7
   mov ax,[bp+8]; zweiter parameter
8
   add ax,bx    ; ergebnis zurück in AX
9
10
   pop bp       ; epilog
11
   RET 4
12
Add2  ENDP

@TO wie du siehst helfen Kommentare ungemein

: Bearbeitet durch User
von Ben B. (Firma: Funkenflug Industries) (stromkraft)


Lesenswert?

> Bei Add2 ist AX undefinert weshalb er vermutlich
> einen Weg sucht AX zu laden
In Assembler ist nie irgendwas undefiniert, es ist höchstens "leer" bzw. 
enthält nicht das was man haben wollte oder erwartet hat.

Wenn man in seinem Beispiel beide Funktionen (Add1 und Add2) direkt 
nacheinaner ausführt, läd Add1 AX für Add2. Mega-umständlich, aber kann 
man machen (im Sinne von das würde so funktionieren).

von rbx (Gast)


Lesenswert?

Man kann sich aber schon ein wenig darüber wundern, warum der 
abgeschriebene Code keinen Platz bzw. ( 
http://www.c-jump.com/CIS77/ASM/Instructions/I77_0250_ptr_pointer.htm ) 
keinen 16 Bit-int für das Ergebnis gelassen hat.

Erst recht, weil Addition ja noch geht, Multiplikation dagegen.. ;)

Was ich mich nämlich oft gefragt hatte, war - wie haben die das nur 
immer mit den 8-Bit-Kisten (oder Taschenrechnern) so hinbekommen?

von Ben B. (Firma: Funkenflug Industries) (stromkraft)


Lesenswert?

Im Grunde sind das ähnliche Verfahren wie Du solche Aufgaben schriftlich 
lösen würdest. Da teilst Du die Aufgabe auch in mehrere kleine Teile und 
genau so macht es ein Computer auch.

Zwei 16-Bit-Werte kann der x86 auch problemlos multiplizieren, das 
Ergebnis landet dann in DX:AX wenn ich mich recht erinnere. Also in DX 
die oberen 16 Bit und in AX die unteren. Habe ich aber seeeeehr lange so 
nicht mehr gebraucht, also nagelt mich nicht darauf fest.

von Funkdepphasser (Gast)


Lesenswert?

Programmierer schrieb:
> Kann irgendwer mal Mitleid haben und dem Kerl einen Haufen
> x86-Assembler-Bücher schicken... Ist ja nicht mit anzusehen wie er sich
> jeden Fitzel einzeln erfragt.

Peter B.Löd ist doch schon zu dämlich Google zu benutzen. Der fragt dann 
das Buch und es kommt keine Antowrt aus dem nicht-eingebauten 
Lautsprecher raus.
Wo ist eigentlich sein Arschabwischer cppbert geblieben?

von rbx (Gast)


Lesenswert?

Ben B. schrieb:
> also nagelt mich nicht darauf fest

passt schon, man kann auch mit AL/AH multiplizieren. Das schöne bei mul 
BX bzw. div BX (o.ä.) ist, dass bei beim Aufteilen der Rest im 
DX-Register landet.
Bevor man damit anfängt, muss unbedingt DX initialisiert werden!

https://www.tutorialspoint.com/assembly_programming/assembly_arithmetic_instructions.htm

Der TO/TE muss sich aber festlegen,

a)wieviel Schritte er mit seinem Stackzeiger gehen will bzw. muss.
b)welches Datenformat die Routine, die den berechneten Wert aufnehmen 
soll, haben sollte.

BP+6 hat in dieser Hinsicht wenig Auskunft über die Übergabeform - 
könnte man aber zur Übung als "Summe" missbrauchen.

Wenn man genau weiß, wo der Stackzeiger gerade hinzeigt, bzw. was man 
nicht überschreiben möchte, dann könnte ein push AX in der Routine 
reichen.

Lässt man den Stack weg, dann kann man einfach den Speicherbereich 
hinter dem Programm nutzen. Dazu muss man ausrechnen, wie groß das 
Programm wird, bzw. wo der Datenbereich anfangen kann.
D.h. man kann z.B. den Speicherzeigern erstmal Dummy-Namen geben.
Wenn man keine Lust zum Rechnen hat, dann kann man den Datenbereich 
extra weiter hinten anlegen, und die Schritte Alignmentfreundlich 
gestalten bzw. z.B. BX (irgendwo weiter hinten) + 10h oder BX + 100h 
oder von mir aus und wenn es Spaß macht, BX + Si und später die 
Feinabstimmung im Hexeditor machen.

von Ben B. (Firma: Funkenflug Industries) (stromkraft)


Lesenswert?

Wie gesagt, das Gewurstel mit dem Stack verstehe ich nicht. Eigentlich 
probiert man in der Assembler-Programmierung auf maximale 
Geschwindigkeit zu optimieren, oder auf kleinste Codegröße.

XOR AX,AX ist z.B. kleiner als MOV AX,0

Zum Thema Geschwindigkeit: Das schnellste was da ist, sind die Register, 
also probiert man möglichst nur diese zu benutzen und jede Form von 
Speicherzugriffen zu vermeiden. In Zeiten von 64 Bit SSE/AVX stehen da 
auch richtig viele Register zur Verfügung, mit ordentlich Speicherplatz. 
Ansonsten  halt probieren, mit dem auszukommen, was da ist. In Assembler 
ist man an keine "Konventionen" gebunden, wenn ich z.B. ES oder DS 
gerade nicht brauche, kann man auch dort 16 Bit drin speichern. BP wird 
dafür sehr gerne genommen, oder SI/DI.

Oder versuchen, die zur Verfügung stehenden Features auch zu nutzen.

MOV ES:[DI],AX
ADD DI,2

macht z.B. das gleiche wie

STOSW

Bei Funktionen kann man sich den Umweg über den Stack sparen, solange 
Funktionen nicht rekursiv aufgerufen werden. Also z.B.

MOV AX,wert1
MOV BX,wert2
CALL (short) funktionsname
CMP AL,0 ;Rückgabewert, 0 für kein Fehler

Es macht auch Sinn, wenn die Funktionen ihre Rückgabewerte gleich in den 
passenden Registern zurückliefern. Beispielsweise

CALL (short) GetDataSize
CMP CX,0 ;Rückgabewert in CX passend für nachfolgende Schleifen

Naja kann man noch viel drüber schreiben. Leider werden wir wohl nie 
erfahren, was der TE eigentlich genau will.

von rbx (Gast)


Lesenswert?

Ben B. schrieb:
> Naja kann man noch viel drüber schreiben. Leider werden wir wohl nie
> erfahren, was der TE eigentlich genau will.

Zumindest ein wenig Taschenlampenlicht mit schwacher Batterie drauf 
werfen geht noch, ohne den Compi zu wechseln, oder auf den Dachboden 
gehen zu müssen:

https://forum.nasm.us/index.php?topic=2548.0
(Addierbeispiel mit zwei ints und dem Watcom Compiler und Nasm)

Dann noch die OpenWC userguide der Teil mit dem Hinweis auf Assembler
bzw. 16-bit Topics:
http://www.openwatcom.org/doc.php (cguide.pdf oben)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.