Hallo, mich beschäftigt folgende Frage: Warum legt man in einem Assemblerprogramm die Programmanweisungen und Daten getrennt voneinander im Speicher ab? Dient dies nur zur Übersichtlichkeit? oder gibt es andere Gründe? MfG
„Man“ kann eigentlich grundsätzlich immer machen, was immer man will. Erst recht bei einem beliebigen Assembler auf einer beliebigen Plattform. Oliver
Erster Grund: Weil der Programmzähler (abgesehen von Sprüngen) fortlaufend erhöht wird. Wenn du zwischen den Anweisungen Daten hättest, müsstest du sie häufig überspringen, was für die Performance schlecht ist. Zweiter Grund: Viele Prozessoren können Befehle schneller abarbeiten, als der Programmspeicher lesbar ist. Deswegen kommt dazwischen ein Cache, der klein aber schnell ist. Wenn Daten und Programmcode gemischt wären, würde man im Cache kostbaren Platz durch Daten belegen, auf die man gar nicht so schnell zugreifen muss, wie auf Anweisungen Dritter Grund: Manche Prozessoren unterschieden zwischen Programmspeicher und Datenspeicher. Sie werden durch unterschiedliche physische Signal-Leitungen angesteuert. Teilweise gibt es sogar getrennte Busse, so dass der Prozessor Befehle und Daten gleichzeitig aus den beiden separaten Quellen laden kann. Und die von dir genannte Übersichtlichkeit ist auch ein guter Grund.
Pat ". schrieb: > Warum legt man in einem Assemblerprogramm die Programmanweisungen und > Daten getrennt voneinander im Speicher ab? Harvard versus von-Neumann, schon mal gehört?! https://www.bernd-leitenberger.de/harvard-neumann.shtml https://studyflix.de/informatik/von-neumann-vs-harvard-786
Syggie Synapse (Gast) >Und dann wäre noch diese Altlast: >https://en.wikipedia.org/wiki/X86_memory_segmentation Hat nix mit der ursprünglichen Frage zu tun. Auserdem ist das keine Altlast, sondern schlicht eine kompatible Erweiterung des ansonsten nur auf 16bit beschränkten Adressraums, welcher sonst nur 64kB zulassen würde.
Jens G. schrieb: > Syggie Synapse (Gast) > >>Und dann wäre noch diese Altlast: > >>https://en.wikipedia.org/wiki/X86_memory_segmentation > > Hat nix mit der ursprünglichen Frage zu tun. Doch, weil es erklärt warum es Datenbereiche und Codebereiche gibt: "Warum legt man in einem Assemblerprogramm die Programmanweisungen und Daten getrennt voneinander im Speicher ab" > Auserdem ist das keine Altlast, sondern schlicht eine kompatible > Erweiterung des ansonsten nur auf 16bit beschränkten Adressraums, > welcher sonst nur 64kB zulassen würde. Es ist doch alt, oder? Ob die Last nun nötig oder unnötig mag jeder selbst entscheiden. Oder mochte, heute wird sich wohl keiner mehr mit .com oder .exe, short oder far jumps herumschlagen. uUd segmente sind auch heute noch was nutze (PMU), nur steigt keiner mehr so tief in Hardware-eingeweide um das zu verstehen. https://en.wikipedia.org/wiki/Memory_management_unit
Syggie Synapse schrieb: > Doch, weil es erklärt warum es Datenbereiche und Codebereiche gibt: > "Warum legt man in einem Assemblerprogramm die Programmanweisungen und > Daten getrennt voneinander im Speicher ab" Komischerweise gab es die Harvard-Architektur aber schon 40 jahre vor dem ersten x86-Prozessor. Also scheint die Angelegenheit sich zumindest nicht vollständig auf das Design von x86 zurückzuführen lassen.
Ein weiterer Aspekt: Daten müssen - sofern es sich nicht nur um Konstanten handelt (aber dann wäre Assemblercode ziemlich langweilig) les- und schreibbar sein. Code dagegen (wenn's kein selbstmodifizierender ist und so was macht man nicht) kann schreibgeschützt abgelegt werden. Wer seinen Code also (vor sich selbst und anderen) vor versehentlicher (oder auch beabsichtigter) Veränderung schützen will, legt ihn in einen scheibgeschützten Bereich ab.
Felix U. schrieb: > Syggie Synapse schrieb: >> Doch, weil es erklärt warum es Datenbereiche und Codebereiche gibt: >> "Warum legt man in einem Assemblerprogramm die Programmanweisungen und >> Daten getrennt voneinander im Speicher ab" > > Komischerweise gab es die Harvard-Architektur aber schon 40 jahre vor > dem ersten x86-Prozessor. Also scheint die Angelegenheit sich zumindest > nicht vollständig auf das Design von x86 zurückzuführen lassen. Es ging mir ja auch auch mit x86 lediglich als Beispiel für Prozessoren mit segmentierten Speicherzugriffen und um Computerarchitekturen mit mehreren Prozessen und damit Mechanismen einzelner Speicherbereich unterschiedlich Zugriffschutz zu geben. Und auf von-Neumann hab ich im post-- referenziert, und der wurde ca. 20 Jahre vor x86 kompostiert. Das wäre auch noch eine weiter Sichtweise auf das Problem, die des Betriebssystem. Der Programmspeicher wird vom Systemuser verwaltet, während der Datenspeicher vom Usertask in Beschlag genommen wird.
Umgekehrt wird ein Schuh draus: Die Segmentierung von x86 im Protected Mode des 286 wiederspiegelt die vom TE beobachtete und schon vorher gemeinhin übliche Trennung von Code- und Datenbereichen. So ganz selbstverständlich ist das indes nicht. Bei ARM Prozessoren legt man oft read-only Daten mitten in den Code rein, weil sie da in geringer Distanz zum Program Counter leicht adressierbar sind und es bei RISC Architekturen auf diese Weise kürzer ist, als sie aus mehreren Immediate-Operanden zusammen zu setzen. Es hat allerdings auch schon eine Architektur gegeben, in der Befehle nicht sequentiell aufeinander folgten, sondern bei der jeder Befehl einen Sprung auf den nächsten Befehl enthielt (IBM 650). Einem kunterbunten durchmischten und an der Rotations-Latenz des Trommelspeichers der Maschine orientierten Code steht dann nichts im Weg.
Syggie Synapse schrieb: > Der Programmspeicher wird vom Systemuser verwaltet, > während der Datenspeicher vom Usertask in Beschlag genommen wird. Das musst du mir jetzt aber noch mal genauer erklären.
Markus F. schrieb: > Code dagegen (wenn's kein selbstmodifizierender ist und so was macht man > nicht) kann schreibgeschützt abgelegt werden. Wer seinen Code also (vor > sich selbst und anderen) vor versehentlicher (oder auch beabsichtigter) > Veränderung schützen will, legt ihn in einen scheibgeschützten Bereich > ab. Diese Wunsch nach Schreibschutz gilt aber auch für Daten, insbesonders bei Multi-User; Multi-task systemen. Dieser Zugriffschutz soll weohl auch ein Grund sein, warum man die (erzwungenen´) Speichersegmentierte nicht in späteren Prozessoren wegliess, sondern im Gegenteil, mit den MMU's sogar verfeinert beibehielt.
Syggie Synapse schrieb: > Diese Wunsch nach Schreibschutz gilt aber auch für Daten, insbesonders > bei Multi-User; Multi-task systemen. Das sind technisch und auch sinngemäß zwei paar Schuhe.
Syggie Synapse schrieb: > Doch, weil es erklärt warum es Datenbereiche und Codebereiche gibt: > "Warum legt man in einem Assemblerprogramm die Programmanweisungen und > Daten getrennt voneinander im Speicher ab" Ja, aber da ist eine Trennung Code/Daten im Speicher absolut nicht sichergestellt, denn die können sich beliebig überlappen (je nach Wert im Code-/Datensegmentregister). Also ja, hat was damit zu tun. Aber man ist als Programmierer selbst verantwortlich, daß sich Code/Daten (und auch Stack) nicht gegenseitig zerfleischen.
Felix U. schrieb: > Syggie Synapse schrieb: >> Der Programmspeicher wird vom Systemuser verwaltet, >> während der Datenspeicher vom Usertask in Beschlag genommen wird. > > Das musst du mir jetzt aber noch mal genauer erklären. Also ich betrachte da ein Multiuser/-task system. Kein Task soll in den Speicherbereich eines anderen ungenehmigt schreiben /oder auch lesen können (Shared Memory und Datentransfer zw. Task jetz mal unberücksichtigt. Das erreicht man in dem man jeden Task. spezifische Speichersegmente zuweist. Die Physikalische Umsetzung zwischen den zugewiesenen Speicher und dem realen RAM-Riegel macht die MMU (Memory managment unit). Greift ein Task auf einen nichtgenehmigten Bereich zu, gibt es einen Fehler, gern auch als Segmentation fault beschrieben. Jetzt stellt sich allerdings das problem des Task-loaders, der in den gesamten Speicher schreiben muss um den Programmcodes des task für den start desselben in den RAM zu bringen. Für den darf kein segmentation fault ausgelöst werden. Das erreicht man, indem dieser Loader besondere Privilegien besitzt. Diese besonderen Privilegien hab ich hemdsärmelig als 'systemuser' bezeichnet. Soweit in aller Kürze die Zusammenhänge zwischen MMU und task priority levels. Einen link hab ich auf die schnelle nicht gefunden, wohl weil diese Low level interna die wenigstens Programmierer tangiert. Lehrbücher zur Computerarchitektur sind da ausführlicher, bspw: ISDN: 978-3110446050 In der WP wird unter 'protection ring' auf das Thema task privilegien eingegangen: https://en.wikipedia.org/wiki/Protection_ring
Syggie Synapse schrieb: > Also ich betrachte da ein Multiuser/-task system. Da würfelst du aber ein paar Dinge durcheinander, oder? Die Separation zwischen Prozessen entsteht dadurch, dass jeder Prozess seinen eigenen virtuellen Speicherbereich hat. Segmentation fault hat daher nichts damit zu tun, dass man in den Speicherbereich eines anderen Prozesses schreiben wollte, sondern einfach in nicht gemappten / nicht schreibbaren Speicher. Für den Speicherbereich von anderen Prozessen gibt es ja überhaupt keine Pointer. Der Loader läuft übrigens zB. unter Linux im Kontext des Prozesses, dessen Image er lädt, im Bezug auf andere Prozesse hat er deshalb gar keine besonderen Privilegien. Den Loader kann man btw im Usermode ausführen.
Jens G. schrieb: > Syggie Synapse schrieb: > Ja, aber da ist eine Trennung Code/Daten im Speicher absolut nicht > sichergestellt, denn die können sich beliebig überlappen (je nach Wert > im Code-/Datensegmentregister). > Also ja, hat was damit zu tun. Aber man ist als Programmierer selbst > verantwortlich, daß sich Code/Daten (und auch Stack) nicht gegenseitig > zerfleischen. Und genau das das Programmierer nicht selbst machen muss, hat man die MMU erfunden. Dann kann nur das Betriebssysten resp. ein task in einem hohen prioritylevel die Speicherzuteilung ändern und der normale Usertask (niedriger prio-level) hat da keine reguläre Chance in fremde Bereichen rumzuschnüffeln. MMU-Befehle (Befehle die regs der MMU ändern) sind dann priviligierte Befehle. Allerdings ist das innerhalb der x86 Familie nicht einheitlich gelöst (erst ab 386 könnte man von MMU sprechen), so dass sich immer ein Beispiel finden lässt, wo dann doch der Programmierer alles kaputtschreiben kann (und auch hat).
Felix U. schrieb: > Syggie Synapse schrieb: >> Also ich betrachte da ein Multiuser/-task system. > > Da würfelst du aber ein paar Dinge durcheinander, oder? Die Separation > zwischen Prozessen entsteht dadurch, dass jeder Prozess seinen eigenen > virtuellen Speicherbereich hat. Segmentation fault hat daher nichts > damit zu tun, dass man in den Speicherbereich eines anderen Prozesses > schreiben wollte, sondern einfach in nicht gemappten / nicht > schreibbaren Speicher. Das stimmt wenn man lediglich eine horizontale Seperation (Speicherbereiche von task gleichen priority levels) betrachtet. Und ob es jetz segmentation oder 'andere Fault' heisst ist eigentlich egal, die Frage ist ob wirklich nur bei nicht einen nicht im System gemappten Speicher ein Fehler ausgelöst, oder auch ein (mglw. anders bezeichneter) Fehler bei einem für einen anderen Prozess) gemappten. > Für den Speicherbereich von anderen Prozessen > gibt es ja überhaupt keine Pointer. Hm auch in Assembler nicht? (siehe threadthema) also 'harte' adressen verwenden, keine OS-calls wie malloc und Co. > Der Loader läuft übrigens zB. unter > Linux im Kontext des Prozesses, dessen Image er lädt, im Bezug auf > andere Prozesse hat er deshalb gar keine besonderen Privilegien. Den > Loader kann man btw im Usermode ausführen. Ja das kann sein, die linux-begrifflichkeit ist mit nicht so vertraut, kann sein das hier auch die Begriffe taskmanager und loader vertauscht wird. Und ich weiss, das es vor Jahren (1995?) auch mal Linux-derivate für Systeme ohne MMU und priviligierte task gab, also vor 386. Da ist aber auch klar das es da keinen (schnellen) speicherschutz geben kann. https://www.linux-magazin.de/ausgaben/2001/03/klein-aber-linux/
In jedem Fall hat das Diskussionsthema "MMU, Multitasking, Task Loader und Segmentation Faults" nur wenig mit der ursprünglichen Frage zu tun. Man trennt Code und Daten im Speicher: - wegen der Übersicht; - weil manche Prozessoren nur schlecht aus dem Codespeicher lesen können; - weil Code und Daten getrennte Caches haben können; - um getrennte Berechtigungen für Code und Daten haben zu können. Daraus folgt aber meistens nicht, dass man es trennen muss.
Syggie Synapse schrieb: > Hm auch in Assembler nicht? (siehe threadthema) also 'harte' adressen > verwenden, keine OS-calls wie malloc und Co. Auch in Assembler nicht. Wir reden ja von Systemen mit virtueller Speicherverwaltung. Ob Assembler oder was auch immer ist nicht wichtig für die Adressierung.
Syggie Synapse schrieb: > erst ab 386 könnte man von MMU sprechen Ab 286. Dessen Segmentierung darf im Protected Mode sehr wohl als echte MMU gelten. Nur nicht von der Art, wie es damals auf Computern wie z.B. der VAX üblich war, und sie erwies sich als Sackgasse.
Pat ". schrieb: > Warum legt man in einem Assemblerprogramm die Programmanweisungen und > Daten getrennt voneinander im Speicher ab? In Assembler gibt es keinerlei Vorschriften, man kann es machen, wie man lustig ist. Ich hab z.B. beim 8051 oder AVR konstante Daten direkt hinter dem Call der Ausgabefunktion im Flash plaziert. Daß man aber Variablen immer im RAM plazieren muß, versteht sich von selbst.
Peter D. schrieb: > In Assembler gibt es keinerlei Vorschriften, man kann es machen, wie man > lustig ist. So sieht's aus. Es gibt aber natürlich schon sinnvolle Verfahrensweisen, und teilweise werden diese sogar durch die Zielarchitektur selber erzwungen. Nehmen wir z.B. nur die Sachen mit den immediate-Daten beim ARM, bzw. dem, was der Sache noch am nächsten kommt... > Daß man aber Variablen immer im RAM plazieren muß, versteht sich von > selbst. Hoffentlich. Beim TO habe ich da meine Zweifel...
Der TO hat bisher hier im Forum genau einen Beitrag geschrieben. Der interessiert sich nicht für die Antwort auf seine Frage, sondern genießt sein Popcorn.
Carl D. schrieb: > Der TO hat bisher hier im Forum genau einen Beitrag geschrieben. > Der interessiert sich nicht für die Antwort auf seine Frage, sondern > genießt sein Popcorn. Ja, das würde ich auch so sehen. Ist ein Stricher AKA Traffic-Troll. Interessant ist, dass meine KI nur 80% Wahrscheinlichkeit ausspuckt. Sprich: der Troll ist echt gut, weit über Durchschnitt...
c-hater schrieb: > der Troll ist echt gut, weit über Durchschnitt... Blödsinn...er ist halt ein troll... Gruß Rainer PS, ich erinnere an den Menschen hier im Forum, der den Widerstand eines Lackisolierten Drahts nicht messen konnte, weil der ja isoliert sei! Also ehrlich...gehts noch?
Pat ". schrieb: > Warum legt man in einem Assemblerprogramm die Programmanweisungen und > Daten getrennt voneinander im Speicher ab? Man tut das nicht. Außer manchmal, wenn es Gründe gibt. Und dann eben wegen jener Gründe. Die Frage ist sinnlos.
> Ich hab z.B. beim 8051 oder AVR konstante Daten direkt > hinter dem Call der Ausgabefunktion im Flash plaziert. Bei historischen CPUs war das ueblich. Die konnten nur innerhalb der Page, aus der der Befehl gelesen wurde, besonders schnell auf weitere Daten zugreifen. Und diese Daten waren keine Konstanten. Ziemlich gruselig, gell?
Oke, danke. Durch die zahlreichen Antworten und Anregungen ist mir das nun klar. Ps: Ich trolle nicht, mir war das halt nicht genau klar, weshalb man dies macht, weil es ja auch ohne funktioniert.
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.