Zum Inhalt springen
L

Das Video kommt von YouTube: erst beim Abspielen verbindet sich die Seite mit YouTube (Google).

Die Anatomie eines Programms | Vom Transistor zur KI #2

Hood Informatik19:24 26.435 Aufrufe veröffentlicht Auf YouTube

Das Wichtigste aus dem Video

Tipp auf eine Zeit – das Video springt genau dorthin.

Transkriptautomatisch erstellt · 144 Zeilen
Herunterladen
  1. Im ersten Teil haben wir gesehen, wie aus Strom Logik entsteht, wie Transistoren zu Gattern werden, Gatter zu addierern und wie eine CPU letztlich
  2. Befehle ausführt. Aber einige Fragen bleiben noch offen. Wie kommt dieser Befehl eigentlich in die CPU? Woher weiß sie, dass sie addieren soll? Woher
  3. kommen diese Instruktionen? Heute bauen wir die nächste mentale Ebene auf. Wir gehen von der Hardwareebene eine Stufe höher zur Codeebene und am Ende dieses
  4. Videos wirst du eine saubere Landkarte im Kopf haben, wie aus einem Stück Text in einer Programmiersprache ein eigentliches Programm wird. Übrigens,
  5. vielen lieben Dank für all eure Kommentare unter Teil 1 dieser Reihe. Ich würde mich wieder sehr über euer Feedback freuen. Ich lese tatsächlich
  6. jeden einzelnen Kommentar. Fangen wir ganz oben an. Ein Programm ist erstmal eine Abfolge von Anweisungen, also eine genaue Beschreibung, was passieren soll.
  7. Sowas wie Werteladen, addieren, vergleichen, springen, wiederholen. Für uns Menschen ist das logisch und lesbar. Für die CPU ist es das aber nicht, weil
  8. die CPU keine Wörter versteht und keine Ideen. Sie versteht nur Zustände, also Bits. Also da die CPU nur Nullen und Einsen versteht, müssen Programme in
  9. eine Form übersetzt werden, die zur Hardware passt. Und die tiefste Form, in der man wirklich sagen kann, dass es direkt ausführbar ist Maschinencode. Das
  10. sieht dann in etwa so aus. Maschinencode ist die Sprache, die die CPU direkt versteht. Jede Instruktion bzw. jeder Befehl ist am Ende des Tages eigentlich
  11. nur ein Bitmuster, also irgendeine Kombination aus Einsen und Nullen, die die CPU dekodieren kann. Sagen wir mal, ein bestimmtes Bitmuster landet jetzt
  12. bei der CPU. Diese Bits werden von einer Dekodierlogik verarbeitet, also einer festen Schaltung aus Transistoren und Logikgattern. Diese Schaltung ist so
  13. konstruiert, dass bestimmte Bitkombinationen bestimmte Leitungen aktivieren. Okay, also ihr müsst euch das so vorstellen, ihr habt am Ende eure
  14. CPU und da kommen jetzt bestimmte Bitmuster rein. Okay? Z.B. sowas wie 1, dass diese Kombination reinkommt, sorgt dafür, dass bestimmte Leitungen in der
  15. CPU getriggert werden. Wir erinnern uns zurück, in der CPU haben wir ja nur solche Transistoren und so weiter. Also Transistoren, die wir hier mit Logik
  16. dann dargestellt haben. Wenn jetzt eine bestimmte Kombination aus Bits da reinfließen, werden bestimmte Schalter aktiviert. Das heißt, da passiert
  17. physisch einfach etwas und nicht die CPU denkt sich jetzt, oh, wir müssen jetzt addieren und jetzt machen wir dieses und jenes. Sondern die CPU sieht einfach
  18. nur, wir bekommen jetzt diese Kombination an Bits rein, also schaltet die CPU so und so und so. Wenn z.B. ein Befehl zum Adieren dekodiert wird, dann
  19. bedeutet das nicht, dass die CPU Addition versteht. Es bedeutet lediglich, dass durch dieses Bitmuster eine bestimmte Kombination von
  20. Steuersignalen aktiviert wird. Die CPU interpretiert also nichts. Sie weiß auch nichts. Sie reagiert nur deterministisch auf elektrische Zustände. Diese Befehle
  21. hier sind also nur Bitmuster, die eine festverdratete Schaltung aktivieren. Für die Hardware ist es lediglich. Bestimmte Transistoren werden leitend, andere
  22. werden gesperrt, Ladungen verschieben sich und Spannung ändern sich. Okay, wir wissen also, dass ein Programm eine Folge von Anweisungen ist. Wir wissen,
  23. dass wir diese Anweisungen in Maschinencode formulieren müssen, also in Nullen und Einsen hier. Weil aber kein Mensch so programmieren kann oder
  24. möchte, hat man sich gedacht, man abstrahiert ein wenig weg davon. Und so ist man bei Assembly gelandet. Assembly ist quasi ein Schritt weg von binär. Das
  25. bedeutet, wir sagen jetzt z.B. sowas hier bedeutet im Grunde Load A. Das ist leicht, also es ist leichter zu verstehen, wenn wir einfach load A oder
  26. load blablabla schreiben oder Move statt diese Binär abfolgen. Im Hintergrund passiert natürlich trotzdem diese Umwandlung zu bin, aber im Grunde kann
  27. man damit einfacher schreiben. Das heißt, ich könnte jetzt einfach losgehen und sowas schreiben wie load A, move, sowas wie move A und so weiter.
  28. Ihr wisst, worauf ich hinaus will. Also so, ihr wisst, worauf ich hinaus will. Das ist viel einfacher zu programmieren als sowas hier. Assembly ist im Grunde
  29. also nur Machinecode, nur mit Namen statt Bitmustern. Aus einer Bitfolge wird dann sowas wie das hier. Aber die meisten Programme schreibt man nicht so,
  30. weil man jede Kleinigkeit selbst regeln müsste, also Datenstrukturen, Speicherverwaltung, Fehlerbehandlung und so weiter. Um Software groß und wartbar
  31. zu bauen, brauchst du Abstraktion. Und damit kommen wir zu höheren Programmiersprachen. In höheren Programmiersprachen wie C, RUS, Java
  32. oder Python formulierst du Absichten. Du sagst z.B. sowas wie: "Diese Variable soll dieses und jenes tun" oder diese Funktion, diese Schleife, diese
  33. Datenstruktur. Du schreibst nicht in welches Register ein Wert kommt oder wie viele Instruktionen nötig sind. Das ist genau der Punkt. Du entfernst dich
  34. bewusst von der Hardware, um in größeren Konzepten denken zu können und Code so zu formulieren, dass er lesbar wird für Menschen. Ich will auf einen Blick sehen
  35. können, was ein Code tut und ihn verstehen können. Das macht immens viele Dinge einfacher, wie z.B. Fehlersuche, aber auch das Entwickeln selbst. Ihr
  36. seht es hier selbst. Sowas hier kann ich z.B. super einfach lesen. Das ist z.B. ein Beispiel für CCode. Hier unten seht ihr einmal den Vergleich von dem, was
  37. wir gerade besprochen haben. Maschinencode ist sehr Hardware nah. Das ist das, was die Hardware wirklich am Ende des Tages braucht. Die CPU kriegt
  38. diese Einsen und Nullen und aktiviert damit tatsächliche Steuerleitungen in der CPU selbst. Dann geht's weiter zu Assembly. Das ist immer noch super
  39. Hardware nah, ne? Also, wir entfernen uns hier nicht wirklich groß. Hier ist der Sprung dann deutlich höher. Hier abstrahieren wir stärker. Dann gebe es
  40. noch z.B. Python und Co. Und die würden dann hier hinten irgendwo landen, ne? weil die deutlich weiter entfernt sind von der Hardware. Das macht
  41. Programmieren viel einfacher und skalierbarer. Aber es bedeutet auch irgendjemand oder irgendetwas muss diese abstrakte Beschreibung wieder in
  42. konkrete CPU Instruktionen übersetzen und das macht der Compiler. Aber bevor wir über den Compiler sprechen, will ich hier noch mal eine Sache anmerken.
  43. Assembly und Maschinencode sind sehr sehr Hardware nah. C++ ist im Vergleich zu den Hardware fern, aber im Vergleich zu anderen Programmiersprachen wie z.B.
  44. Python immer noch Hardware nah. Das heißt, wir können sagen innerhalb der Programmiersprachen selbst, ich kann hier z.B. mal so ein Teil einzeichnen,
  45. innerhalb der Programmiersprachen selbst könnte man diese Skala noch mal neu machen. Das heißt, man könnte sagen, Python ist irgendwo hier. Das heißt, von
  46. den höheren Programmiersprachen ist C oder C++ immer noch sehr hardware nah im Vergleich zu Python z.B. so, aber im Vergleich zu Assembly oder Machine Code
  47. ist C++ nun mal Hardware fern. Ein Compiler nimmt deinen Quelltext, also deinen Code und übersetzt ihn vor der Ausführung in Maschinencode. Das heißt,
  48. bevor dein Programm überhaupt startet, wird es vollständig in eine Form gebracht, die die CPU direkt ausführen kann. Dabei passiert viel mehr als nur
  49. Wort für Wort zu ersetzen. Der Compiler analysiert deinen Code, entscheidet, welche Instruktionen verwendet werden, welche Register benutzt werden, wie
  50. Speicher organisiert wird und versucht das Ganze effizient zu machen. Also wie gesagt, egal wie sehr ihr abstrahiert, egal welche Programmiersprache ihr habt,
  51. am Ende war geht man immer die Kette wieder zurück zum Maschinencode immer. Die CPU wird immer nur das ausführen. Sie führt nie euren Code direkt aus.
  52. Dieser Code wird erstmal übersetzt in dieses hier und das wird ausgeführt. Aber nicht jede Programmiersprache funktioniert so. Manche Sprachen
  53. übersetzen den Code nicht komplett im voraus. Stattdessen wird der Code Schritt für Schritt zur Laufzeit verarbeitet und ausgeführt. Und genau
  54. das macht ein Interpreter. Ein Interpreter übersetzt den Code während der Ausführung, also Zeile für Zeile. Am Ende steht aber auch hier immer eine
  55. Folge von Zahlen im RAM. Also egal was wir tun, egal ob Interpreter oder Compiler, am Ende steht immer der Maschinencode im RAM. Ich habe mir noch
  56. mal kurz die Unterschiede zwischen beiden aufgelistet. Die Entwicklung beim Compiler ist weniger flexibel, aber dafür läuft der Code sehr schnell. Aber
  57. warum ist die Entwicklung hier weniger flexibel? Ein Compiler übersetzt ja das komplette Programm vor der Ausführung in Maschinencode. Deshalb läuft es
  58. schneller, ist aber weniger flexibel, weil jede Änderung eine Neukompilierung erfordern würde. Ein Interpreter verarbeitet den Code während der
  59. Laufzeit Schritt für Schritt, ist dadurch also flexibler, z.B. für dynamischen Code, aber langsamer, weil die Übersetzung ständig mitläuft. Aber
  60. woher weiß dieser Übersetzer bzw. der Compiler und die CPU eigentlich, welche Befehle sie überhaupt nutzen darf? Sagen wir mal, ich möchte zwei Zahlen
  61. miteinander addieren. Gehen wir mal davon aus, meine CPU hat gar keinen Adierer, was natürlich nie der Fall sein würde, aber woher weiß ich also genau,
  62. was die CPU alles kann und was sie nicht kann? Woher kenne ich die Befehle, die eine CPU wirklich nutzen kann und in dem Sinne versteht? Und hier kommt die ISA
  63. ins Spiel, die sogenannte Instruction Set Architecture. Die ISA ist die formale Spezifikation dessen, was eine CPU versteht. Sie definiert, welche
  64. Instruktionen existieren, wie sie codiert werden, welche Register es gibt und wie Speicher adressiert wird. Aber wie sieht so ein Instruction Set
  65. eigentlich aus? Ich kann euch das mal zeigen. Und zwar könnt ihr einfach mal nach X86 OCE suchen oder X86 ISA, dann landet ihr schnell bei solchen Tabellen.
  66. Ihr seht hier eine Instruktion und hier den OCode dazu. Hier eine kleine Beschreibung, was diese Instruktion genau tut. Wir werden das jetzt nicht im
  67. Detail durchgehen, aber hier ist im Grunde eine Liste mit allen Befehlen, die eine X86er CPU im Grunde ausführen kann. Die CPU kann also nur alles
  68. ausführen, was hier drin gelistet ist, mehr nicht. Also jeder Code, jedes Programm, egal was ihr auf eurem PC ausführt, basiert auf Ainanderreihungen
  69. von diesen Instruktionen, die die CPU versteht. Das heißt, egal was ihr in eurer Programmiersprache programmiert, der Compiler bzw. Der Interpreter
  70. übersetzt das Ganze in so eine Instruktion hier. Das heißt, Compiler und Interpreter können nur dann zur Hardware runter, wenn klar ist, welche
  71. Instruktion überhaupt gültig ist. Der Compiler generiert also nicht einfach irgendeinen Maschinencode, sondern Maschinencode für eine konkrete ISA. Und
  72. wie vorhin erwähnt, gibt es mehrere Architekturen, z.B. X86, Arm oder Risk. Ein Beispiel für einen Armprozessor ist z.B. der Apple M1 Chip. Die typischen
  73. Intel oder AMD Chips sind meist X86er. Deswegen können Programme, die für X86 kompiliert wurden, nicht nativ auf einem Armprozessor ausgeführt werden, weil
  74. beide Architekturen unterschiedliche Befehlssätze haben. Sie benötigen dann entweder eine Neukompilierung oder eine Übersetzungsschicht, wie z.B.
  75. Emulatoren. Also, wir haben bis jetzt verstanden, dass ein Programm eine Folge von Anweisungen ist. Wir schreiben unsere Anweisung in der Regel so. Diese
  76. Anweisungen werden aber übersetzt vom Compiler oder Interpreter. So, dieser Compiler oder Interpreter nutzt dabei das Instruction Set Architecture. Das
  77. heißt, es weiß genau, welche Befehle es wie umwandeln muss, damit es überhaupt von der CPU ausgeführt werden kann. Jetzt schauen wir uns an, was der Linker
  78. macht. Bevor wir verstehen, was ein Linker macht, müssen wir kurz erklären, was eigentlich Objektdateien sind. Dazu habe ich hier unten eine kleine Skizze
  79. gemacht. Ich glaube, die ist eigentlich ganz nützlich. Links siehst du zwei CDien, main.c C und math. Der Compiler übersetzt diese Dateien nicht direkt zu
  80. einem fertigen Programm. Stattdessen wird jede Datei einzeln kompiliert. Das Ergebnis sind sogenannte Objektdateien. Hier main. Math. In diesen Objektdateien
  81. steckt bereits echter Maschinencode. In Main. Z.B. in der Punkt Text Section der Befehl Call AD. Ihr seht es hier rot markiert, aber entscheidend ist Add ist
  82. hier nur ein Symbol. In der Symboltabelle steht, dass Ad extern ist, also irgendwo anders definiert wird. Zusätzlich gibt es hier so einen
  83. weiteren Eintrag, der sagt, an dieser Stelle muss später noch eine Adresse gesetzt werden und zwar bei Ad, weil wir eben nicht wissen, wo sich dieses Ad
  84. befindet. In math. Dagen sehen wir die Definition von Ad. Dort steht die eigentliche Implementierung. Wichtig, beide dieser Objektdateien enthalten
  85. schon Maschinencode. Ich habe das jetzt hier so dargestellt, damit wir es einfacher lesen können. Wichtig, sie wissen aber noch nichts voneinander. Vor
  86. allem kennt main. Noch nicht die konkrete Speicheradresse von AD. Und genau hier kommt der Linker ins Spiel. Der Linker nimmt diese einzelnen
  87. Objektdateien, führt ihre Textbereiche zusammen, gleicht die Symboltabelle ab und löst alle offenen Referenzen auf. Das Symbol Add wird durch eine konkrete
  88. Adresse ersetzt. Hier z.B. 4050. Das Ergebnis wäre erst jetzt das ausführbare Programm. Wichtig, hier drin steht Text, aber in Wirklichkeit sind
  89. das auch wieder Nullen und Einsen. Ich habe das jetzt hier so hingeschrieben, damit wir einmal den Übergang hier verstehen können. Man kann es sich also
  90. so merken. Der Compiler erzeugt einzelne noch unvollständige Bausteine. Der Linker verbindet sie und löst alle offenen Verweise auf und daraus entsteht
  91. ein vollständiges startbares Programm. Aus vielen Dateien wird also ein Binary, also eine ausführbare Datei. Somit kommen wir auch direkt schon zum Punkt
  92. Executable. Ein Executable ist eine Datei mit Struktur. Sie enthält also Maschinencode Daten, Metadaten über Segmente, ein Einstiegspunkt und häufig
  93. Referenzen auf weitere Libraries. Sie ist so gebaut, dass das Betriebssystem sie später in den RAM laden und starten kann. Aber wichtig, eine Datei ist noch
  94. kein Prozess. Ein Binary ist also noch nicht laufend. Es ist also einfach nur eine Beschreibung dessen, was laufen soll. Es ist also auch hier wie eine Art
  95. Rezept. Das Rezept wird aber noch nicht ausgeführt. Es liegt jetzt erstmal nur im Speicher. Bevor wir aber zum Betriebssystem übergehen, fehlen noch
  96. drei Ebenen, die erklären, wie diese Binärwelt organisiert ist. Und damit kommen wir zum Application Binary Interface Kurz Abi. Die Abi ist im
  97. Grunde die technische Vereinbarung auf Maschinencode, damit Programme und Libraries miteinander reden können. Also, stellt euch mal vor, ich schreibe
  98. jetzt meinen Code und ich möchte irgendwas auf dem Bildschirm ausgeben. In der Regel läuft das so ab. Ich würde jetzt hier reingehen und z.B. sowas
  99. sagen wie Print F und dann hello. So kann ich z.B. was auf dem Bildschirm ausgeben. Dieses Add hier habe ich ja vorhin selbst definiert, aber Print F
  100. habe ich nicht selbst definiert. Er stammt nämlich aus der C Standardbibliothek. Ihr seht es hier oben. Aber sagen wir mal, mein Code
  101. wurde vielleicht heute kompiliert und die Library hier oben wurde schon vor Jahren kompiliert. Trotzdem müssen beide auf Maschinenebene perfekt
  102. zusammenarbeiten. Aber wie? Woher weiß Print F, wo seine Parameter liegen, wie Rückgabewerte zurückgegeben werden, wie der Stack aussieht, wie man ins
  103. Betriebssystem springt und und. Und genau hier kommt diese Abi ins Spiel. Die Abi legt also fest, wie fertig kompilierte Programme und Libraries,
  104. also Bibliotheken miteinander sprechen. Nicht auf C-Ebene, nicht auf Quellcode, sondern auf Binärebene. Wichtig, diese Abi wird nicht vom Linker gemacht. Abi
  105. ist im Grunde das Regelwerk, an das sich Compiler, Libraries und das Betriebssystem halten. Es ist also wie eine Art Spezifikation oder Dokument,
  106. das genau festlegt, welche Register dürfen für Parameter genutzt werden, wo sollen Rückgabewerte landen, wie soll der Stack ausgerichtet werden, was der
  107. Stack ist, dazu kommen wir gleich noch. Wie sollen Systemcalls aussehen und wie soll am Ende eine Executable strukturiert sein? Der Compiler
  108. implementiert diese Regeln beim Erzeugen des Codes. Die Standardbibliothek wurde nach denselben Regeln kompiliert und das Betriebssystem erwartet dieselben
  109. Regeln. Warum ist das Ganze so entscheidend? Stell dir vor, dein Compiler würde Parameter im bestimmte Register übergeben und die Library würde
  110. sie aber ganz woanders erwarten. Dann würde Print F komplett falsche Werte lesen und es würde sofort crashen. Dass das nicht passiert, liegt darin, weil
  111. beide sich an dieselben Regeln halten bzw. die AI. Okay, genug von der AI. Machen wir weiter. Sprechen wir jetzt über Speicherse. Ein Programm ist im
  112. Speicher nicht einfach ein chaotischer Block. Neben Code und statischen Daten gibt es zwei besondere wichtige Bereiche, den Stack und den Hieb. Der
  113. Stack ist der Bereich für Funktionsaufrufe. Er funktioniert nach dem Prinzip Last in, first out. Also das, was zuletzt hineingelegt wurde,
  114. kommt zuerst wieder heraus. Stell dir einen Stapelt Teller vor. Du legst oben einen neuen Teller drauf, dann noch einen weiteren und dann noch einen
  115. weiteren und wenn du einen brauchst, nimmst du wieder den obersten weg. Genauso organisiert sich der Stack. Jedes Mal, wenn eine Funktion gestartet
  116. wird, legt das System dort ihre lokalen Variablen ab und die Information, wo es nach dem Ende der Funktion zurückspringen soll. Wenn die Funktion
  117. fertig ist, wird dieser Speicher automatisch wieder freigegeben. Der Stack wächst also bei jedem Funktionsaufruf und schrumpft wieder
  118. sobald die Funktion endet. Das macht den Speicher sehr effizient. Der Hieb hingegen funktioniert anders. Er ist für Speicher gedacht, der zur Laufzeit
  119. flexibel angefordert wird, z.B. für größere oder dynamische Datenstrukturen. Anders als beim Stack wird dieser Speicher nicht automatisch freigegeben.
  120. Das Programm fordert ihn aktiv an. In C würde man das z.B. über Mallock machen, also Memory Allocation. Wichtig, man muss den Speicher selber auch wieder
  121. freigeben. Der Hieb wird dadurch flexibler, aber auch aufwendiger zu verwalten. Warum entstehen hier jetzt aber so viele Speicherfehler? Im Grunde
  122. liegt es hier auf der Hand, weil du den Speicher selbst organisieren musst. Das heißt, du musst ihn selbst reservieren und selbst wieder löschen, wenn du ihn
  123. nicht brauchst. Sagen wir mal, ich reserviere Speicher für drei Bereiche, für drei Zahlen. Okay, ich mache jetzt mal so. Ich sag, ich will jetzt drei
  124. Dinger hier reservieren im Hieb. Das sollen ganze Zahlen sein und ich reserviere jetzt einfach mal. Wenn der Nutzer jetzt aber fünf Werte eingibt, du
  125. aber nicht sauber überprüfst, ob er genau drei eingibt oder nicht, dann hast du ein Problem, weil er jetzt fünf Werte reingibt und damit deinen Speicher
  126. überschreibt. Das heißt, er sorgt jetzt dafür, dass Werte überlaufen. So viiel zu Speichersegmenten. Kommen wir jetzt zum letzten Punkt und zwar zur Runtime.
  127. Die Runtime ist die Laufzeitumgebung, die ein Programm während der Ausführung unterstützt. Sie übernimmt die grundlegenden Aufgaben, die fast jedes
  128. Programm braucht. Dazu gehören z.B. Dinge wie das Starten des Programms selbst, die Initialisierung von Speicher, Standardfunktion für z.B. ein
  129. und Ausgabe auf dem Bildschirm, das ist das, was wir uns hier unten angeschaut hatten. In der Sprache C ist das z.B. die C Runtime. Bevor deine Funktion
  130. überhaupt startet, hat die Runtime bereits den Stack vorbereitet, globale Variablen initialisiert und die Umgebung eingerichtet. Erst danach wird dein Code
  131. ausgeführt. In anderen Sprachen ist diese Schicht noch deutlich sichtbarer. In Java läuft dein Code nicht direkt auf der CPU, sondern in der JVM. In Python
  132. wird dein Code vom Interpreter ausgeführt. Diese Komponenten sind ebenfalls Runtime Systeme. Wichtig ist, die Runtime ersetzt nicht das
  133. Betriebssystem, sie sitzt darüber. Wenn dein Programm Speicher braucht, ruft die Runtime letztlich Funktionen des Betriebssystems auf. Man kann es sich so
  134. vorstellen. Dein Code beschreibt, was passieren soll. Die Runtime organisiert, wie es innerhalb der Sprache abläuft und das Betriebssystem stellt die echten
  135. Ressourcen bereit. Die Runtime ist also die vermittelnde Schicht zwischen Sprache und System. Wenn wir einmal zurückblicken, dann haben wir heute eine
  136. sehr wichtige Schicht aufgebaut. Lassen wir einmal Teil 1 und Teil 2 kurze Revue passieren. Ganz unten stehen Strom und Transistoren. Transistoren bilden Gat.
  137. Gat bilden Adierer und Logik und daraus entsteht die CPU. Die CPU verarbeitet nur elektrische Zustände deterministisch. Darüber liegt der
  138. Maschinencode. Bitmuster, die nichts bedeuten, sondern festverdratete Steuerleitungen aktivieren. Darüber liegt Assembly, dieselbe Welt nur mit
  139. lesbaren Namen. Darüber liegen höhere Programmiersprachen, indem wir Absichten formulieren, statt Register zu verwalten. Dann kommen Compiler und
  140. Interpreter, die diese Abstraktion wieder herunterbrechen, zurück auf eine konkrete Instruction Set Architecture. Der Linker verbindet dann einzelne
  141. Bausteine. Das Ergebnis ist ein strukturiertes Binary mit klarer Abi, klaren Speichersegmenten, Stack und Hieb. Die Runtime unterstützt das Ganze
  142. während der Ausführung und erst dann übernimmt das Betriebssystem, was wir uns im nächsten Video anschauen werden. Wenn dir diese Reihe hilft, solche
  143. komplexen Systeme klarer zu sehen, dann schreib es mir wieder in die Kommentare. Ich lese wirklich jeden Kommentar und bin happy über Feedback. Wie gesagt, im
  144. nächsten Teil schauen wir uns Betriebssysteme genauer an und bis dahin stay safe und bis zum nächsten

Zum Nachlesen