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
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
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?
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
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.
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.
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.
Das kann auch sein, weiß nicht wie elementar der Prozessor die Instruktionen zerlegt.
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.
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.
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
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.
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.
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.
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...
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
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.
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.
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.
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
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.
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
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.
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
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.
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?
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.
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.
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.
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
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!
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?
Du kannst dieses Format auch für den ersten Befehl verwenden, musst es aber nicht.
:
Bearbeitet durch User
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.
Immerhin hat er hier doch schon einen eigenen Thread für eine neue Frage recycelt, statt einen neuen aufzumachen.
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.
https://de.wikipedia.org/wiki/Maschinensprache https://de.wikipedia.org/wiki/Assemblersprache https://de.wikipedia.org/wiki/Assembler_%28Informatik%29
Aber ist jetzt das Format Präfix|Opcode|ModR/M|SIB|Displacement|Immediate auf Maschinencode bezogen oder auf Assemblercode?
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.
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
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?
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.
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?
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.
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
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.
Eure Antworten haben mir wirklich viel gebracht! Großes Danke!
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.
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
georg schrieb: > Ist meine Meinung, wahrscheinlich halten sich längst nicht alle > Entwickler daran. Meine Einschätzung: heutzutage niemand.
:
Bearbeitet durch User
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.
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.
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
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
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.
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...
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
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...
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.
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 :-)
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.