Forum: Mikrocontroller und Digitale Elektronik Assemblerprogram (allgemeine Frage)


von Jantscher (technikp)


Lesenswert?

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

von Oliver S. (oliverso)


Lesenswert?

„Man“ kann eigentlich grundsätzlich immer machen, was immer man will. 
Erst recht bei einem beliebigen Assembler auf einer beliebigen 
Plattform.

Oliver

von Stefan F. (Gast)


Lesenswert?

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.

von Syggie Synapse (Gast)


Lesenswert?

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

von Syggie Synapse (Gast)


Lesenswert?

Und dann wäre noch diese Altlast:

https://en.wikipedia.org/wiki/X86_memory_segmentation

von A. S. (Gast)


Lesenswert?

Programmspeicher kann ROM sein, Variablen müssen RAM sein.

von Jens G. (jensig)


Lesenswert?

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.

von Syggie Synapse (Gast)


Lesenswert?

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

von Felix U. (ubfx)


Lesenswert?

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.

von Markus F. (mfro)


Lesenswert?

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.

von Syggie Synapse (Gast)


Lesenswert?

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.

von (prx) A. K. (prx)


Lesenswert?

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.

von Felix U. (ubfx)


Lesenswert?

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.

von Syggie Synapse (Gast)


Lesenswert?

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.

von Felix U. (ubfx)


Lesenswert?

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.

von Jens G. (jensig)


Lesenswert?

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.

von Syggie Synapse (Gast)


Lesenswert?

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

von Felix U. (ubfx)


Lesenswert?

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.

von Syggie Synapse (Gast)


Lesenswert?

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).

von Syggie Synapse (Gast)


Lesenswert?

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/

von S. R. (svenska)


Lesenswert?

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.

von Felix U. (ubfx)


Lesenswert?

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.

von (prx) A. K. (prx)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

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.

von c-hater (Gast)


Lesenswert?

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...

von Carl D. (jcw2)


Lesenswert?

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.

von c-hater (Gast)


Lesenswert?

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...

von Rainer V. (a_zip)


Lesenswert?

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?

von Axel S. (a-za-z0-9)


Lesenswert?

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.

von Klugscheisser (Gast)


Lesenswert?

> 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?

von Jantscher (technikp)


Lesenswert?

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
Noch kein Account? Hier anmelden.