Verständnisfragen zum Compiler/Interpreter

Da muss nichts übersetzt werden, weil es nichts zu übersetzen gibt. Hex oder Binär sind einfach nur andere Darstellungen der absolut gleichen Zahl.
 
hamju63 schrieb:
Daher bin ich der Ansicht, dass man nicht tief genug anfangen kann, das Programmieren wirklich zu lernen, um sich die entsprechende (mathematische) Denke anzugewöhnen.
Steckbrett mit Transistoren und Quarz tief genug? 😉
 
BeBur schrieb:
Davon habe ich noch nie zuvor gehört ^_^.

Ist aber wichtig.
Wenn Du in einem Programm ein Feld A und ein Feld B auf Gleichheit abfragst, dann werden die Felder nie gleich sein, wenn Feld A eine gepackte Zahl 120 beinhaltet und Feld B eine gezonte Zahl 120, da beide binär unterschiedlich gespeichert werden.
 
BeBur schrieb:
Wobei die Priorisierung vermutlich auch direkt von der CPU gemacht wird.
Aber so generell, die CPU sendet (irgendwie) ein Signal an das OS. Und die CPU hat eine Liste mit aktiven Prozessen. Das OS kann diese Liste den verschiedenen Anwendungen zuordnen. Ist das vom Grundverständnis her korrekt?
Woher weiß die CPU denn, von welchem Prozess es gerade OP Codes erhält?
Welche Priorisierung? Scheduling etc. ist auch Aufgabe des Betriebssystems. Das sollte also auch immer wissen, welcher Prozess gerade CPU-Zeit bekommt. Die CPU selbst weiß das nicht wirklich (*).
Generell ist die Implementierung von Software-Interrupts natürlich abhängig von CPU-Architektur und Betriebssystem. Bei x86 gibt es eine Interrupt Descriptor Table (IDT) mit bis zu 256 Einträgen, die vom OS aufgesetzt wird. Die sagt der CPU, bei welchem Interrupt zu welchem Teil des OS-Kernel-Codes gesprungen werden soll. Bei Linux wird glaube ich immer der Interrupt 0x80 für System Calls genutzt.
Wenn ein Programm also den Maschinenbefehl INT 0x80 benutzt, dann unterbricht die CPU die Ausführung und ruft den Kernel-Code auf, der in der IDT für 0x80 vom OS hinterlegt wurde. Dieser Kernel-Code ist dann dafür verantwortlich, den System Call entsprechend zu interpretieren (das geht über die Register, die die Anwendung vorher entsprechend mit den nötigen Infos beschrieben hat), ihn umzusetzen und am Ende wieder den Ablauf des ursprünglichen Programms zu starten.
Hier gibt es viele nützliche Infos zu dem Thema. Man ist unschwer erkennbar schon sehr nah an der Hardware und dem OS-Kernel.

(*) genau genommen kann man das nicht ausschließen.
 
hamju63 schrieb:
Wenn Du in einem Programm ein Feld A und ein Feld B auf Gleichheit abfragst, dann werden die Felder nie gleich sein, wenn Feld A eine gepackte Zahl 120 beinhaltet und Feld B eine gezonte Zahl 120, da beide binär unterschiedlich gespeichert werden.
Interessant, das scheint etwas zu sein, das BCD spezifisch ist. Wenn ich den Wikipedia Artikel richtig verstanden habe, dann wird BCD kaum noch in moderne Hardware gegossen / verwendet, das Format speziell auch in beiden Varianten (ich vermute aus historischen / legacy Gründen) aber durchaus noch bei einiger Software von Konzernen verwendet.

Web-Schecki schrieb:
Bei x86 gibt es eine Interrupt Descriptor Table (IDT) mit bis zu 256 Einträgen, die vom OS aufgesetzt wird. Die sagt der CPU, bei welchem Interrupt zu welchem Teil des OS-Kernel-Codes gesprungen werden soll.
Das war schonmal sehr erhellend, danke.

Web-Schecki schrieb:
Das sollte also auch immer wissen, welcher Prozess gerade CPU-Zeit bekommt. Die CPU selbst weiß das nicht wirklich (*).
Wenn die CPU aber nicht weiß, welcher Prozess gerade arbeitet, wie kann die CPU dann einem Prozess einen virtuellen Speicherbereich zuordnen?

PS.: Den Link hatte ich beim ersten Lesen galant übersehen. Schaue ich mir mal an.
 
BeBur schrieb:
das Format speziell auch in beiden Varianten (ich vermute aus historischen / legacy Gründen) aber durchaus noch bei einiger Software von Konzernen verwendet.

SAP z.B. :)
 
  • Gefällt mir
Reaktionen: BeBur
BeBur schrieb:
Wenn die CPU aber nicht weiß, welcher Prozess gerade arbeitet, wie kann die CPU dann einem Prozess einen virtuellen Speicherbereich zuordnen?
Das ist auch Aufgabe vom Betriebssystem. Die CPU, genauer die MMU, enthält Paging-Tabellen, mit denen die virtuelle Adressen den physikalischen Adressen zugeordnet werden. Das OS muss das initialisieren und korrekt verwalten. Teilweise will man ja auch, dass mehrere Prozesse denselben Speicherbereich nutzen können, um darüber zu kommunizieren. Das OS ist dafür verantwortlich, dass die Abschottung korrekt funktioniert. Das ist aber alles eine sehr komplizierte Angelegenheit, von der ich auch nur rudimentär Ahnung habe. Im OSdev-Wiki gibt es enorm viel zu dem Thema, ich stöbere da sehr gerne.
 
  • Gefällt mir
Reaktionen: BeBur
Nur mal ein paar zusammenhanglose Gedanken zu den Kommentaren hier:

Ein Großteil von dem hier genannten wird eigentlich in einem der ersten Semester im Informatikstudium gelehrt ("Betriebssysteme"). Du kannst mal auf Youtube schauen, gibt einige Unis die ihre Vorlesungen online anbieten.

hamju63 schrieb:
Noch ein Grund warum ich nicht zu denen will. Zumindest zahlen sie wohl gutes Schmerzensgeld. :D


KOply schrieb:
Verstehe ich es dann richtig, dass es dann Compiler geben kann, welche direkt in Maschinensprache übersetzen und andere noch den Weg über eine Zwischensprache wie C gehen? Und das könnte dann den Grund haben, dass der Entwickler des Compilers eben gerne mit C oder anderen Zwischensprachen arbeitet und/oder sich dadurch andere Vorteile erhofft, womit dann für den Compiler geworben wird.
Ein Beispiel wurde schon genannt, LLVM-IR. Damit können dann viele Leute sich darauf konzentieren den LLVM compiler zu optimieren und Leute die eine neue Sprache implementieren müssen "nur" noch einen simplen compiler bauen der ihre neue Programmiersprache akzeptiert und die LLVM-IR repräsentation davon ausgibt. Die Optimierungen können sie sich sparen (Auch wenn die meisten aus verschiedenen Gründen trotzdem Optimierungen beinhalten). Beispiele dafür sind der Rust compiler Rustc, Clang, Julia, Zig und zahlreiche andere. Zig bietet anscheinend auch die Möglichkeit über C zu gehen, Zig und C sind sich aber auch sehr ähnlich und genauere Infos dazu kann ich leider auch nicht liefern.
Rustc hat neben dem offiziellen LLVM backend auch viele andere Backends in Entwicklung, ein sehr erwartetes ist das gcc backend, da GCC der große Gegenspieler zu LLVM ist.
Rust nutzt übrigends nicht nur eine Zwischensprache, sondern theoretisch gleich 4 (HIR, THIR, MIR, LLVM-IR): Der Vorteil ist, dass man sich auf jeder Schicht auf eine Sache konzentrieren kann und diese Schicht demnach auch genau für diese Aufgabe designen kann, man muss nicht mehr darauf achten, dass Menschen sie gut schreiben können. Eine sehr schöne Begründung von den Entwicklern gibt es hier.

Ein weiterer nicht zu unterschätzender Vorteil ist auch das ganze Tooling neben dem compiler selbst. Ich helfe z.B. bei einem Tool mit, welches Funktionen im Mathematischen Sinn ableiten kann. Dieses Tool arbeitet auf LLVM-IR, effektiv könn(t)en wir so ohne zu großen Aufwand gleich mal ein dutzend Sprachen unterstützen.

hamju63 schrieb:
Danke, dann hat sich in den letzten Jahrzehnten offensichtlich Einiges geändert.
Ich habe Anfang der 80er Informatik studiert.
Und es war schon ein ordentlicher Unterschied, den selbstgeschriebenen Assembler Code zu sehen und danach das, was ein Compiler so 'hindilettiert' hat.
Hindilettiert trifft es mittlerweile nicht mehr wirklich, wenn man dem Compiler genug Zeit gibt kann der mittlerweile einige Optimierungen anwenden die über das hinausgehen was man als normaler Mensch realistisch hinbekommt: https://polygeist.mit.edu/
Befreit einen aber natürlich nicht ganz vom Nachdenken wenn es mal auf die Performance ankommt, der Compiler hat keine Glaskugel.


Ich würde mittlerweile übrigens eher empfehlen mit höheren Sprachen anzufangen.
Zum einen kann man damit auch tatsächlich realistisch Geld verdienen, zum anderen gibt es mehr
Sachen als nur low-level Hardware Details die man können sollte.
Viele Sprachen wie z.B. C++, Rust, Julia beherrschen inline assembly, damit kannst du einerseits gleich auch etwas spannendere Programme schreiben, andererseits aber auch gezielt die Teile optimieren die "hot" sind und wo der compiler suboptimalen code generiert - was zusammen erstaunlich selten passiert.

Hier sieht man z.B., dass eine Rust Funktion (auf geeigneter Hardware) direkt auf die Asm instruktion popcnt gemapped wird. Wenn du Spaß dran hast könntest du z.B. mal manuell das zählen der nullen implementieren, einmal in Rust und einmal mittels inline-asm. Danach kannst du vergleichen was der compiler jeweils generiert und ob er deine Intention versteht. Rust ist hier nur ein beliebiges Beispiel weil ich die Sprache nutze, die anderen gehen sicher genauso gut.
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: KOply und BeBur
Interessantes Thema... Will ich mir mal vormerken zum in Ruhe durchlesen.
 
Das Thema ging nun tiefer als ich erhofft hatte, weshalb ich kaum folgen kann.

Wichtig für mein Verständnis wäre noch, wenn mir jemand in einer simplen Reihenfolge den Weg meines Python Codes aus VSC aufzeigen könnte. Es wurden zwar schon Details genannt, doch manches ging mir zu tief und ich würde es dennoch gerne einfach verstehen. In etwa so: Python Code -> Python Interpreter -> .... -> Assembler -> Prozessor

Danke. :(

Incanus schrieb:
Da muss nichts übersetzt werden, weil es nichts zu übersetzen gibt. Hex oder Binär sind einfach nur andere Darstellungen der absolut gleichen Zahl.
Ja es sind die gleichen Zahlen, aber der Prozessor arbeitet doch nur mit binären Zahlen und kann doch kein Hexadezimal? Daher interessiert es mich, wo die Übersetzung für den Prozessor stattfindet und ob dieser Prozess dann auch Teil des Assemblers ist.
 
Der Prozessor sieht auch kein Hexadezimal, er sieht auch keine Farben beim Syntaxhighlighting beispielsweise, das siehst Du nur am Bildschirm.
Im Speicher steht also z.B. irgendwo 10101010 (binär), am Bildschirm wird Dir AA (Hex) angezeigt, wenn Du die Darstellung umschaltest aber vielleicht auch 170 (dezimal). Alles die gleiche Zahl, die CPU bekommt davon gar nichts mit. Es ist also keinerlei Übersetzung notwendig.
 
  • Gefällt mir
Reaktionen: Phrasendreher und KOply
KOply schrieb:
wo die Übersetzung für den Prozessor stattfindet
Das ist oben schon alles sehr passend beschrieben worden, das Internet und die Literatur sind voll von guten Beschreibungen.
Der Interpreter (in Deinem Beispiel für Python) macht aus der Hochsprache Zahlen (der Interpreter macht es on the fly, der Compiler on command).
Das Zahlensystem darfst, sollst und musst Du mal ausblenden - auf logischer Ebene findet die Verarbeitung zwar Bit für Bit statt, aber solange Du Dir nicht Deine eigenen Halbleiter dotierst, daraus Transistoren fertigst und damit logische Schaltungen a la NAND zusammenbaust, ist das wirklich egal.

Um das in Dein gefragtes Schema zu bringen:
Python (Hochsprache) -> Interpreter -> Zahlen (Maschinencode).

Und die Frage, an welcher Stelle welcher Code wie auf welcher Hardware ausgeführt wird, eröffnet wieder nur eine neue Komplexitätsebene (von denen es unglaublich viele bei einer Betrachtung auf solchem Niveau gibt), die mit der Übersetzung von Programmiersprachen wieder nur entfernt zu tun hat.

@Incanus Der Vergleich mit dem Syntax Highlighting ist wirklich gut getroffen, das verdeutlicht schön, dass nicht alles, was wir im Code sehen (möchten), von der CPU gesehen wird.
 
  • Gefällt mir
Reaktionen: BeBur und KOply
Zurück
Oben