Forum: PC-Programmierung x86-Programmierung und Befehlsabarbeitung


von torben_25 (Gast)


Lesenswert?

Hallo zusammen,

ich bin zunächst auf der Suche nach einem einfachen 
x86-Assemblerprogramm, das ein beliebiges Speicherwort in das Register 
AX schreibt und einen anderen beliebigen Registerwert hinzuaddiert.

Würde mir hier jemand helfen?

Vielen Dank

von Mark B. (markbrandis)


Lesenswert?

Das ist einmal ein MOV, und einmal ein ADD Befehl. Die genaue Syntax 
hängt etwas davon ab welchen Assembler man verwendet.

Hier zum Beispiel gibt es Erläuterungen zum Thema:
https://www.cs.virginia.edu/~evans/cs216/guides/x86.html

von torben_25 (Gast)


Lesenswert?

Danke für den Link.

ich habe es selbst versucht und bin zu folgendem Ergebnis bzw. Code 
gekommen:

#Zuerst deklariere ich eine 8-Bit-Variable x, die den wert 96 enthält.
1
x DB 96
#Ich verschiebe diese Variable in ein internes Register
1
mov eax, x
#Nun addiere ich den Wert 42 zu diesem Register.
1
add eax, 42

Jetzt müsste sich IMHO der Wert 138 im Register eax befinden.

Ist das korrekt?

von Ben B. (Firma: Funkenflug Industries) (stromkraft)


Lesenswert?

mov ax, <16 bit direkt>
add ax, <16 bit direkt>

also

mov ax,1234h
add ax,4321h

danach hat AX den Wert 5555h

Geht natürlich auch mit EAX und 32 Bit Werten.


oder ein klein wenig praktischer:

mov eax,1
mov ebx,2
add eax,ebx

danach hat EAX den Wert 3

: Bearbeitet durch User
von torben_25 (Gast)


Lesenswert?

Ben B. schrieb:
> danach hat AX den Wert 5555h

Danke für die Hilfe.

Die Nahelem-Mikroarchitektur besitzt einen Befehls-Cache und einen 
Daten-Cache. 
(https://en.wikichip.org/wiki/intel/microarchitectures/coffee_lake)

Bezogen auf den Befehl
1
 mov eax,1
 stelle ich mir die Frage, welche Teile des Befehls in den Befehls-Cache 
und welche in den Daten-Cache gelangen.

von Ben B. (Firma: Funkenflug Industries) (stromkraft)


Lesenswert?

Nehalem.

Das sind Prozessor-Internas, die für die Programmierung recht wenig 
interessant sind. Aber ich würde davon ausgehen, daß der OpCode oder 
µCode MOV EAX<-DIRECT in den Befehlscache wandert und der Wert 1 in den 
Datencache.

von Rolf M. (rmagnus)


Lesenswert?

Nein, der Wert 1 ist ein Immediate, also Bestandteil der Instruktion. 
Die landet einfach komplett so wie sie ist im Befehls-Cache.
Im Datencache landen Zugriffe auf Speicher, also wenn man z.B. mit einem 
weiteren MOV den Inhalt von EAX an irgendeine RAM-Adresse schreibt.

von Ben B. (Firma: Funkenflug Industries) (stromkraft)


Lesenswert?

Das kann auch sein, weiß nicht wie elementar der Prozessor die 
Instruktionen zerlegt.

von Programmierer (Gast)


Lesenswert?

Ben B. schrieb:
> Das kann auch sein, weiß nicht wie elementar der Prozessor die
> Instruktionen zerlegt.

CPU Caches arbeiten blockweise, d.h. z.B. ein 4kB-Block (Page genannt) 
des Hauptspeicher wird 1:1 in einen Cache Block abgebildet. Die 
Instruktionen werden damit "am Stück", inklusive Immediate Werten, in 
den Cache übernommen. Es wäre ziemlich sinnlos, den gleichen 
Hauptspeicher Bereich sowohl im Daten- als auch Befehls Cache abzulegen. 
Ein Aufteilen der Instruktionen beim Füllen des Cache findet nicht 
statt, damit wäre auch nichts gewonnen.

von (prx) A. K. (prx)


Lesenswert?

torben_25 schrieb:
> Die Nahelem-Mikroarchitektur besitzt einen Befehls-Cache und einen
> Daten-Cache.
> (https://en.wikichip.org/wiki/intel/microarchitectures/coffee_lake)

Es stimmt zwar für beide, aber zwischen Nehalem und Coffee Lake liegt 
ein Jahrzehnt.

von (prx) A. K. (prx)


Lesenswert?

Programmierer schrieb:
> CPU Caches arbeiten blockweise, d.h. z.B. ein 4kB-Block (Page genannt)
> des Hauptspeicher wird 1:1 in einen Cache Block abgebildet.

Die Grundstruktur von Caches sind nicht Pages, sondern Lines, und die 
sind nicht 4kB gross, sondern z.B. 64 Bytes.

Pages gibts in der MMU, und die sind tatsächlich meist 4kB gross. Das 
hat aber keinen Bezug zu I/D-Caches, sondern nur zu TLBs.

: Bearbeitet durch User
von torben_25 (Gast)


Lesenswert?

Müsste die Befehlsabarbeitung nicht streng nach dem Harvard-Prinzip 
erfolgen? Was man aber konkret damit meint, kann ich nicht herausfinden. 
Viele Quellen beschränken sich auf die Ausage, Programm-Speicher und 
Datenspeicher seien getrennt.

von (prx) A. K. (prx)


Lesenswert?

Ben B. schrieb:
> Das sind Prozessor-Internas, die für die Programmierung recht wenig
> interessant sind. Aber ich würde davon ausgehen, daß der OpCode oder
> µCode MOV EAX<-DIRECT in den Befehlscache wandert und der Wert 1 in den
> Datencache.

Nein. Spannend wird es erst bei solchem Code, wenn also auf Code per 
Datenbefehl zugegriffen wird:
    mov al, [l1]
l1: nop

Oder in der verschärften Fassung als:
    mov [l1], al
l1: nop

Was dann intern abgeht kann sehr interessant sein, geht aber 
kilometerweise über diesen Thread hinaus.

von (prx) A. K. (prx)


Lesenswert?

torben_25 schrieb:
> Müsste die Befehlsabarbeitung nicht streng nach dem Harvard-Prinzip
> erfolgen? Was man aber konkret damit meint, kann ich nicht herausfinden.
> Viele Quellen beschränken sich auf die Ausage, Programm-Speicher und
> Datenspeicher seien getrennt.

Auf die realen x86 Prozessoren der letzten gut 2 Jahrzehnte sind die 
Begriffe Harvard / von Neumann nicht sinnvoll anwendbar. Einer meint, 
getrennte I/D-Caches machen Harvard draus, ein Anderer sieht dank des 
gemeinsamen RAMs und Adressraums darin von Neumann.

von Ben B. (Firma: Funkenflug Industries) (stromkraft)


Lesenswert?

Wäre möglich, daß die eigentliche Abarbeitung für den Cache 
uninteressant ist. Aber diese Prozessoren sind bestimmt in der Lage, 
bestimmte Speicherbereiche, die möglicherweise gleich benötigt werden, 
in den Cache vorzuladen wenn dafür freie Speicherbandbreite zur 
Verfügung steht.

Man könnte auch fragen, ob die Verarbeitungs-Pipeline eigene Caches 
hat...

von (prx) A. K. (prx)


Lesenswert?

Ben B. schrieb:
> Aber diese Prozessoren sind bestimmt in der Lage,
> bestimmte Speicherbereiche, die möglicherweise gleich benötigt werden,
> in den Cache vorzuladen wenn dafür freie Speicherbandbreite zur
> Verfügung steht.

Ja. Nur ist das für die Sicht des Programmierers auf den prinzipiellen 
Programmablauf völlig irrelevant. Hat nur Einfluss auf die Laufzeit, 
nicht auf das Ergebnis.

> Man könnte auch fragen, ob die Verarbeitungs-Pipeline eigene Caches
> hat...

Trace caches und solche für decoded instructions. Sonst jede Menge 
Puffer aller Art, aber nichts, was man gemeinhin als Cache bezeichnet.

Alles was über Rolfs Antwort hinaus geht, ist für Torben erst einmal 
nicht relevant und führt nur zu Verwirrung.

: Bearbeitet durch User
von torben_25 (Gast)


Lesenswert?

Ich möchte noch einmal die meine letzte Frage aufgreifen. Im Daten-Cache 
liegen die Daten, im Befehl-Cache die Befehle.

Die Autoren Schiffmann, Bähring und Hönig sind im Buch Technische 
Informatik 3 der Meinung, die Intel-Core-Architektur sei intern eine 
Harvard-Architektur, denn sie weise mit den beiden getrennten Caches für 
Instruktionen und Daten die typischen Merkmale dafür auf.

Kann es aber sein, dass die beiden Caches damit gar nichts zutun haben?

Wenn ich das folgende x86-Programm
mov R04, 125
mov EAX, R04
ADD EAX, R01

betrachte, dann muss ich feststellen, dass sich die Trennung von Daten 
und Befehlen ja schon aus der Tatsache ergibt, dass die Werte (wie z. B. 
125 ) in einzelne separate Register geschrieben werden, in denen keine 
Vermischung von daten und Befehlen stattfindet.

von torben_25 (Gast)


Lesenswert?

A. K. schrieb:
> Auf die realen x86 Prozessoren der letzten gut 2 Jahrzehnte sind die
> Begriffe Harvard / von Neumann nicht sinnvoll anwendbar. Einer meint,
> getrennte I/D-Caches machen Harvard draus, ein Anderer sieht dank des
> gemeinsamen RAMs und Adressraums darin von Neumann.

Danke, habe ich erst gesehen, nachdem ich meinen Beitrag gepostet habe.

von Ben B. (Firma: Funkenflug Industries) (stromkraft)


Lesenswert?

Für mich ist das weiterhin ganz klar eine von-Neumann-Architektur. Code 
ist Daten und Daten sind Code, der komplette Hauptspeicher kann variabel 
für beides genutzt werden, beides kann jederzeit gegeneinander 
ausgetauscht werden. Das kann die Harvard-Architektur nicht. Ein 
Harvard-Computer kann keinen Code im Datensegment ausführen, man müsste 
ein solches Programm erst vom Datensegment in das Codesegment kopieren.

Durch Mechanismen wie Speicherschutz usw. werden zwar bestimmte Vorteile 
der Harvard-Architektur kopiert (z.B. daß der Prozessor daran gehindert 
wird, Code außerhalb von Codesegmenten auszuführen), aber das ist 
Programmierung und hat mit dem grundlegenden Aufbau nichts zu tun.

von (prx) A. K. (prx)


Lesenswert?

Ben B. schrieb:
> Für mich ist das weiterhin ganz klar eine von-Neumann-Architektur.

Und für Torbens Lehrbuch ist es eindeutig Harvard. Woraus man den 
Schluss ziehen sollte, dass diese Klassifizierung sinnlos geworden ist, 
oder man explizit ranschreiben sollte, ob man sich auf L1-Caches oder 
Adressräume bezieht.

Wobei es selbst bei Caches schwierig sein kann, das klar zu erkennen. 
Der Cyrix M2 hatte einen gemeinsamen 64kB I/D-Cache, dem aber ein 256B 
L0-Cache für Befehle vorgeschaltet war. Rechnet man den Winzling mit, 
war es Harvard, sonst von-Neumann.

: Bearbeitet durch User
von Ben B. (Firma: Funkenflug Industries) (stromkraft)


Lesenswert?

Wenn man es so betrachtet, ist es aber generell die Frage, ab wo ich die 
Betrachtung ansetze. Sobald ich die Prozessor-intern ansetze, wirds 
natürlich schwammig, weil spätestens in den eigentlichen Recheneinheiten 
µCode und Daten physikalisch nebeneinander vorliegen. Wenn man so 
rangeht, dürfte es gar keine Von-Neumann-Architektur geben.

Mal ein Gegenbeispiel: Der AVR-µC ist ein klassischer Vertreter der 
Harvard-Architektur. Daten und Code liegen in verschiedenen 
physikalischen Speicherbereichen (sogar mit verschiedener 
Speichertechnologie). Deswegen ist das Teil auch recht schnell, auf 
Befehle und Daten kann gleichzeitig zugegriffen werden. Und egal wieviel 
Mühe ich mir geben würde, es ist nicht möglich, Befehlscode aus dessen 
RAM heraus auszuführen. Ich müsste solchen Code erst ins Flash kopieren 
und dadurch zu Code wandeln.

Der x86 als klassischer Von-Neumann-Rechner muß Code und Daten 
nacheinander aus dem Hauptspeicher laden. Er benötigt daher mehr 
Speicherzyklen (wo eine Harvard-Architektur immer nur einen einzigen 
Zyklus braucht). Irgendwo im Prozessor wird dann natürlich in Code und 
Daten aufgeteilt, ob das nun im Cache oder erst in den Recheneinheiten 
passiert finde ich unrelevant. Dazu kann der x86 ohne jedes Problem im 
gesamten Adressbereich herumspringen, im Real Mode kennt er keinen 
Speicherschutz. Er kann nicht zwischen Code und Daten unterscheiden, ein 
Harvard-Rechner kann das.

von (prx) A. K. (prx)


Lesenswert?

Ben B. schrieb:
> Mal ein Gegenbeispiel: Der AVR-µC ist ein klassischer Vertreter der
> Harvard-Architektur.

Jo, aber das Ding ist ja auch nicht komplexer als die Rechner aus der 
Ära, aus der die Begriffe stammen.

> Der x86 als klassischer Von-Neumann-Rechner muß Code und Daten
> nacheinander aus dem Hauptspeicher laden.

Nö. Also der 8088 schon, aber heutige x86 nicht. I- und D-Strukturen mit 
ihren Caches operieren völlig getrennt, somit parallel. Und auch wenn du 
auf die Schnittstelle zum externen DRAM raus willst, passt es nicht, 
denn da kannst du mehrere unabhängig operierende DRAM-Busse haben.

Allerdings brauchst du mich nicht davon zu überzeugen, allenfalls 
Adressräume als Kritierium zu betrachten. Meine Rede seit Jahren. Nur 
sind die Begriffe in der Fachliteratur unverrückbar an sogenannten 
Bussen festgenagelt - die es heute überhaupt nicht mehr gibt. Frei 
interpretiert landet man bei Adressräumen. Orthodox wirds willkürlich, 
an welcher Struktur man ansetzt.

: Bearbeitet durch User
von Ben B. (Firma: Funkenflug Industries) (stromkraft)


Lesenswert?

Doch, bei der Harvard-Architektur gibt es genau das. Hardwareseitig 
getrennte Daten- und Befehlscode-Busse, die ausschließlich eines von 
beiden transportieren und auch nicht umgeschaltet werden können.

Naja egal, einen Konsens darüber wird es wohl nicht geben und heutige 
Prozessoren mögen Hybride aus beidem sein, um die Vorteile von beiden 
Ideen nutzen zu können.

Oder anders, man könnte es auch auf die Spitze treiben und einen alten 
x86 mit einem AVR simulieren. Dann bleibt es ein Von-Neumann-Rechner, 
obwohl die "CPU" eigentlich streng der Harvard-Architektur folgt.

von (prx) A. K. (prx)


Lesenswert?

Ben B. schrieb:
> Doch, bei der Harvard-Architektur gibt es genau das. Hardwareseitig
> getrennte Daten- und Befehlscode-Busse, die ausschließlich eines von
> beiden transportieren und auch nicht umgeschaltet werden können.

Dann ist AVR von-Neumann, denn man kann mit einem speziellen Befehl auf 
den Codespeicher zugreifen. Bei den 16-Bit PICs, eigentlich klar 
Harvard, auch mit normalen Befehlen.

Aber verlassen wir mal die 50er Jahre: Welche heute verwendete 
Architektur ist deiner Definition nach Harvard, kann also nicht auf 
Codespeicher anders als in Form von Befehlen zugreifen?

: Bearbeitet durch User
von Ben B. (Firma: Funkenflug Industries) (stromkraft)


Lesenswert?

Um diese Frage zu beantworten müsste man sich anschauen, wie der 
"Datenzugriff" auf den Flash beim PIC oder AVR elektrisch realisiert 
ist. Das Datenblatt des AVR gibt dazu nichts her, dort gibt es keine 
Verbindung zwischen Flash und Datenbus.

Wahrscheinlich landet man dann wieder bei der Frage an welcher Stelle 
man die Betrachtung ansetzt.

von Programmierer (Gast)


Lesenswert?

Und wie ist das beim STM32F7? Der hat zwei getrennte RAM Blöcke ITCM und 
DTCM, welche man als schnellen Speicher für Instruktionen bzw. Daten 
nutzen kann, welche über getrennte Busse an die CPU angebunden sind. 
Also klassisch Harvard. Allerdings kann man auch Datenzugriffe auf den 
ITCM machen, also doch etwas Neumannig. Dann gibt es noch den L1 Cache, 
der beides beinhalten kann. Dann noch getrennte Busse für Daten und 
Instruktionen für Flash und normalen SRAM. Doch Harvard?

von torben_25 (Gast)


Lesenswert?

Rolf M. schrieb:
> Im Datencache landen Zugriffe auf Speicher, also wenn man z.B. mit einem
> weiteren MOV den Inhalt von EAX an irgendeine RAM-Adresse schreibt.

Wenn Rolf Recht hat, dann kann ich nicht nachvollziehen, was I-Cache und 
D-Cache mit der Harvard-Architektur zutun haben.

Ich hatte mir das irgendwie so vorgestellt:

Zuerst müsste sämtlicher Hauptspeicherinhalt, der zum Cache 
transportiert wird, erstmal von oben nach unten untersucht werden, ob es 
sich bei der jeweiligen Bitfolgen um Befehle oder Daten handelt.

Dann hätte ich im I-Cache die Befehle und im D-Cache die Daten. Man 
müsste dann irgendwie noch sicherstellen, dass sich die 
Speicheradressen, die in den jeweiligen Befehlen zur Adressierung der 
Operanden angegeben wurden, auf den D-Cache beziehen. Tatsächlich 
beziehen sie sich aber auf die internen Register (EAX etc..) oder den 
Hauptspeicher. Hier bricht dann mein Luftschloss zusammen.

von (prx) A. K. (prx)


Lesenswert?

torben_25 schrieb:
> Wenn Rolf Recht hat, dann kann ich nicht nachvollziehen, was I-Cache und
> D-Cache mit der Harvard-Architektur zutun haben.

Man kann sich darüber zwar ewig streiten, aber nutzlos.

> Zuerst müsste sämtlicher Hauptspeicherinhalt, der zum Cache
> transportiert wird, erstmal von oben nach unten untersucht werden, ob es
> sich bei der jeweiligen Bitfolgen um Befehle oder Daten handelt.

Wozu? Schräges Konzept. Die instruction fetch unit will Befehle, die 
load/store units wollen Daten. Damit ist der Fall ja wohl klar. Die L1 
caches sind sowieso dicht in diese Units integriert, die kann man kaum 
isoliert betrachten. Abgesetzt ist erst ein L2 cache.

Bissel komplizierter wird es, wenn die betreffenden Daten vorher im 
falschen Cache liegen (siehe Beispiel oben). Damit bei einem 
Schreibbefehl in den Code Ordnung statt Chaos herrscht. Aber wenn du es 
gerne noch komplizierter haben willst, dann betrachte den Fall mehrerer 
Cores, einer führt die Bytes als Befehl aus, der andere modifiziert 
genau diesen Code.

> Hier bricht dann mein Luftschloss zusammen.

Besser so. Völlig falsche Vorstellung.

von Rolf M. (rmagnus)


Lesenswert?

torben_25 schrieb:
> Zuerst müsste sämtlicher Hauptspeicherinhalt, der zum Cache
> transportiert wird, erstmal von oben nach unten untersucht werden, ob es
> sich bei der jeweiligen Bitfolgen um Befehle oder Daten handelt.

Woran sollte das erkannt werden? Jede beliebige Bitfolge kann Daten 
sein. Da wird auch nichts durchlaufen. Der Cache soll sich nur 
Ergebnisse von Zugriffen merken, um sie beim nächsten mal schneller 
ausführen zu können.

> Dann hätte ich im I-Cache die Befehle und im D-Cache die Daten. Man
> müsste dann irgendwie noch sicherstellen, dass sich die
> Speicheradressen, die in den jeweiligen Befehlen zur Adressierung der
> Operanden angegeben wurden, auf den D-Cache beziehen. Tatsächlich
> beziehen sie sich aber auf die internen Register (EAX etc..) oder den
> Hauptspeicher. Hier bricht dann mein Luftschloss zusammen.

Es ist eigentlich ganz einfach. Der Prozessor führt Instruktionen aus. 
Bei der ersten Instruktion wird diese und die folgenden als eine 
Cache-Line in den Cache kopiert. Die zweite Instruktion steht dann 
bereits im Cache. Und wenn später nochmal dieser Codeteil ausgeführt 
wird, steht er komplett im Cache. Das ist alles I-Cache.
Nun greift das Programm auch auf Variablen im RAM zu. Diese laufen dann 
über den D-Cache. Der arbeitet als write-back-Cache, d.h. 
Schreibzugriffe gehen erstmal nur in den Cache und landen irgendwann 
später dann im RAM. Auch hier kann man Vorteile aus Cache-Lines ziehen, 
weil oft sequenziell  zugegriffen wird, z.B. beim Durchlaufen eines 
Arrays.
Somit hat man eine strikte Trennung von Code und Daten bei den Caches, 
wobei ein in der Instruktion enthaltener Immediate-Wert zum Code gehört, 
wie bei einer Harvard-Architektur ja auch.

von (prx) A. K. (prx)


Lesenswert?

Rolf M. schrieb:
> Woran sollte das erkannt werden?

Die Telefunken TR440 hatte 48 Bit Wortbreite plus 2 Bit Typenkennung:
1
0 – Gleitkommawert oder höherwertiger Teil bei doppelter Genauigkeit
2
1 – Festkommawert oder niedrigwertiger Teil einer doppelt genauen Gleitkommazahl
3
2 – Befehlsworte oder Adressen (2 je Ganzwort)
4
3 – Zeichenkette (meist 6 Zeichen mit 8 Bit je Ganzwort) oder beliebige Bitmaterie

Also prinzipiell... ;-)

: Bearbeitet durch User
von torben_25 (Gast)


Lesenswert?

Ich habe es jetzt verstanden. Der Punkt mit Load/Store hat mir gefehlt. 
Ich bedanke mich bei allen, die mir bei meiner Frage hier weitergeholfen 
haben!

von Torben (Gast)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,

Gegeben ist ein fiktives Assembler-Programm.
1
mov EAX, 200
2
add EAX, [x+2]
3
4
section .data
5
x DD 2F1000

Ich möchte die ersten zwei Zeilen in Maschinen-Code überführen. Liege 
ich richtig mit der Annahme, dass ich das Befehlsformat verwenden muss, 
das ich diesem Beitrag als Bild angehängt habe?

von (prx) A. K. (prx)


Lesenswert?

Du kannst dieses Format auch für den ersten Befehl verwenden, musst es 
aber nicht.

: Bearbeitet durch User
von Rene K. (xdraconix)


Lesenswert?

Kann man eigentlich die ganzen Threads zu ein und dem selben Thema nicht 
mal zusammenfassen?

Zu zum Beispiel "Torben lernt x86-ASM" oder so?

Nimm mir das nicht übel aber demnächst erscheint womöglich für die 
Erklärung von mov, add, nop etc.. Noch jeweils ein Thread.

von (prx) A. K. (prx)


Lesenswert?

Immerhin hat er hier doch schon einen eigenen Thread für eine neue Frage 
recycelt, statt einen neuen aufzumachen.

von torben_25 (Gast)


Lesenswert?

Rene K. schrieb:
> Nimm mir das nicht übel aber demnächst erscheint womöglich für die
> Erklärung von mov, add, nop etc.. Noch jeweils ein Thread.

ich gelobe Besserung!

Ein Assembler-Befehl wie
1
 mov EAX, 200

besteht doch aus ASCII-Zeichen. Welcher Zusammenhang existiert denn 
zwischen diesem Befehl und dem Befehlsformat, der im x86-Manual 
abgebildet ist?

Präfix|Opcode|ModR/M|SIB|Displacement|Immediate

Beide haben doch einen völlig unterschiedlichen Aufbau.

von Programmierer (Gast)


Lesenswert?


von torben_25 (Gast)


Lesenswert?

Aber ist jetzt das Format

Präfix|Opcode|ModR/M|SIB|Displacement|Immediate

auf Maschinencode bezogen oder auf Assemblercode?

von Programmierer (Gast)


Lesenswert?

Das ist Maschinencode. Benutze doch einen Assembler, um deinen 
Assemblersprachen-Code in Maschinencode zu überführen. Das von Hand zu 
machen macht sehr wenig Sinn.

von georg (Gast)


Lesenswert?

torben_25 schrieb:
> Beide haben doch einen völlig unterschiedlichen Aufbau.

Das spielt überhaupt keine Rolle, denn ein Befehl wie mov muss von einem 
Übersetzungsprogramm, das ganz zufällig Assembler heisst, in den 
Maschinencode übersetzt werden. Daher ist es auch egal, ob der Befehl 
zum Bewegen einer Zahl mov, ld, cp oder sonstwie heisst, das muss man 
nur dem Assemblerprogramm sagen.

Georg

von torben_25 (Gast)


Lesenswert?

Dürfte ich zu diesem Thema noch einmal Eure Nerven strapazieren.

Ich komme irgendwie durcheinander. In meinem Buch ist das Befehlsformat 
des Core i7 abgebildet.

Die Autoren geben folgendes Format an:

PREFIX | OPCODE | MODE | SIB | DISPLACEMENT | IMMEDIATE

Kurz darauf zeigen sie ein beispielhaftes i7-Assembler-Programm, in dem 
unter anderem der Befehl
1
add eax, 42
 vorkommt.

Doch dieser Befehl entspricht doch gar nicht dem obigen Format.

Wo ist mein Denkfehler?

von Programmierer (Gast)


Lesenswert?

torben_25 schrieb:
> Wo ist mein Denkfehler?

Lies das, dann wird es klar:

Programmierer schrieb:
> https://de.wikipedia.org/wiki/Maschinensprache
> https://de.wikipedia.org/wiki/Assemblersprache
> https://de.wikipedia.org/wiki/Assembler_%28Informatik%29

Das Format bezieht sich auf den Maschinencode/sprache, das "add eax, 42" 
ist Assemblersprache.

von torben_25 (Gast)


Lesenswert?

Das Problem ist: Ich habe deine Quellen gelesen und habe das, was du 
sagst, dort auch so verstanden. Ich bin aber durcheinander gekommen, 
weil in dem Buch, das ich durcharbeite, keine Rede davon ist, dass 
dieses Format Maschinencode ist. Die Autoren schreiben die ganz Zeit 
über Assembler-Code und dann präsentieren sie das Befehlsformat in 
Maschinencode. Wie passt das zusammen?

Kann mir jemand sagen, was man in diesem Zusammenhang unter Offset 
versteht?

von Programmierer (Gast)


Lesenswert?

torben_25 schrieb:
> Wie passt das zusammen?

Dann ist das kein besonders gutes Buch. Da ja Assemblersprache und 
Maschinensprache (mehr oder weniger) 1:1 aufeinander abbildbar sind, 
werden die oft durcheinander gebracht. Nach den Beispiel von Wikipedia 
ist z.B.

"48 89 E5" Maschinensprachen-Code (im Format aus dem Buch), und
"mov rbp, rsp" der zugehörige Assemblersprachen-Code.

Da das zweite deutlich besser lesbar ist, schreibt man meistens nur 
Assemblersprache, unter der Annahme, dass man beides simpel ineinander 
konvertieren kann (mittels Assembler bzw. Disassembler).

Bei z.B. C gilt das aber nicht - ein Stück C-Code lässt sich auf viele 
Weisen in Assemblersprache (und danach in Maschinensprache) überführen, 
und die Kunst besteht darin, die effizienteste Art zu finden. Dabei wird 
oft die Struktur auch derart durcheinander geworfen, dass die 
Rückführung Assemblersprache -> C auch kaum möglich ist.

Je nach Architektur gibt es allerdings auch bei der Assemblersprache 
durchaus Mehrdeutigkeiten, so kann z.B. mancher 
ARM-Assemblersprachen-Code auf verschiedene Arten in Maschinensprache 
ausgedrückt werden; bei x86 weiß ichs nicht.

torben_25 schrieb:
> Kann mir jemand sagen, was man in diesem Zusammenhang unter Offset
> versteht?

Das kann alles mögliche sein. Vermutlich ist damit der "Abstand" 
zwischen zwei Adressen gemeint; indem man auf eine Basisadresse einen 
Offset addiert, erhält man die finale Adresse. Wenn z.B. ein Register 
einen Zeiger auf ein C-struct enthält, könnte man einen Offset von 4 
addieren um das 4. Byte des structs zu laden. Viele 
Speicher-Zugriffs-Instruktionen können diese Addition zusammen mit dem 
Zugriff durchführen, um zusätzliche Rechen-Instruktionen zu vermeiden; 
der AVR kann sowas aber z.B. nicht.

von Pandur S. (jetztnicht)


Lesenswert?

Es gibt zumindest bei der x86 Familie die Offset Adressierung.
Also

Effektive Adressierung (Record) = Segment + Index
Effektive Adressierung (Record Element) = Segment + Index + Offset

Das Erste ist das Objekt zB ein Record, ein Record auf dem Stack,
Dann ist das Zweite die Adresse des Elementes des Records.

Bei einem RISC waere das ein zusaetzlicher Rechenschritt, hier macht die 
Adressiereinheit das.

: Bearbeitet durch User
von Ben B. (Firma: Funkenflug Industries) (stromkraft)


Lesenswert?

ADD EAX,42 hat kein Präfix.

Mit Präfix (Busblockierung) wäre es zB. LOCK ADD EAX, 42 wobei ich jetzt 
nicht nachgesehen habe ob LOCK bei ADD erlaubt ist.

Ein Offset ist einfach nur eine Adresse im Speicher, beim x86 meistens 
relativ zum Anfang eines Segments. Beispielsweise wenn man Variablen im 
RAM benutzt:

MOV word ptr ds:[variable1],AX oder
MOV word ptr ds:[offset variable1],AX

Ein Displacement hast Du bei manchen Speicherzugriffen. Wenn Du z.B. 
Werte auf dem Stack ändern möchtest, kommt häufig sowas wie

ADD SS:[SP+10h],20h

In dem Beispiel wäre +10h das Displacement und 20h das Immediate.

Sowas wie ADD AX,BX z.B. hat nur einen Opcode, sonst nichts.

von torben_25 (Gast)


Lesenswert?

Eure Antworten haben mir wirklich viel gebracht! Großes Danke!

von Sigi (Gast)


Lesenswert?

Programmierer schrieb:
> Je nach Architektur gibt es allerdings auch bei der Assemblersprache
> durchaus Mehrdeutigkeiten, so kann z.B. mancher
> ARM-Assemblersprachen-Code auf verschiedene Arten in Maschinensprache
> ausgedrückt werden; bei x86 weiß ichs nicht.

Bei x86-CPUs gibt es z.B. mov (=: mov1) speziell
für das A-Register (AL,AX,EAX) als Quelle/Ziel,
es gibt aber auch mov (=: mov2) in allgemeinerer
Form und der selben Funktion, bei der aber alle
Register als Quelle/Ziel spezifiziert werden
können. Hier gilt: mov1 ist kürzer als mov2
(bei mov2 wird das entsprechende Register per
ModRegRM spezifiziert).

Und aus solchen Beispielen ergibt sich für ein
Assembler das Problem der nichteindeutigen
Abbildung, Ziel sollte hier aber das möglichst
kürzeste Ergebnis sein.

Beitrag #6135227 wurde vom Autor gelöscht.
von georg (Gast)


Lesenswert?

Sigi schrieb:
> Und aus solchen Beispielen ergibt sich für ein
> Assembler das Problem der nichteindeutigen
> Abbildung, Ziel sollte hier aber das möglichst
> kürzeste Ergebnis sein.

Meiner Meinung nach sollte die Assemblersprache eindeutig sein, denn das 
ist u.a. einer der Gründe, Assembler einzusetzen: dass man genau in der 
Hand hatt, was als Maschinencode rauskommt. Also sollten in so einem 
Fall 2 verschiedene Mnemonics verwendet werden. Ich möchte nicht es 
drauf ankommen lassen, was ein "intelligenter" Assembler da 
rausoptimiert, dann kann ich ja gleich C schreiben.

Ist meine Meinung, wahrscheinlich halten sich längst nicht alle 
Entwickler daran.

Georg

von (prx) A. K. (prx)


Lesenswert?

georg schrieb:
> Ist meine Meinung, wahrscheinlich halten sich längst nicht alle
> Entwickler daran.

Meine Einschätzung: heutzutage niemand.

: Bearbeitet durch User
von olibert (Gast)


Lesenswert?

Hallo torben_25,

ich kann dir dieses Buch empfehlen:

https://www.apress.com/gp/book/9781484224021

Low-Level Programming C, Assembly, and Program Execution on Intel® 64 
Architecture
Authors: Zhirkov, Igor

Der Titel klingt abschreckend, aber es ist sehr gut erklaert mit guten 
Beispielen.

von Programmierer (Gast)


Lesenswert?

georg schrieb:
> Meiner Meinung nach sollte die Assemblersprache eindeutig sein, denn das
> ist u.a. einer der Gründe, Assembler einzusetzen: dass man genau in der
> Hand hatt, was als Maschinencode rauskommt.

Warum ist es so wichtig, dass der Maschinencode exakt kontrollierbar 
ist? Es ist doch viel praktischer, wenn der Assembler automatisch die 
optimale Möglichkeit nimmt. z.B. gibt es bei ARM eine ganze Reihe 
"clevere" Möglichkeiten, Immediates in Register zu laden - jeweils mit 
verschiedenen Codierungen verschiedener Instruktionen. Der Assembler 
nutzt automatisch die  für den jeweiligen Wert effizienteste; diese aber 
jedes Mal von Hand zu ermitteln wäre ziemlich lästig, da einige 
umständliche Bitfummeleien nötig sind. Das gilt besonders wenn die 
konkreten Werte per Makro o.ä. ermittelt werden und sich die zu nutzende 
optimale Vorgehensweise ändern kann...

Falls nötig kann man durch Nutzung spezieller Syntax den Assembler auf 
eine bestimmte Instruktion festnageln. Macht man aber eher selten.

von Ben B. (Firma: Funkenflug Industries) (stromkraft)


Lesenswert?

Es gibt Mnemonics beim x86 Assembler, die nicht so übersetzt werden wie 
sie im Quelltext stehen.

LEA AX, variable1 z.B. wird zu
MOV AX, offset variable1

von (prx) A. K. (prx)


Lesenswert?

Ben B. schrieb:
> LEA AX, variable1 z.B. wird zu
> MOV AX, offset variable1

Und?

Apropos: Es könnte interessant sein, im 64-Bit Modus die Binärcodes 
hiervon zu vergleichen:
  lea eax, variable1
  lea rax, variable1

: Bearbeitet durch User
von rbx (Gast)


Lesenswert?

Sicherlich interessant ist, wenn man im Hexeditor ein Assemblerprogramm 
mit einem C-Programm vergleicht. Man bekommt einen ersten Eindruck, was 
mit "Daten" gemeint sein könnte ;)

Aber ohne Datentypen (z.B. AX, Al, Ah, Byte oder Word Pointer) geht 
nicht viel, so gesehen wären "Daten" zum Teil in die Prozessortechnik 
eingebaut.

Programmiersprachen (und Zeiger oder Datentypen (z.B. die Typenhilfe bei 
Haskell)) wären schon ein passendes Kapitel, aber das hilft nicht 
sonderlich darüber hinweg, wenn man am Anfang mit dem Thema (z.B. BP, SP 
navigation, LEA Anwendung usw.) sehr durcheinander kommt.

https://stackoverflow.com/questions/1658294/whats-the-purpose-of-the-lea-instruction

Und sind "Daten" nicht eher das, was die Computerlinguisten meinen, z.B. 
eine Wörterliste, oder ein Video bzw. mp3?

In der Prozessortechnik kann man z.B. inc ax machen, oder eine 
Listenabarbeitung beschleunigen - wenn man so will, dann sind die diese 
impliziten "Daten" schon mit in die Planung eingeflossen.
Zunehmende Parallelisierung, Kryptohilfen/Packbeschleuniger könnten auch 
in diese Richtung argumentieren.

Das herausragende Merkmal der Intels, nämlich seine Kompatibilität nach 
unten oder oben werden bei der obigen Betrachtung m.E. nicht gewürdigt.

Teilweise kann man seine Trennung haben, wenn man Grafikkarten zur 
Beschleunigung einsetzt und sich das Zusammenspiel von Cpu und 
Grafikkarte denkt und daran denkt, dass die Grafikkarte eine bestimmte 
Art von Daten braucht, wie z.B. ein Matheprogramm.

von Programmierer (Gast)


Lesenswert?

rbx schrieb:
> Das herausragende Merkmal der Intels, nämlich seine Kompatibilität nach
> unten oder oben werden bei der obigen Betrachtung m.E. nicht gewürdigt.

Heutige ARMs können auch alle alten ARM Programme ausführen. Der selbe 
ARM Code kann auf den kleinsten Mikrocontrollern bis zum dicksten Server 
lauffähig sein (wenn entsprechend kompiliert). Die 
Abwärts-kompatibilität wird lediglich auf OS-Ebene eingeschränkt; hier 
werden alte Zöpfe abgeschnitten. Unter solchen leidet x86 ziemlich...

von (prx) A. K. (prx)


Lesenswert?

Programmierer schrieb:
> Heutige ARMs können auch alle alten ARM Programme ausführen.

Die Cortex M können kein ARM7 Programm ausführen.
Die ARM7 wiederum haben Probleme mit ARM2 Programmen.

> wenn entsprechend kompiliert

Entsprechen kompiliert, also in Hochsprache geschrieben, kann ein Cortex 
A76 oft auch ein Program für AMD Ryzen ausführen, und umgekehrt.

: Bearbeitet durch User
von Programmierer (Gast)


Lesenswert?

A. K. schrieb:
> Die Cortex M können kein ARM7 Programm ausführen.

Doch, wenn es in Thumb geschrieben ist.

A. K. schrieb:
> Die ARM7 wiederum haben Probleme mit ARM2 Programmen.

Ach, wieso?

A. K. schrieb:
> Entsprechen kompiliert, also in Hochsprache geschrieben, kann ein Cortex
> A76 oft auch ein Program für AMD Ryzen ausführen, und umgekehrt.

Jeder Cortex-A sollte alle alten ARM-Anwendungs-Programme ohne 
Neukompilierung ausführen können, da er sowohl ARM als auch Thumb Code 
kann. Nur-Thumb-Prozessoren wie Cortex-M können nur alte 
Thumb-Programme, das stimmt.

Die Intel-Quark können auch keinen IA-64-Code ausführen, obwohl sie 
neuer sind...

von Rolf M. (rmagnus)


Lesenswert?

Programmierer schrieb:
> Die Intel-Quark können auch keinen IA-64-Code ausführen, obwohl sie
> neuer sind...

IA-64 ist aber auch schon lange tot.

von Programmierer (Gast)


Lesenswert?

Rolf M. schrieb:
> IA-64 ist aber auch schon lange tot.

Sorry, ich meinte AMD64. Wobei das Argument mit IA64 auch nicht ganz 
falsch ist :-)

von Rolf M. (rmagnus)


Lesenswert?

Programmierer schrieb:
> Rolf M. schrieb:
>> IA-64 ist aber auch schon lange tot.
>
> Sorry, ich meinte AMD64.
> Wobei das Argument mit IA64 auch nicht ganz falsch ist :-)

Naja, mit IA-64 hat Intel mal versucht, seine alten x86-Zöpfe 
abzuschneiden und ist damit kläglich gescheitert. Zu ihrem Glück haben 
sie das erstmal nur auf dem Server-Markt probiert und nicht gleich 
überall, sonst wären sie wohl weg vom Fenster gewesen. Entsprechend 
vorsichtig sind sie heute mit der Schere.

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Programmierer schrieb:
>> Die Cortex M können kein ARM7 Programm ausführen.
>
> Doch, wenn es in Thumb geschrieben ist.

Die früher verbreiteten ARMTDMI Microcontroller haben zwar das T und 
damit Thumb. Startup und Exceptions sind aber völlig anders enthalten 
zwingend non-Thumb code. Cortex M Programme und ARM7TDMI Programme sind 
in diesem Bereich inkompatibel.

Nur bei Systemen mit klarer Trennung zwischen Betriebssystem und 
Anwendungsprogrammen ist Kompatibilität der Anwendungsprogramme denkbar.

>> Die ARM7 wiederum haben Probleme mit ARM2 Programmen.
>
> Ach, wieso?

Weil anfangs PC, Flags und Modus-Bits zusammen in R15 steckten und der 
Programmadressraum damit auf 64 MB begrenzt war. Flags und Modus-Bits 
wurden später zugunsten des Adressraums in ein vorher nicht 
existierendes PSR Register rausoperiert, was nicht ohne Folgen für die 
Programmierung blieb.

: Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.