home *** CD-ROM | disk | FTP | other *** search
- Von: Michael Seyfried @ STA (So, 23.09.90 19:49)
-
- >Reg-Übergabe wie TC: (Auszüge aus TC Bunutzerhandbuch Seite 155ff)
-
- [Zitat on]
- [..]
- Normalerweise werden die Parameter nach einer gemischten Register/Stack-
- Konvention übergeben. Das bedeudet, daß solange wie möglich die schnelle
- Registerübergabe versucht wird und erst dann der Stack verwendet wird. Daten-
- typen wie char, int oder long werden in den Datenregistern D0-D2 übergeben.
- Adreßparameter (Zeiger) kommen in die Register A0-A1. Fließkommavariablen,
- wie float, double und long double werden immer über den Stack übergeben.
- Im Falle von Funktionen mit variabler Parameterzahl erfolgt die Übergabe
- in jedem Fall über den Stack. Dasselbe trifft für Funktionen zu, die
- explizit mit den Schlüsselworten pascal und cdecl deklariert wurden.
-
- Das Übergabeformat von C
-
- [..]
- Die Register D0-D2 und A0-A1 dienen als Parameterregister. Diese Register
- müssen naturgemäß nicht gesichert werden. Sie werden zum Teil auch für die
- Rückgabe von Ergebnissen verwendet. Skalare Parameter mit einer 8-, 16- oder
- 32-Bit Darstellung (z.B: char, int, long, *(Zeiger)) werden in Registern über-
- geben, soweit ausreichend Parameterregister zur Verfügung stehen. Dabei erfolgt
- die Zuteilung von Parametern auf Register getrennt nach Adreß- und Daten-
- parametern entsprechend folgender Konvention (1):
-
- 1. Der erste Adreßparameter wird in A0 übergeben, der zweite in A1, alle
- anderen auf dem Stack.
-
- 2. Anschließend wird der erste skalare Parameter in D0 übergeben, der zweite
- in D1, der dritte in D2, alle anderen auf dem Stack.
-
- [..]
-
- Diese Konvention gilt für alle Standardfunktionen. Funktionen mit variabler
- Parameterzahl arbeiten jedoch nur mit Stackübergabe. Das bedeutet, daß für
- die Übergabe keine Register verwendet werden (2). [..]
- Bei der reinen Stackübergabe, die sich übrigens mit der expliziten Verwen-
- dung des Schlüsselworts cdecl erzwingen läßt, werden die Parameter in umge-
- kehrter Reihenfolge auf den Stack gelegt. Wenn das Schlüsselwort pascal ver-
- wendet wird, werden die Parameter in der Reihenfolge der Argumente auf den
- Stack gelegt. [..]
-
- Wer ist wann für den Stack verantwortlich?
-
- Bei allen normal und mit cdecl deklarierten Funktionen muß die aufrufende
- Funktion nach dem Aufruf die Parameter selbst vom Stack holen (z.B: mit
- ADDQ.W #8, A7). Dies erübrigt sich natürlich, wenn alle Parameter in Registern
- übergeben wurden.
- Eine als pascal deklarierte Funktion räumt alle ihre Parameter vor der Rück-
- kehr selbst vom Stack ab. Nur die Funktionsresultate bleiben auf dem Stack.
-
- [..]
- Funktionsresultate
- [..]
-
- Für die Rückgabe von Funktionswerten gelten allgemein folgende Regeln:
-
- - Die Datentypen char, int, enum, und long werden im Register D0 zu-
- rückgeliefert. Zeigerresultate werden über A0 zurückgegeben.
- - Strukturen und Verbände (struct und union) werden per Adresse in A0
- zurückgegeben. Die Adresse der temponären Speicherstelle wird als letzter
- Parameter in den Adreßregistern beziehungsweise am Stack abgelegt (3).
-
- Erlaubete und unerlaubte Verwendung von Registern
-
- Die Register D3-D7 und A2-A6 müssen von allen Routinen gerettet werden, falls
- sie verwendet werden. Diese Register werden vom Compiler intern verwendet und
- stehen aus diesem Grunde nicht zur freien Verfügung.
- [Zitat off]
-
- Anmerkungen:
-
- ad 1: In dieser Regel wird leider wenig über die Reihenfolge der Parameter,
- die nicht in Register passen, auf dem Stack gesagt. Das wird folgen-
- dermaßen gehandhabt:
- a) Alle Parameter, die in Register passen werden gemäß 1. und 2. in
- Registern übergeben.
- b) Alle übrigen Parameter werden in der Reihenfolge von rechts nach
- links auf dem Stack übergeben. Siehe dazu Beispiel weiter unten.
- ad 2: Daß gar keine Register verwendet werden stimmt nicht. Die festen
- Parameter (z.B der Formatstring bei 'printf') werden nach der
- Standardkonvention (d.h. in Registern/Stack) übergeben. Alle variablen
- Parameter (z.B bei 'printf' alle Parameter nach dem Formatstring)
- werden in Reihenfolge von rechts nach links auf dem Stack übergeben.
- Siehe dazu ebenfalls Beispiel weiter unten.
- Da es aber in Modula-2 keine Prozeduren mit variabler Parameteranzahl
- gibt, müssen solche Prozeduren gesondert behandelt werden. Ich könnte
- vorerst ohne direkte Unterstützung dieser speziellen Parameter-
- übergabeart leben.
- ad 3: Diese Regel gilt offensichtlich für alle Datenstrukturen >32-Bit,
- also insbesondere auch für float, double , und long double.
-
-
- Beispielprogramm:
-
- int printf(const char *format, ... ); /* Prototyp */
-
- double p1(int i1,
- int *p1,
- int i2,
- int *p2,
- double d1,
- double *p3,
- int i3,
- int *p4,
- int i4,
- int *p5)
- {
- *p1 = i1;
- *p2 = i2;
- *p3 = d1;
- *p4 = i3;
- *p5 = i4;
- return i1 + i2 + i3 + i4 + d1;
- }
-
- int i1, i2, i3, i4;
- double d1, d;
-
- void main( void)
- {
- d = p1( 1, &i1, 2, &i2, 0.123456789, &d1, 3, &i3, 4, &i4);
- printf( "d: %10lf i1: %10d\n", d, i1);
- }
-
- Was der Compiler daraus macht (siehe Kommentar ab 'main'):
-
- DISPOBJ Object file browser Borland Intl. Scotts Valley
- Copyright (C) 1990 All Rights reserved
- Version 1.00
-
- * Object File "tcparam1"
-
-
- .TEXT
-
- .MODULE GLOBAL
-
- p1:
- T000000: MOVE.W D6,-(A7)
- T000002: LEA.L -$000A(A7),A7
- T000006: MOVE.W $0026(A7),D6
- T00000A: MOVE.W D0,(A0)
- T00000C: MOVE.W D1,(A1)
- T00000E: MOVEA.L $001E(A7),A0
- T000012: LEA.L $0014(A7),A1
- T000016: MOVE.L (A1)+,(A0)+
- T000018: MOVE.L (A1)+,(A0)+
- T00001A: MOVE.W (A1)+,(A0)+
- T00001C: MOVEA.L $0022(A7),A0
- T000020: MOVE.W D2,(A0)
- T000022: MOVEA.L $0028(A7),A1
- T000026: MOVE.W D6,(A1)
- T000028: ADD.W D1,D0
- T00002A: ADD.W D2,D0
- T00002C: ADD.W D6,D0
- T00002E: LEA.L (A7),A0
- T000030: JSR _wxcnv(PC)
- T000034: LEA.L (A7),A0
- T000036: LEA.L $0014(A7),A1
- T00003A: JSR _xxadd(PC)
- T00003E: MOVEA.L $0010(A7),A0
- T000042: LEA.L (A7),A1
- T000044: MOVE.L (A1)+,(A0)+
- T000046: MOVE.L (A1)+,(A0)+
- T000048: MOVE.W (A1)+,(A0)+
- T00004A: LEA.L $000A(A7),A7
- T00004E: MOVE.W (A7)+,D6
- T000050: RTS
-
- .MODULE GLOBAL
-
- main:
- T000000: MOVE.L A2,-(A7) ; A2 wird gerettet
- T000002: LEA.L -$000A(A7),A7 ; 10 Bytes auf Stack für Returnwert
- T000006: LEA.L i1,A2 ; Basisadresse der Var's nach A2
- T00000C: PEA.L i4 ; Adresse von i4 auf Stack
- T000012: MOVEQ.L #$04,D0
- T000014: MOVE.W D0,-(A7) ; Wert 4 auf Stack
- T000016: PEA.L i3 ; Adresse von i3 auf Stack
- T00001C: PEA.L d1 ; Adresse von d1 auf Stack
- T000022: LEA.L +$0000001E,A0 ; 0.123456789 auf Stack
- T000028: MOVE.L -(A0),-(A7)
- T00002A: MOVE.L -(A0),-(A7)
- T00002C: MOVE.W -(A0),-(A7)
- T00002E: MOVEQ.L #$03,D2 ; Wert 3 in Parameterregister D2
- T000030: LEA.L $0002(A2),A1 ; Adresse von i2 in Parameterregister A1
- T000034: MOVEQ.L #$02,D1 ; Wert 2 in Parameterregister D1
- T000036: MOVEA.L A2,A0 ; Adresse von i1 in Parameterregister A0
- T000038: MOVEQ.L #$01,D0 ; Wert 1 in Parameterregister D0
- T00003A: PEA.L $0018(A7) ; Adresse von Returnwert auf den Stack
- T00003E: JSR p1(PC) ; Aufruf von 'p1'
- T000042: LEA.L $001C(A7),A7 ; Stackkorrektur und Ergebnis nach d:
- T000046: LEA.L (A7),A0
- T000048: LEA.L $0012(A2),A1
- T00004C: MOVE.L (A0)+,(A1)+
- T00004E: MOVE.L (A0)+,(A1)+
- T000050: MOVE.W (A0)+,(A1)+
- T000052: MOVE.W (A2),-(A7) ; i1 auf Stack
- T000054: LEA.L $001C(A2),A0 ; d auf Stack
- T000058: MOVE.L -(A0),-(A7)
- T00005A: MOVE.L -(A0),-(A7)
- T00005C: MOVE.W -(A0),-(A7)
- T00005E: LEA.L ,A0 ; Adresse von Formatstring nach A0
- T000064: JSR printf(PC) ; Aufruf von 'printf'
- T000068: LEA.L $000C(A7),A7 ; Stackkorrektur und Prozedurende:
- T00006C: LEA.L $000A(A7),A7
- T000070: MOVEA.L (A7)+,A2
- T000072: RTS
-
-
- .DATA
-
- .MODULE LOCAL
-
- D000000: .DC.W $643A ,$2025 ,$3130 ,$6C66 ,$2020 ,$6931 ,$3A20 ,$2531
- D000010: .DC.W $3064 ,$0A00 ,$3FFB ,$FCD6 ,$E9B9 ,$CB1A ,$F989
-
-
- .BSS
-
- .MODULE LOCAL
-
- i1::
- B000000: .DS.B 2
- i2::
- B000002: .DS.B 2
- i3::
- B000004: .DS.B 2
- i4::
- B000006: .DS.B 2
- d1::
- B000008: .DS.B 10
- d::
- B000012: .DS.B 10
-
-
- .END
-
- Stackframe beim Call von p1:
-
- Datenregister | Stack | Adreßregister
- ---------------|--------------|----------------
- D0: 1 | ADR( i4) | A0: ADR( i1)
- D1: 2 | 4 | A1: ADR( i2)
- D2: 3 | ADR( i3) |
- | ADR( d1) |
- | 0.123456789 |
- | ADR( return) |
-
- Dabei ist ADR( return) die lokale Adresse, an der der Returnwert gespeicht
- wird. Dieser ist ja vom Typ 'double' und wird daher nicht in D0/A0 übergeben.
-
- Stackframe beim Call von 'printf'
-
- Datenregister | Stack | Adreßregister
- ---------------------------------------------------------
- D0: - | i1 | A0: ADR( Formatstring)
- D1: - | d | A1: -
- D2: - | |
-
- Der Formatstring ist ein fester Parameter und wird deshalb nach Standard-
- konvention (hier: Register A0 für ersten Adreßparameter) übergeben.
-
- Das ganze ist wohl nicht ganz einfach zu implementieren. Ich glaube aber,
- daß sich der Aufwand lohnt. Man hätte dann echtes Multilanguage Programming
- auf dem ST/TT.
-
- END
-
-