Maschinencode verstehen

EnVerdichtet

Cadet 1st Year
Registriert
Jan. 2021
Beiträge
9
Hi,

ich habe mich mit der Entwicklung des Computers beschäftigt und interessiere mich für die ersten Programme. Bzw. wie man mit der Maschine kommunizieren und diese programmieren kann.

Wenn ich es richtig verstanden habe, dann werden durch die Aneinanderreihung von Schaltern Signalkombinationen definiert, die bestimmte Operationen ausführen.

Habt ihr Tipps und eventuell Links für mich, wie ich als Laie Maschinencode, Firmware, Compiler und Assembler der ersten Computer verstehen kann? Mir würde es schon reichen, wenn ich verstehe, wie von Maschinencode bis über den Assembler ein Buchstabe in einer Konsole ausgegeben wird.

Ich habe wenigstens schon das Binärsystem verstanden. Glaube ich jedenfalls...

Habt ihr eventuell eine Seite für mich mit dem einfachsten möglichen Weg, wie ich ein Buchstabe in der Konsole darstellen kann?
Mir geht es eigentlich eher darum zu verstehen wie es funktioniert. Um damit tatsächlich jemals ein Programm zu schreiben fehlt mir mit Sicherheit das intuitive Verständnis für Informatik ;)

Ein Beispiel des primitivsten elektronischen PCs und dessen simpelsten Programm würde daher reichen. Es soll nur leicht zu verstehen sein. So dass ich als Laie wenigstens das Prinzip verstehen kann.
 
Wie gut ist dein Englisch?


Das Video ist Teil einer Serie mit 7 Videos. Schau einfach alle an, danach bist du im Bilde.
Allgemein ist Ben Eater ein hervorragender Youtuber, wenn man die Hardwareseite von Computern verstehen will.
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: EnVerdichtet und Hexxxer76
Hm, für Assembler und den Aufbau von Computern fand ich den MFA Lerncomputer sehr genial, weiß aber nicht ob es da mittlerweile gutes Material online gibt, aber so wie es aussieht wohl nicht. Der wurde früher in der Ausbildung für Informatiker verwendet (mittlerweile wohl nicht mehr, aber ich hab damals damit hantiert ;-)

Allgemein dürfte es wohl einfacher sein sich einen Emulator für einen alten 8 oder 16 Bit Computer und alte Handbücher dazu zu holen als auf modernen Systemen zu versuchen mit Assembler einzusteigen...
 
  • Gefällt mir
Reaktionen: EnVerdichtet
Bist du dir sicher, dass du nicht etwas viel auf einmal möchtest?

Also Maschinen-Code ist halt die "Sprache", die der Prozessor versteht. Assembler (damit meine ich die Sprache) abstrahiert das schon ein wenig, auch wenn er sehr nah am Maschinen-Code ist. Höhere Programmiersprachen abstrahieren das noch mehr.

Willst du wirklich Maschinen-Code verstehen, oder willst du verstehen, wie ein Prozessor diesen ausführt?

Mir würde es schon reichen, wenn ich verstehe, wie von Maschinencode bis über den Assembler ein Buchstabe in einer Konsole ausgegeben wird.
Von Maschinecode bis über den Assembler? Ergibt für mich wenig Sinn.
 
tollertyp schrieb:
Von Maschinecode bis über den Assembler?
Jepp, die Reihenfolge ist eigentlich andersrum, aus Assembler wird Maschinencode und der wird ausgeführt. Wobei Assembler größtenteils nur eine lesbare Variante des Maschinencodes ist (von so Erweiterungen wie den Makro-Assemblern mal abgesehen)
 
  • Gefällt mir
Reaktionen: EnVerdichtet
Danke für eure Antworten!

"Von Maschinecode bis über den Assembler? Ergibt für mich wenig Sinn."

Das ist gut möglich. Ich kenne mich ja wie gesagt noch nicht aus. Wo meinst du sollte ich am besten anfangen?

"Willst du wirklich Maschinen-Code verstehen, oder willst du verstehen, wie ein Prozessor diesen ausführt?"

Mir geht es besonders um die Hierarchie.
Also wie der Prozessor Schritt für Schritt Maschinencode weitergibt.
Zum Beispiel: Maschinencode > Compiler > Assemblersprache (dieses Beispiel kann wie gesagt auch falsch sein)

Werde mir die 7 Videos auf jeden Fall gleich anschauen. Auch der Mikrocomputer sieht sehr interessant aus.
 
EnVerdichtet schrieb:
Zum Beispiel: Maschinencode > Compiler > Assemblersprache (dieses Beispiel kann wie gesagt auch falsch sein)
Wenn ein Compiler im Spiel ist dann umgeht man den Schritt mit dem Assembler. Es ist entweder:

Hochsprache - Compiler - Maschinensprache - CPU
Assemblersprache - Assembler - Maschinensprache - CPU
oder auch neuerdings:
Hochsprache - Compiler - Zwischensprache - JIT - Maschinensprache - CPU

letzteres ist vor allem .NET oder Java.
 
  • Gefällt mir
Reaktionen: NJay, EnVerdichtet und Tornhoof
EnVerdichtet schrieb:
Maschinencode bis über den Assembler ein Buchstabe in einer Konsole ausgegeben wird.
Klar, total einfach...
Das sind dutzende Schritte, da passiert dreckige MMIO Magie, Zeichentabellen in Hardware sind beteiligt, Betriebssystem? Speicherverwaltung, Sceduler,...
 
@Jesterfox Hey, vielen Dank! Die ersten beiden Beispiele habe ich glaube ich verstanden! Das dritte Beispiel ist mir als Laie zu verwirrend ;)

Wenn ich dich richtig verstanden habe, dann geht die Hierarchie also nicht von der CPU aus, sondern von der Programmiersprache. Liegt das daran, dass ein Befehl über diese Sprache ausgeführt wird?

@scooter010 Pardon, ich habe nicht geschrieben, dass es einfach ist. Ich habe lediglich nach Tipps gefragt, wie ich es so einfach wie möglich verstehen kann. Wie gesagt geht es mir in erster Linie um das Verständnis.

Vielleicht kannst du diese Schritte ja grob zusammenfassen, um sie mir verständlich zu machen. Also ohne konkrete Schritte oder Programmierung. Sondern die Logik dahinter.
 
in Maschinencode lassen sich halt quasi "nur" elementare Dinge machen (wobei auch da optimierte Befehlssätze das Gegenteil beweisen). Ein Befehl alleine tut meistens sehr wenig und sie setzen sich eigentlich implizit auch aus mehreren zusammen. So kann zwar mit einem Befehl addiert werden, aber die beiden Werte, die addiert werden sollen, müssen vorher oft noch aus dem Speicher irgendwo her geholt werden usw...

Um bei der Konsolenausgabe zu bleiben: In einer Hochsprache hast du dafür einen schönen Befehl meistens. Da kannst du sagen "In dieser Zeile passiert es". Im Hintergrund sind das aber unzählige Befehle, die da ablaufen, wo man eigentlich keinem mehr ansieht, was das eigentliche Ziel ist.

Das "nur" am Anfang soll nicht wertend sein. Aber all die Aufgaben lassen sich alt immer auf kleinere Teilaufgaben herunterbrechen.

Ich meine für uns ist das Einschenken aus einer Flasche in ein Glas z.B. eine Anweisung. In der Realität musst du dafür aber viele Schritte machen. Flasche nehmen, öffnen, ansetzen, ...
Das Flasche öffnen kann man wieder runter brechen mit "Deckel greifen, Hand drehen, umgreifen, nochmal drehen, ..."
Und auch diese Dinge lassen sich runterbrechen, bis man irgendwann bei ganz nichtssagenden Befehlen angekommen ist. (Also sowas wie "Impuls an Muskel so und so")
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: EnVerdichtet
EnVerdichtet schrieb:
Liegt das daran, dass ein Befehl über diese Sprache ausgeführt wird?
Es ist eigentlich vor allem die zeitliche Reihenfolge... der Programmierer schreibt in der Hochsprache oder Assembler, die Ausführung auf der CPU kommt dann erst später.

Mein letztes Beispiel ist etwas komplexer, aber eigentlich nur weil da halt noch eine Stufe dazwischen kommt. Der Compiler erzeugt erst mal nur eine Zwischensprache die unabhängig der ursprünglichen Hochsprache ist (sie hängt vom System ab, Java hat da eine andere als .NET) und während der Ausführung erzeugt ein just-in-time Compiler den Maschinencode aus dieser Zwischensprache.
 
  • Gefällt mir
Reaktionen: EnVerdichtet
@tollertyp "Willst du wirklich Maschinen-Code verstehen, oder willst du verstehen, wie ein Prozessor diesen ausführt?"

Vielleicht hast du ja recht und das ist die richtige Definition meiner Frage. Also die Schritte von der Eingabe eines Befehls bis hin zur Maschine.

Ich glaube ich habe falsch herum gedacht, weil ich davon ausgegangen bin, dass der Prozessor der Anfang ist.
Wenn ich meine Gedanken umdrehe: Nehmen wir an, ich gebe einen Buchstaben auf meiner Tastatur ein. Wie wird dieser verarbeitet bis er bei der CPU ankommt?

Ich meine damit nicht die einzelnen Befehle im Hintergrund, sondern die logische Abfolge der Hardware und Sprachen.

PS: Schaue mir gerade das Video an. Ist sehr interessant, aber ich merke mir fehlt ganz offensichtlich schon dort grundlegendes Wissen allein über die Platine. Ich werde mir aus Interesse trotzdem auch die anderen Videos anschauen.
 
EnVerdichtet schrieb:
@tollertypNehmen wir an, ich gebe einen Buchstaben auf meiner Tastatur ein. Wie wird dieser verarbeitet bis er bei der CPU ankommt?

Ich meine damit nicht die einzelnen Befehle im Hintergrund, sondern die logische Abfolge der Hardware und Sprachen.
Was Du willst ist demnach: Wie funktioniert die sogenannte "von-Neumann-Architektur", die auch heute noch im Wesentlichen die Grundlage aller Computerei ist.
 
  • Gefällt mir
Reaktionen: EnVerdichtet
@blöderidiot Ich danke dir! Das ist tatsächlich genau das was ich gesucht habe.

Dann werde ich mal anfangen ein paar Videos zu schauen.

Tut mir leid, falls ich mich anfangs umständlich ausgedrückt habe!
Ihr wart alle eine große Hilfe! Und wesentlich freundlicher, als man es aus anderen Foren so gewohnt ist.
 
Maschinencode ist das, was die CPU ganz am Schluss braucht.
Kann man natürlich selbst erstellen (wird nur noch extrem selten gemacht)

Weil sich keiner mit dem "Scheiß" beschäftigen will, macht man alles in einer Hochsprache.
z.b. C#, der Compiler übersetzt das dann in den passenden Maschinencode.
Mit dem Maschinencode muss man sich also eigentlich gar nicht mehr befassen.
Ardoino ist da eine schöne Plattform zum üben.


https://de.wikipedia.org/wiki/Maschinensprache

einfaches c Programm:
int main() {
int a = 2;
int b = 3;
int c = a + b;
return c;
}

Das gleiche in Maschinensprache:
Maschinencode
(hexadezimal)
zugehöriger Assemblercodezugehöriger C-CodeErläuterung
55
48 89 E5
push rbp
mov rbp, rsp
int main() {Sichere Register RBP auf dem Stack und setze RBP auf den Wert von Register RSP, dem Stackpointer (gehört nicht zur eigentlichen Berechnung). Diese Vorbereitung ist notwendig, um die Werte der Variablen a, b und c auf dem Stack speichern zu können.
C7 45 FC 02mov DWORD PTR [rbp-4], 2int a = 2;Setze Variable a, die durch Register RBP adressiert wird, auf den Wert 2.
C7 45 F8 03mov DWORD PTR [rbp-8], 3int b = 3;Setze Variable b, die durch Register RBP adressiert wird, auf den Wert 3.
8B 45 F8
8B 55 FC
01 D0
89 45 F4
mov eax, DWORD PTR [rbp-8]
mov edx, DWORD PTR [rbp-4]
add eax, edx
mov DWORD PTR [rbp-12], eax
int c = a + b;Setze Register EAX auf den Wert von Variable b.
Setze Register EDX auf den Wert von Variable a.
Addiere den Wert von EDX zum Wert von EAX.
Setze Variable c, die durch RBP adressiert wird, auf den Wert von EAX.
8B 45 F4mov eax, DWORD PTR [rbp-12]return c;Setze Register EAX auf den Wert von Variable c. Weil Register EAX diesen Wert bereits enthält, könnte diese Anweisung in einem optimierten Programm entfallen.
5D
C3
pop rbp
ret
}Setze RBP wieder auf seinen ursprünglichen Wert.
Springe zurück an die Stelle des Aufrufs von main. Register EAX enthält den Rückgabewert.

Und das ist bei jeder Controllerfamilie anders!
Damit will sich nun wirklich keiner mehr befassen.


also streich aus deinem Lernvorhaben den Maschinencode, der bringt dich nicht weiter.
 
  • Gefällt mir
Reaktionen: EnVerdichtet und tollertyp
Eben. Also sich mit Maschinencode zu befassen ist wie wenn man als Biologe sich mit der Physik beschäftigt, die letztendlich für alles verantwortlich ist. Kann man machen, bringt aber nicht unbedingt immer viele bessere Erkenntnisse.

Das Schnipsel zeigt auch sehr gut was ich meine, dass ein für uns "einfacher Befehl" in Maschinencode ziemlich komplex aussieht und man nicht mal dem Assembler-Code - bis auf die Zeile "add eax, edx" - gut ansieht, was gerade passiert.

Edit:
Zum Thema freundlich: Auch hier kann es "rauer" sein, war ich selbst gerade wo anders. Wie sagt man so schön: Wie man in den Wald hinein ruft, so schallt es heraus.
 
@florian. Vielen Dank für das Beispiel! Ich glaube ich hab es sogar verstanden. Also den C-Code. Echt klasse. Habe schon tagelang nach diesen Infos gesucht.

Deinen Rat werde ich mir zu Herzen nehmen. Der C-Code ist auf jeden Fall sehrviel übersichtlicher. Das einzige was ich nicht ganz verstanden habe, ist das int main() vor den Klammern. Bedeutet deine Erklärung zum Speichern, dass ich dieses Programm immer wieder ausführen kann? Was ist ein Stack? Davon habe ich noch nie gehört.

@tollertyp Da hast du natürlich recht. Actio und Reactio (wo du gerade von Physik gesprochen hast ;)).
 
int --> Format der Rückgabe Variable (hier c)
main --> jedes "C" Programm braucht eine main Funktion als "Start"

um bei deinem Beispiel "Konsolenausgabe" zu bleiben:
in "c" sieht das so aus : https://de.wikipedia.org/wiki/Printf
#include <stdio.h>

int main(void)
{
printf("Hallo Welt!\n");
return 0;
}
Bibliothek einbinden: #include <stdio.h> (Standard Input Output)
Sachen ausgeben: printf("Hallo Welt!\n");

Was der Computer im Hintergrund daraus macht, interessiert eigentlich niemanden.
 
"int main()" ist halt eine Funktion, die ein "int" (also einen Ganzzahlwert) zurückliefern kann muss. Eine Funktion ist vereinfacht gesagt ein abstrakterer Befehl (der sich wiederum aus anderen Befehlen zusammensetzt). "main" ist eine spezielle Funktion, die bei einem C-Programm eben als Startpunkt verwendet wird. Da geht es auch los - auch wenn das Programm selbst eigentlich noch wo anders beginnt, auch hier findet bereits eine Abstraktion statt.

Der Stack (Stapel) ist ein Speicherkonzept das vom Prozessor so vorgegeben/unterstützt wird. (Fast) jedes Programm hat dafür einen reservierten Speicherbereich. Das ist halt ein Speicher, der sehr dynamisch aber meist nur kurzzeitig genutzt wird, um z.B. vorübergehend Dinge zu merken. Das können unterschiedliche Dinge sein, hier kurzzeitig genutzte Variablen, die nach Verlassen von main() nicht mehr gebraucht werden. Daneben werden noch andere Dinge auf den Stack gelegt (z.B. Rücksprungadressen, Parameter für Funktionsaufrufe).

Man kann Dinge auf den Stack legen (push) und vom Stack holen (pop), das ist eben wie ein Stapel dann, was zuletzt drauf kam, kommt auch zuerst wieder runter. Oder man kann auf Werte im Stack direkt zugreifen DWORD PTR [rbp-4]. Warum das alles technisch so notwendig ist, das geht hoffentlich zum Teil aus den Videos hervor.

Hochsprachen abstrahieren diese ganzen Dinge zum Glück.
 
  • Gefällt mir
Reaktionen: EnVerdichtet
Jesterfox schrieb:
Wenn ein Compiler im Spiel ist dann umgeht man den Schritt mit dem Assembler. Es ist entweder:

Hochsprache - Compiler - Maschinensprache - CPU
Assemblersprache - Assembler - Maschinensprache - CPU
oder auch neuerdings:
Hochsprache - Compiler - Zwischensprache - JIT - Maschinensprache - CPU

letzteres ist vor allem .NET oder Java.

Verstehe die Vereinfachung. Aber die APIs vergessen Du hast ;)

Kompiliert wird ja für die jeweilige API, welche dann wiederum in Maschinensprache bzw. Befehlssätze übersetzt. Und der Decoder stückelt es dann auf die letzte Ebene, die Bits.
 
Zurück
Oben