Zum Inhalt springen

Objektcode

aus Wikipedia, der freien Enzyklopädie
Dies ist eine alte Version dieser Seite, zuletzt bearbeitet am 2. August 2019 um 10:26 Uhr durch VÖRBY (Diskussion | Beiträge) (+ref). Sie kann sich erheblich von der aktuellen Version unterscheiden.

Objektcode ist ein Zwischenergebnis eines Compiler- bzw. Übersetzungsvorgangs von einem Computerprogramm. Einfache Compiler können diesen Schritt überspringen.

Der Objektcode besteht hauptsächlich aus Maschinencode für die Architektur, für die das Programm übersetzt wurde. Er enthält üblicherweise kompakten und vorgeparsten Code und oft benutzte Programmbibliotheken, die dann mit anderen Objektdateien gebunden werden.

Das Format eines Objektcodes ist abhängig von Programmiersprache, Compiler und der Maschine. Nach dem Erstellen von Objektcode erfolgt normalerweise das Linken, welches als Ergebnis das fertige, ausführbare Programm liefert.

Beispiel (Großrechner IBM-Welt)

Wie Module durch Aufrufkonventionen zusammenwirken, zeigt dieses Beispiel für den Aufruf eines Unterprogramms. Unterstellt ist ein fiktives Hauptprogramm, das sind Unterprogramm aufruft. Siehe auch nebenstehende Grafik:

  • Quellcode des rufenden Programms (im Beispiel COBOL-ähnlicher Code):
Struktur der Call-Schnittstelle
* Daten:
  A.
   >Struktur von A, z. B.:
   Ax >Format und Längen
   Ay ...
  B.
   B1 (Definitionen, ggf. weitere Teilfelder)
   B2 (Definitionen)
   B3 (Definitionen)
* Funktionscode:
   A-ROUTINE.
   A-1. >Befehle-1
        Call UPRO Using A, B2.
   A-2. >Befehle-2, z. B. Auswerten und Verarbeiten Rückgabewert(e)
   A-ROUTINE Exit.
    >beliebige weitere Routinen/Befehle
* Programm-Ende
  • Quellcode des Unterprogramms, ggf. aus einer anderen Programmiersprache:
Der daraus erzeugte Objectcode ist im Lademodul des Hauptprogramms eingebunden.
* Datendefinitionen:
   A-DAT >Format und Sub-Struktur wie in A; andere Bezeichner möglich!
   B-2  dto.
   C-x  z. B. eigene Definitionen von UPRO
* Funktionscode:
   Entry UPRO Using A-DAT, B-2.
         >Feldbezeichnungen von Using ggf. abweichend, Reihenfolge identisch zu 'Call'!
   >Weitere Befehle des Unterprogramms:
   >Mit vollem Zugriff (auch ändernd) auf die Struktur (Einzelfelder) von A-Daten und B2.
    Ggf. setzen Returncode, z. B. in B-2 (= B2)
   Exit = UPRO-Ende
  • Ablauf des Unterprogramm-Aufrufs (Call und Return):
(vom Compiler generierter Code, bei Assemblerprogrammen vom Programmierer codiert)
* Call im rufenden Programm:
   Setzt in einer (vom Compiler angelegten) Hauptspeicher-Adressliste
    mit 2 Einträgen die Adresse von A und von B-2
   Setzt einen Zeiger (Register, konkret R1) auf die Adressliste
   Setzt einen Zeiger (Register 14) auf die Rückkehradresse A-2.
   Setzt einen Zeiger (Register 13) auf die Register-Savearea,
    (Speicherbereich automatisch vom Compiler reserviert, Details siehe[1])
   Lädt Register 15 mit der Adresse (Entrypoint) des Unterprogramms 
    (die z. B. vom Linkage Editor im Maschinenprogramm eingesetzt wurde)
   Verzweigt über R15 in das Unterprogramm
* Entry im Unterprogramm:
   >Sichern der Registerstände in die Savearea des rufenden Programms (lt. R13)
    Speichern der Adresse dieser Savearea (= Inhalt R13) in einem eigenen Speicherbereich 
   >Übernehmen der übergebenen Variablen (aus Adressliste lt. R1):
    Adr(A-DAT) = aus Adressliste(1. Adresse), Adr(B-2) = aus Adressliste(2. Adresse)
   >Verarbeitung – mit Zugriff auf übergebene und eigene Daten sowie individueller Registernutzung
* Rücksprung ins rufende Programm:
   >Laden R13 mit der gespeicherten Adresse der Savearea
    Rückladen aller Register aus der Savearea lt. R13
   >Exit: Verzweigung (= Rückkehr) zu Adresse A-2 im rufenden Programm (lt. Inhalt R14)
   

Nach demselben Schema (Registerkonventionen, Savearea) könnte das Modul weitere Untermodule aufrufen. Das dazu erforderliche Sichern der Registerstände zum Zeitpunkt des Aufrufs erfolgt jeweils in einer „Savearea“ genannten Speicherstruktur aufrufender Module, die folgenden Aufbau aufweist:

 |_A_|_B_|_C_|_D1_|_D2_|_.._|_D15_|   = 18 „Fullwords“ (je 4 Bytes) = 72 Bytes
   A = nicht belegt, reserviert    
   B = Adresse der Savearea des aufrufenden Moduls; vom aufgerufenen Modul in seiner eigenen Savearea gesetzt
   C = Adresse der Savearea des aufgerufenen Moduls; vom aufgerufenen Modul in der Savearea des aufrufenden Moduls gesetzt 
   Dn = Inhalt der Register „14 bis 12“ (entspricht R14,R15,R0,R1 .. R12):
       vom aufgerufenen Modul in der Savearea des aufrufenden Moduls gespeichert und vor dem Rücksprung zurückgeladen.

Über die Inhalte von Speicherstelle B und C sind die Saveareas der beteiligten Module in ihrer Aufrufreihenfolge miteinander verkettet; sie zeigen den Stand des jeweils letzten Modulaufrufs, womit sich z. B. im Debug-Modus bei Modultests die Aufruftiefe und die -Reihenfolge ermitteln und nachvollziehen lässt. Einen detaillierten Assembler-Programmcode für die Savearea-Behandlung zeigt dieses Beispiel.

Einzelnachweise

  1. IBM SAVE