Unterprogramme in Assembler

Kirby.exe

Top Contributor
@mihe7 Es ist wieder so weit....It`s Assembler time xD Könnte mir jemand erläutern wie Unterprogramme in Assembler funktionieren ?

In Java sind Unterprogramme z.B. Methoden:

Java:
public int getAnzahlCookies(int newCookie){
    return this.cookie + newCookie;
}

- Meine Fragen wäre z.B. wie übergebe ich Werte an das Unterprogramm?
- Ich weiß noch dass man irgendwie eine Rücksprung Adresse retten muss, jedoch wie und was genau?

Der Befehlsatz ist im Anhang :)
 

Anhänge

  • pHILOs_manual.pdf
    1,3 MB · Aufrufe: 6
Zuletzt bearbeitet:

mihe7

Top Contributor
Meine Fragen wäre z.B. wie übergebe ich Werte an das Unterprogramm?
Allgemein kann man das nicht sagen, da Du in Assembler alle Freiheiten hast. Du könntest z. B. Register, einen Stack oder einen fixen Speicherbereich verwenden. Das gilt natürlich auch für Rückgabewerte.

Ich weiß noch dass man irgendwie eine Rücksprung Adresse retten muss, jedoch wie und was genau?
Manual, ab Seite 8.
 

mihe7

Top Contributor
Noch ein Beispiel: unter DOS gibt's den berühmten Interrupt 21h für bestimmte Systemaufrufe. Ein Interrupt funktioniert zwar ein wenig anders aber das ändert am Prinzip der Parameter ja nichts. Das AH-Register wird mit der auszuführenden Funktion belegt (1. Parameter). Je nach Funktion können dann Parameter mit anderen Registern übergeben werden.

Code:
MOV dl, 65
MOV ah, 2 ; Ausgabe des in dl übergebenen Zeichens auf dem Bildschirm, also ein A
INT 21h
MOV ah, 0 ; Ende
INT 21h

Wenn Du die Übersetzung als .com-Datei speicherst und die unter DOS ausführst, erhältst Du ein A am Bildschirm ausgegeben. Für komplexere Dinge werden Speicheradressen in Registern übergeben. Der eigentliche Parameter befindet sich dann im Hauptspeicher. So gibt es die Funktion 9 (AH=9), bei der die Adresse eines Strings (also ein Zeiger auf den Beginn des Strings) in den Registern DS:DX erwartet wird.

Das gleiche Prinzip kannst Du natürlich für Unterprogramme verwenden. Bei mehreren Parametern bietet sich aber der Stack an, der ja auch nichts anderes ist als ein Bereich im Speicher.
 

Kirby.exe

Top Contributor
Noch ein Beispiel: unter DOS gibt's den berühmten Interrupt 21h für bestimmte Systemaufrufe. Ein Interrupt funktioniert zwar ein wenig anders aber das ändert am Prinzip der Parameter ja nichts. Das AH-Register wird mit der auszuführenden Funktion belegt (1. Parameter). Je nach Funktion können dann Parameter mit anderen Registern übergeben werden.

Code:
MOV dl, 65
MOV ah, 2 ; Ausgabe des in dl übergebenen Zeichens auf dem Bildschirm, also ein A
INT 21h
MOV ah, 0 ; Ende
INT 21h

Wenn Du die Übersetzung als .com-Datei speicherst und die unter DOS ausführst, erhältst Du ein A am Bildschirm ausgegeben. Für komplexere Dinge werden Speicheradressen in Registern übergeben. Der eigentliche Parameter befindet sich dann im Hauptspeicher. So gibt es die Funktion 9 (AH=9), bei der die Adresse eines Strings (also ein Zeiger auf den Beginn des Strings) in den Registern DS:DX erwartet wird.

Das gleiche Prinzip kannst Du natürlich für Unterprogramme verwenden. Bei mehreren Parametern bietet sich aber der Stack an, der ja auch nichts anderes ist als ein Bereich im Speicher.
Naja ich darf wie wunderschöne Ackermann Funktion moderieren :) Ich fuchse mich da schon irgendwie rein :) Danke für deine Hilfe
 
X

Xyz1

Gast
It`s Assembler time xD
Ok, sagen wir Du möchtest x-y (Subtraktion) in Assembler berechnen

File: TutorialJNI.java
Java:
public class TutorialJNI {
	static {
		System.loadLibrary("tutorial");
	}
	private native int calculate(int x, int y);
	public static void main(String[] args) {
		System.out.println(new TutorialJNI().calculate(4, 5));
	}
}


Compile: javac -h . TutorialJNI.java
File: TutorialJNI.h (maschinell erstellt)
C:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class TutorialJNI */

#ifndef _Included_TutorialJNI
#define _Included_TutorialJNI
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     TutorialJNI
 * Method:    calculate
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_TutorialJNI_calculate
  (JNIEnv *, jobject, jint, jint);

#ifdef __cplusplus
}
#endif
#endif


File: TutorialJNI.c (Die Subtraktion in asm...)
C:
#include <jni.h>
#include "TutorialJNI.h"
#include <stdint.h>

JNIEXPORT jint JNICALL Java_TutorialJNI_calculate(JNIEnv *env, jobject thisObj, jint x, jint y)
{
    uint32_t src1 = x;
    uint32_t src2 = y;
    uint32_t dst = 42;
    asm ("movl $1, %0\n\t"
    "subl $2, %0"
    : "=r" (dst) 
    : "r" (src1, src2));
    return dst;
}


Compile: x86_64-w64-mingw32-gcc -I"C:\Program Files\Java\jdk-12.0.1\include" -I"C:\Program Files\Java\jdk-12.0.1\include\win32" -shared -o tutorial.dll TutorialJNI.c
File: tutorial.dll

Run: java TutorialJNI
Result: ...:)

Das war auch schon alles
 
X

Xyz1

Gast
Ach ICH kann den Kram auch nicht super... Aber mir fällt gerade auf dass mit Funktionsprototypen (also Funktionsaufrufen) in Assembler nicht zu spaßen ist... Das ist eventuell auch nochmal eine Nuss. ;)
 

Kirby.exe

Top Contributor
Jap ich kämpfe gerade mit dem Stack....Ich glaube er mag mich einfach nicht xD Also ich bin mehr oder weniger fertig, muss halt noch irgendwie alle geretteten werde wieder vom Stack entnehmen :)
 
X

Xyz1

Gast
Oh Sorry ich habe jetzt in die PDF geschaut.... Die ganze Code Wurst oben brauchst Du nicht... das macht pHILOs bereits...

Weiterhin gutes Gelingen. :)
 

Kirby.exe

Top Contributor
Also vielleicht hat mir die Ackermann Funktion einfach das Hirn frittiert...aber jetzt mal eine blöde Frage, könnte mir jemand in Worten sagen wie man überprüft ob zwei Zahlen Vielfache voneinander sind?

Beispielsweise die Zahlen 2 und 4 :)
 
X

Xyz1

Gast
Also die Ackermann-Funktion wäre in C-Inline- Assembler nicht schwer... es gibt aber praktisch gar keine Vorteile gegenüber einer normalen C-Funktion. :D Oder?
 
X

Xyz1

Gast
Also das wär mein Verusch
C:
#include <jni.h>
#include "TutorialJNI.h"
#include <stdint.h>

jint add1(jint x)
{
    asm("movl %1, %0\n\t"
        "addl $1, %0"
        : "=r"(x)
        : "r"(x));
    return x;
}

jint sub1(jint x)
{
    asm("movl %1, %0\n\t"
        "subl $1, %0"
        : "=r"(x)
        : "r"(x));
    return x;
}

JNIEXPORT jint JNICALL Java_TutorialJNI_calculate(JNIEnv *env, jobject thisObj, jint x, jint y)
{
    if (x == 0)
    {
        return add1(y);
    }
    if (y == 0)
    {
        return Java_TutorialJNI_calculate(env, thisObj, sub1(x), 1);
    }
    return Java_TutorialJNI_calculate(env, thisObj, 
    sub1(x), Java_TutorialJNI_calculate(env, thisObj, x, sub1(y)));
}


Sieht furchtbar aus ich weiß... Aber gibt das richtig aus.

Und hier hat jemand das für ziemlich viele Assemblersprachen bereits gemacht:
https://rosettacode.org/wiki/Ackermann_function

@mihe7 für Ackermann(3, 8) kommt zum Bleistift 2045 raus - so weit kann ich gar nicht rechnen. :D
 

Kirby.exe

Top Contributor
Praktisch kannst Du die Ackermann-Funktion ohne nennenswerte Nachteile auch mit Hand ausrechnen :)
Habe ich getan :) Ist im Anhang für Ackermann(2,3) ;)

Meine Ackermann Lösung in pHILO`s ist so:

#Einlesen von n
addi zero t1 1
sysmove exc t1
syscall

#Einlesen von m
addi zero t2 2
sysmove exc t2
syscall

#schiebe die Zahlen wieder in Register
sysmove a0 I[0] # a0 = n
sysmove a1 I[1] # a1 = m

#Retten der Rücksprung Adresse
ldpc ra
addi ra ra 3
jmp ackermann


#Ausgabe des Ergebnis
sysmove O[0] v0
addi zero t6 6
sysmove exc t6
syscall
jmp ende

#Reguläre Beenden des Programms
ende:
sysmove exc zero
syscall


########################################################################################################
ackermann:

#Retten der Register auf den Stack
addi SP SP -12
sto SP ra 12
sto SP a0 8
sto SP a1 4

beq zero a0 first # falls n = 0
bgt a0 zero secondTest # n > 0
jmp third # else

secondTest:
beq zero a1 second # falls m = 0
jmp third # else


first:
ldd SP a1 4
addi a1 v0 1
ldd SP a1 4 # a1 vom Stack holen
ldd SP a0 8 # a0 vom Stack holen
ldd SP ra 12 # ra vom Stack holen
addi SP SP 12 #Stackpointer zurückschieben
stpc ra #Rücksprung

second:
addi a0 a0 -1
addi zero a1 1
ldpc ra
addi ra ra 3 #Rücksprung Adresse retten
jmp ackermann
ldd SP a1 4 # a1 vom Stack holen
ldd SP a0 8 # a0 vom Stack holen
ldd SP ra 12 # ra vom Stack holen
addi SP SP 12 #Stackpointer zurückschieben
stpc ra #Rücksprung

third:
addi a1 a1 -1
ldpc ra
addi ra ra 3 #Rücksprung Adresse retten
jmp ackermann
addi a0 a0 -1
addi v0 a1 0 #v1 in a1 kopieren
ldpc ra
addi ra ra 3 #Rücksprung Adresse retten
jmp ackermann
ldd SP a1 4 # a1 vom Stack holen
ldd SP a0 8 # a0 vom Stack holen
ldd SP ra 12 # ra vom Stack holen
addi SP SP 12 #Stackpointer zurückschieben
stpc ra #Rücksprung
 

Anhänge

  • Era_Aufgabe4a.pdf
    1,2 MB · Aufrufe: 2

Neue Themen


Oben