Aufrufkonvention - Calling convention

In der Informatik ist eine Aufrufkonvention ein Schema auf Implementierungsebene (Low-Level), wie Unterroutinen Parameter von ihrem Aufrufer empfangen und wie sie ein Ergebnis zurückgeben. Unterschiede in verschiedenen Implementierungen umfassen , in denen Parameter, Rückgabewerte , Rückkehr - Adressen und Umfang Links platziert werden ( Register , Stapel oder Speicher etc.) und wie die Aufgaben für einen Funktionsaufruf der Vorbereitung und die Wiederherstellung der Umwelt danach zwischen dem Anrufer unterteilt sind und die Angerufener.

Aufrufkonventionen können sich auf die Evaluierungsstrategie einer bestimmten Programmiersprache beziehen , werden aber meistens nicht als Teil davon betrachtet (oder umgekehrt), da die Evaluierungsstrategie normalerweise auf einer höheren Abstraktionsebene definiert und nicht als Teil der Sprache angesehen wird als Low-Level-Implementierungsdetail des Compilers einer bestimmten Sprache .

Variationen

Aufrufkonventionen können sich unterscheiden in:

  • Wo Parameter, Rückgabewerte und Rückgabeadressen platziert werden (in Registern , auf der Aufrufliste , einer Mischung aus beidem oder in anderen Speicherstrukturen)
  • Für Parameter, die im Speicher übergeben werden, die Reihenfolge, in der tatsächliche Argumente für formale Parameter übergeben werden (oder die Teile eines großen oder komplexen Arguments)
  • Wie ein (möglicherweise langer oder komplexer) Rückgabewert vom Angerufenen an den Aufrufer zurückgeliefert wird (auf dem Stack, in einem Register oder innerhalb des Heaps)
  • Wie die Aufgabe des Einrichtens und Aufräumens nach einem Funktionsaufruf zwischen Anrufer und Angerufenem aufgeteilt wird
  • Ob und wie Metadaten , die die Argumente beschreiben, übergeben werden
  • Wo der vorherige Wert des Rahmenzeigers gespeichert wird, der verwendet wird, um den Rahmenzeiger wiederherzustellen, wenn die Routine endet (im Stapelrahmen oder in einem Register)
  • Wo statische Bereichslinks für den nicht-lokalen Datenzugriff der Routine platziert werden (normalerweise an einer oder mehreren Positionen im Stack-Frame, manchmal jedoch in einem allgemeinen Register oder bei einigen Architekturen in Spezialregistern)
  • Die Zuweisung lokaler Variablen kann manchmal auch Teil der Aufrufkonvention sein (wenn der Aufrufer für den Aufgerufenen allokiert)

In einigen Fällen umfassen die Unterschiede auch Folgendes:

  • Konventionen, nach denen Register vom Angerufenen direkt verwendet werden können, ohne dass sie beibehalten werden
  • Welche Register gelten als flüchtig und müssen, wenn sie flüchtig sind, vom Angerufenen nicht wiederhergestellt werden

Viele Architekturen haben nur eine weit verbreitete Aufrufkonvention, die oft vom Architekten vorgeschlagen wird. Für RISCs einschließlich SPARC, MIPS und RISC-V werden häufig Registernamen verwendet, die auf dieser Aufrufkonvention basieren. MIPS-Register $4bis $7haben beispielsweise "ABI-Namen" $a0bis $a3, was ihre Verwendung für die Parameterübergabe in der Standardaufrufkonvention widerspiegelt. (RISC-CPUs haben viele gleichwertige Universalregister, daher gibt es normalerweise keinen Hardwaregrund, ihnen andere Namen als Zahlen zu geben.)

Obwohl einige Programmiersprachen die Aufrufsequenz teilweise in der Sprachspezifikation oder in einer zentralen Implementierung spezifizieren können, können verschiedene Implementierungen solcher Sprachen (dh verschiedene Compiler ) immer noch verschiedene Aufrufkonventionen verwenden, und eine Implementierung kann eine Auswahl von mehr als einem Aufruf bieten Konvention. Gründe dafür sind Leistungsfähigkeit, häufige Anpassung an die Konventionen anderer populärer Sprachen, mit oder ohne technische Gründe, sowie Einschränkungen oder Konventionen, die von verschiedenen „ Rechenplattformen “ auferlegt werden .

Architekturen

x86 (32-Bit)

Die x86-Architektur wird mit vielen verschiedenen Aufrufkonventionen verwendet. Aufgrund der geringen Anzahl von Architekturregistern und des historischen Fokus auf Einfachheit und kleine Codegröße übergeben viele x86-Aufrufkonventionen Argumente auf dem Stapel. Der Rückgabewert (oder ein Zeiger darauf) wird in einem Register zurückgegeben. Einige Konventionen verwenden Register für die ersten paar Parameter, was die Leistung verbessern kann, insbesondere für kurze und einfache Blattroutinen, die sehr häufig aufgerufen werden (dh Routinen, die keine anderen Routinen aufrufen).

Beispielaufruf:

 push EAX            ; pass some register result
 push dword [EBP+20] ; pass some memory variable (FASM/TASM syntax)
 push 3              ; pass some constant
 call calc           ; the returned result is now in EAX

Typische Angerufene-Struktur: ( einige oder alle (außer ret) der folgenden Anweisungen können in einfachen Prozeduren wegoptimiert werden ). Einige Konventionen lassen den Parameterraum zugewiesen und verwenden plain retstatt ret imm16. In diesem Fall könnte sich der Anrufer add esp,12in diesem Beispiel oder anderweitig mit dem Wechsel zu ESP befassen.

calc:
  push EBP            ; save old frame pointer
  mov EBP,ESP         ; get new frame pointer
  sub ESP,localsize   ; reserve stack space for locals
  .
  .                   ; perform calculations, leave result in EAX
  .
  mov ESP,EBP         ; free space for locals
  pop EBP             ; restore old frame pointer
  ret paramsize       ; free parameter space and return.

ARM (A32)

Die standardmäßige 32-Bit- ARM- Aufrufkonvention weist die 15 Universalregister wie folgt zu:

  • r15: Programmzähler (gemäß Befehlssatzspezifikation).
  • r14: Linkregister. Der BL-Befehl, der in einem Unterprogrammaufruf verwendet wird, speichert die Rückkehradresse in diesem Register.
  • r13: Stapelzeiger. Die Push/Pop-Befehle in der Betriebsart "Daumen" verwenden nur dieses Register.
  • r12: Intra-Procedure-Call-Scratch-Register.
  • r4 bis r11: Lokale Variablen.
  • r0 bis r3: Argumentwerte, die an ein Unterprogramm übergeben werden, und Ergebnisse, die von einem Unterprogramm zurückgegeben werden.

Wenn der zurückgegebene Werttyp zu groß ist, um in r0 bis r3 zu passen, oder dessen Größe zur Kompilierzeit nicht statisch bestimmt werden kann, muss der Aufrufer zur Laufzeit Platz für diesen Wert zuweisen und einen Zeiger auf diesen Platz in r0 übergeben.

Subroutinen müssen den Inhalt von r4 bis r11 und den Stack-Zeiger beibehalten (vielleicht indem sie sie in der Funktion prologue auf dem Stack speichern, sie dann als Scratch-Space verwenden und sie dann in der Funktion epilogue vom Stack wiederherstellen ). Insbesondere Subroutinen , die andere Subroutinen aufrufen muss die Absenderadresse in den Link - Register r14 auf den Stapel speichern , bevor die anderen Unterprogramme aufrufen. Solche Unterprogramme müssen diesen Wert jedoch nicht an r14 zurückgeben – sie müssen diesen Wert lediglich in r15, den Programmzähler, laden, um zurückzukehren.

Die ARM-Aufrufkonvention verlangt die Verwendung eines vollständig absteigenden Stapels.

Diese Aufrufkonvention bewirkt, dass eine "typische" ARM-Subroutine:

  • Schieben Sie im Prolog r4 bis r11 auf den Stack und schieben Sie die Rückkehradresse in r14 auf den Stack (dies kann mit einem einzigen STM-Befehl erfolgen);
  • Kopieren Sie alle übergebenen Argumente (in r0 bis r3) in die lokalen Scratch-Register (r4 bis r11);
  • Weisen Sie den verbleibenden lokalen Scratch-Registern (r4 bis r11) andere lokale Variablen zu;
  • Führen Sie Berechnungen durch und rufen Sie nach Bedarf andere Unterprogramme mit BL auf, vorausgesetzt, r0 bis r3, r12 und r14 bleiben nicht erhalten;
  • Tragen Sie das Ergebnis in r0 ein;
  • Ziehen Sie im Epilog r4 bis r11 vom Stapel und ziehen Sie die Rückkehradresse zum Programmzähler r15. Dies kann mit einem einzigen LDM-Befehl erfolgen.

ARM (A64)

Die 64-Bit-ARM ( AArch64 ) -Aufrufkonvention weist die 31 Universalregister wie folgt zu :

  • x31 (SP): Stack-Pointer oder ein Nullregister, je nach Kontext.
  • x30 (LR): Prozedur-Link-Register, wird verwendet, um von Unterprogrammen zurückzukehren.
  • x29 (FP): Rahmenzeiger.
  • x19 bis x29: Angerufener gespeichert.
  • x18 (PR): Plattformregister. Wird für einige betriebssystemspezifische Sonderzwecke oder ein zusätzliches vom Anrufer gespeichertes Register verwendet.
  • x16 (IP0) und x17 (IP1): Intra-Procedure-Call-Scratch-Register.
  • x9 bis x15: Lokale Variablen, Anrufer gespeichert.
  • x8 (XR): Indirekte Rückgabewertadresse.
  • x0 bis x7: Argumentwerte, die an eine Subroutine übergeben werden, und Ergebnisse, die von einer Subroutine zurückgegeben werden.

Alle Register, die mit x beginnen, haben ein entsprechendes 32-Bit-Register mit dem Präfix w . Daher heißt ein 32-Bit-x0 w0.

In ähnlicher Weise werden die 32 Gleitkommaregister wie folgt zugewiesen:

  • v0 bis v7: Argumentwerte, die an eine Subroutine übergeben und Ergebnisse von einer Subroutine zurückgegeben werden.
  • v8 bis v15: Callee-saved, aber nur die unteren 64 Bit müssen erhalten bleiben.
  • v16 bis v31: Lokale Variablen, Anrufer gespeichert.

PowerPC

Die PowerPC- Architektur hat eine große Anzahl von Registern, so dass die meisten Funktionen alle Argumente in Registern für Single-Level- Aufrufe übergeben können. Zusätzliche Argumente werden auf dem Stack übergeben, und Platz für registerbasierte Argumente wird auch immer auf dem Stack zugewiesen, um die aufgerufene Funktion zu vereinfachen, falls mehrstufige Aufrufe verwendet werden (rekursiv oder anderweitig) und die Register gespeichert werden müssen. Dies ist auch in variadischen Funktionen von Nutzen , z. B. printf(), bei denen auf die Argumente der Funktion als Array zugegriffen werden muss. Für alle prozeduralen Sprachen wird eine einzige Aufrufkonvention verwendet.

MIPS

Das O32 ABI ist aufgrund seines Status als ursprüngliches System V ABI für MIPS das am häufigsten verwendete ABI . Es ist streng stapelbasiert, mit nur vier Registern, die für die Übergabe von Argumenten verfügbar sind. Diese wahrgenommene Langsamkeit hat zusammen mit einem antiken Gleitkommamodell mit nur 16 Registern die Verbreitung vieler anderer Rufkonventionen gefördert. Das ABI nahm 1990 Gestalt an und wurde seit 1994 nicht mehr aktualisiert. Es ist nur für 32-Bit-MIPS definiert, aber GCC hat eine 64-Bit-Variante namens O64 entwickelt. $a0-$a3

Für 64-Bit wird am häufigsten das N64 ABI (nicht verwandt mit Nintendo 64 ) von Silicon Graphics verwendet. Die wichtigste Verbesserung besteht darin, dass jetzt acht Register für die Argumentübergabe verfügbar sind; Es erhöht auch die Anzahl der Gleitkommaregister auf 32. Es gibt auch eine ILP32-Version namens N32, die 32-Bit-Zeiger für kleineren Code verwendet, analog zum x32 ABI . Beide laufen im 64-Bit-Modus der CPU.

Es wurden einige Versuche unternommen, O32 durch ein 32-Bit-ABI zu ersetzen, das N32 mehr ähnelt. Auf einer Konferenz von 1995 wurde MIPS EABI entwickelt, für das die 32-Bit-Version ziemlich ähnlich war. EABI hat MIPS Technologies dazu inspiriert, ein radikaleres "NUBI"-ABI vorzuschlagen, das zusätzlich Argumentregister für den Rückgabewert wiederverwendet. MIPS EABI wird von GCC unterstützt, jedoch nicht von LLVM; weder unterstützt NUBI.

Für alle O32 und N32/N64 wird die Rücksprungadresse in einem $raRegister gespeichert . Dies wird automatisch mit den Anweisungen JAL(Sprung und Link) oder JALR(Sprung und Link Register) eingestellt. Der Stapel wächst nach unten.

SPARC

Die SPARC- Architektur ist im Gegensatz zu den meisten RISC- Architekturen auf Registerfenstern aufgebaut . Es gibt 24 zugängliche Register in jedem Registerfenster: 8 sind die "in"-Register (%i0-%i7), 8 sind die "lokalen" Register (%l0-%l7) und 8 sind die "out"-Register (% o0-%o7). Die "in"-Register werden verwendet, um Argumente an die aufgerufene Funktion zu übergeben, und alle zusätzlichen Argumente müssen auf den Stack gelegt werden . Allerdings wird von der aufgerufenen Funktion immer Platz zugewiesen, um einen möglichen Registerfensterüberlauf, lokale Variablen und (bei 32-Bit-SPARC) eine Struktur nach Wert zurückzugeben. Um eine Funktion aufzurufen, platziert man die Argumente für die aufzurufende Funktion in den "out"-Registern; Wenn die Funktion aufgerufen wird, werden die "out"-Register zu den "in"-Registern und die aufgerufene Funktion greift auf die Argumente in ihren "in"-Registern zu. Wenn die aufgerufene Funktion abgeschlossen ist, platziert sie den Rückgabewert im ersten "In"-Register, das bei der Rückkehr der aufgerufenen Funktion zum ersten "Out"-Register wird.

Das System V ABI , dem die meisten modernen Unix- ähnlichen Systeme folgen, übergibt die ersten sechs Argumente in den "in"-Registern %i0 bis %i5, wobei %i6 für den Rahmenzeiger und %i7 für die Rücksprungadresse reserviert ist.

IBM System/360 und Nachfolger

Das IBM System/360 ist eine weitere Architektur ohne Hardware-Stack. Die folgenden Beispiele veranschaulichen die Aufrufkonvention, die von OS/360 und Nachfolgern vor der Einführung von 64-Bit z/Architecture verwendet wurde ; andere Betriebssysteme für System/360 haben möglicherweise andere Aufrufkonventionen.

Aufrufprogramm:

     LA  1,ARGS      Load argument list address
     L   15,=A(SUB)  Load subroutine address
     BALR 14,15      Branch to called routine1
     ...
ARGS DC A(FIRST)     Address of 1st argument
     DC A(SECOND)
     ...
     DC A(THIRD)+X'80000000' Last argument2

Aufgerufenes Programm:

SUB  EQU *            This is the entry point of the subprogram

Standardeingabereihenfolge:

     USING *,153
     STM 14,12,12(13) Save registers4
     ST  13,SAVE+4    Save caller's savearea addr
     LA  12,SAVE      Chain saveareas
     ST  12,8(13)
     LR  13,12
     ...

Standard-Rücklaufreihenfolge:

     L   13,SAVE+45
     LM  14,12,12(13)
     L   15,RETVAL6
     BR  14          Return to caller
SAVE DS  18F         Savearea7

Anmerkungen:

  1. Die BALRAnweisung speichert die Adresse der nächsten Anweisung (Rücksprungadresse) in dem durch das erste Argument spezifizierten Register – Register 14 – und verzweigt zur zweiten Argumentadresse in Register 15.
  2. Der Aufrufer übergibt die Adresse einer Liste von Argumentadressen in Register 1. Bei der letzten Adresse ist das höherwertige Bit gesetzt, um das Ende der Liste anzuzeigen. Dadurch werden Programme, die diese Konvention verwenden, auf die 31-Bit- Adressierung beschränkt.
  3. Die Adresse der aufgerufenen Routine befindet sich in Register 15. Normalerweise wird diese in ein anderes Register geladen und Register 15 wird nicht als Basisregister verwendet.
  4. Der STMBefehl sichert die Register 14, 15 und 0 bis 12 in einem 72-Byte-Bereich, der vom Aufrufer bereitgestellt wird, der als Sicherungsbereich bezeichnet wird, auf den das Register 13 zeigt. Die aufgerufene Routine stellt ihren eigenen Sicherungsbereich zur Verwendung durch von ihr aufgerufene Unterroutinen bereit; die Adresse dieses Bereichs wird normalerweise während der gesamten Routine im Register 13 gehalten. Die folgenden Anweisungen STMaktualisieren Vorwärts- und Rückwärtsketten, die diesen Speicherbereich mit dem Speicherbereich des Anrufers verbinden.
  5. Die Rückkehrsequenz stellt die Register des Anrufers wieder her.
  6. Register 15 wird normalerweise verwendet, um einen Rückgabewert zu übergeben.
  7. Die statische Deklaration eines savearea in der aufgerufenen Routine macht es nicht-reentrant und nicht-rekursiv ; ein wiedereintretendes Programm verwendet einen dynamischen Sicherungsbereich, der entweder vom Betriebssystem erworben und bei der Rückkehr freigegeben wird, oder im Speicher, der vom aufrufenden Programm übergeben wird.

In der System/390 ABI und der z/Architecture ABI, die unter Linux verwendet werden:

  • Register 0 und 1 sind flüchtig
  • Register 2 und 3 werden für Parameterübergabe und Rückgabewerte verwendet
  • Register 4 und 5 werden auch für die Parameterübergabe verwendet
  • Register 6 wird für die Parameterübergabe verwendet und muss vom Angerufenen gespeichert und wiederhergestellt werden
  • Die Register 7 bis 13 sind für den Angerufenen bestimmt und müssen von ihm gespeichert und wiederhergestellt werden
  • Register 14 wird für die Rücksendeadresse verwendet
  • Register 15 wird als Stack-Pointer verwendet
  • Gleitkommaregister 0 und 2 werden für Parameterübergabe und Rückgabewerte verwendet
  • Die Gleitkommaregister 4 und 6 sind für den Angerufenen bestimmt und müssen von ihm gespeichert und wiederhergestellt werden
  • In z/Architecture werden die Gleitkommaregister 1, 3, 5 und 7 bis 15 vom Angerufenen verwendet
  • Zugriffsregister 0 ist für die Systemnutzung reserviert
  • Die Zugriffsregister 1 bis 15 sind für den Angerufenen bestimmt

SuperH

Registrieren Windows CE 5.0 gcc Renesas
R0 Rückgabewerte. Temporär zum Erweitern von Baugruppen-Pseudoanweisungen. Implizite Quelle/Ziel für 8/16-Bit-Operationen. Nicht erhalten. Rückgabewert, Anrufer speichert Variablen/temporär. Nicht garantiert
R1..R3 Dient als temporäre Register. Nicht erhalten. Anrufer hat Kratzer gespeichert. Strukturadresse (Anrufer speichern, standardmäßig) Variablen/temporär. Nicht garantiert
R4..R7 Die ersten vier Wörter von Integer-Argumenten. Der Argumentaufbaubereich bietet Platz, in den R4 bis R7 mit Argumenten überlaufen können. Nicht erhalten. Parameterübergabe, Aufrufer speichert Argumente. Nicht garantiert.
R8..R13 Dient als permanente Register. Konserviert. Callee speichert Variablen/temporär. Garantiert.
R14 Standardrahmenzeiger. (R8-R13 kann auch als Rahmenzeiger dienen und Blattroutinen können R1-R3 als Rahmenzeiger verwenden.) Erhalten. Frame Pointer, FP, Angerufene speichert Variablen/temporär. Garantiert.
R15 Dient als Stack-Pointer oder als permanentes Register. Konserviert. Stack Pointer, SP, Angerufene speichert Stapelzeiger. Garantiert.

Hinweis: "konserviert" behält sich das Speichern des Angerufenen vor; das gleiche gilt für "garantiert".

68k

Die gebräuchlichste Anrufkonvention für die Motorola 68000-Serie ist:

  • d0, d1, a0 und a1 sind Scratch-Register
  • Alle anderen Register sind angerufene gespeichert
  • a6 ist der Frame-Pointer, der durch eine Compiler-Option deaktiviert werden kann
  • Parameter werden von rechts nach links auf den Stack geschoben
  • Rückgabewert wird in d0 gespeichert

IBM 1130

Die IBM 1130 war eine kleine 16-Bit-Wort-adressierbare Maschine. Es hatte nur sechs Register plus Zustandsindikatoren und keinen Stack. Die Register sind Befehlsadressenregister (IAR) , Akkumulator (ACC) , Akkumulatorerweiterung (EXT) und drei Indexregister X1–X3. Das aufrufende Programm ist für das Sichern von ACC, EXT, X1 und X2 verantwortlich. Es gibt zwei Pseudooperationen zum Aufrufen von Unterprogrammen, CALLzum Codieren von nicht verschiebbaren Unterprogrammen, die direkt mit dem Hauptprogramm verknüpft sind, und LIBFzum Aufrufen verschiebbarer Bibliotheksunterprogramme über einen Transfervektor . Beide Pseudo-Ops werden zu einem Maschinenbefehl Verzweigen und Speichern IAR ( BSI) aufgelöst, der die Adresse des nächsten Befehls an seiner effektiven Adresse (EA) speichert und zu EA+1 verzweigt.

Argumente folgen auf die BSI‍—‌normalerweise sind dies Ein-Wort-Adressen von Argumenten‍—‌die aufgerufene Routine muss wissen, wie viele Argumente sie erwartet, damit sie sie bei der Rückkehr überspringen kann. Alternativ können Argumente in Registern übergeben werden. Funktionsroutinen gaben das Ergebnis in ACC für reelle Argumente oder an einer Speicherstelle zurück, die als Pseudoakkumulator für reelle Zahlen (FAC) bezeichnet wird. Argumente und die Rückkehradresse wurden unter Verwendung eines Offsets zum IAR-Wert adressiert, der an der ersten Stelle der Unterroutine gespeichert ist.

  *                  1130 subroutine example
     ENT  SUB        Declare "SUB" an external entry point
 SUB DC   0          Reserved word at entry point, conventionally coded "DC *-*"
 *                   Subroutine code begins here
 *                   If there were arguments the addresses can be loaded indirectly from the return addess
     LDX I 1 SUB     Load X1 with the address of the first argument (for example)
 ...
 *                   Return sequence
     LD      RES     Load integer result into ACC
 *                   If no arguments were provided, indirect branch to the stored return address
     B   I   SUB     If no arguments were provided
     END  SUB

Subroutinen in IBM 1130, CDC 6600 und PDP-8 (alle drei Computer wurden 1965 eingeführt) speichern die Rückkehradresse an der ersten Stelle einer Subroutine.

Überlegungen zur Implementierung

Diese Variabilität muss berücksichtigt werden, wenn in mehreren Sprachen geschriebene Module kombiniert werden oder wenn Betriebssystem- oder Bibliotheks- APIs aus einer anderen Sprache aufgerufen werden als der, in der sie geschrieben wurden. In diesen Fällen muss besonders darauf geachtet werden, dass die Aufrufkonventionen von Aufrufer und Aufrufer aufeinander abgestimmt sind. Sogar ein Programm, das eine einzige Programmiersprache verwendet, kann mehrere Aufrufkonventionen verwenden, die entweder vom Compiler zur Codeoptimierung ausgewählt oder vom Programmierer angegeben werden.

Gewindecode

Threaded-Code legt die gesamte Verantwortung für das Einrichten und Bereinigen nach einem Funktionsaufruf auf den aufgerufenen Code. Der aufrufende Code führt nichts anderes aus, als die aufzurufenden Unterroutinen aufzulisten. Dadurch wird der gesamte Funktions-Setup- und -Bereinigungscode an einem Ort – dem Prolog und Epilog der Funktion – und nicht an den vielen Stellen, an denen die Funktion aufgerufen wird, platziert. Dies macht Threaded-Code zur kompaktesten Aufrufkonvention.

Threaded-Code übergibt alle Argumente auf dem Stack. Alle Rückgabewerte werden auf dem Stack zurückgegeben. Dies macht naive Implementierungen langsamer als Aufrufkonventionen, die mehr Werte in Registern halten. Allerdings sind Threaded-Code-Implementierungen, die mehrere der obersten Stack-Werte in Registern zwischenspeichern – insbesondere die Rücksprungadresse – in der Regel schneller als Konventionen zum Aufrufen von Subroutinen, die die Rücksprungadresse immer in den Stack verschieben und ablegen.

PL/I

Die Standardaufrufkonvention für Programme, die in der PL/I- Sprache geschrieben sind, übergibt alle Argumente als Referenz , obwohl optional andere Konventionen angegeben werden können. Die Argumente werden für verschiedene Compiler und Plattformen unterschiedlich behandelt, aber normalerweise werden die Argumentadressen über eine Argumentliste im Speicher übergeben. Eine letzte, versteckte Adresse kann übergeben werden, die auf einen Bereich zeigt, der den Rückgabewert enthält. Aufgrund der Vielzahl der von PL/I unterstützten Datentypen kann auch ein Datendeskriptor übergeben werden, um beispielsweise die Länge von Zeichen- oder Bitfolgen, die Dimension und Grenzen von Arrays ( Dope-Vektoren ) oder das Layout und den Inhalt zu definieren einer Datenstruktur . Dummy-Argumente werden für Argumente erstellt, die Konstanten sind oder nicht mit dem Argumenttyp übereinstimmen, den die aufgerufene Prozedur erwartet.

Siehe auch

Verweise

Externe Links