Forum: Mikrocontroller und Digitale Elektronik AVR: Zugriff auf ungültige Speicherbereiche


von memset (Gast)


Lesenswert?

Mir ist vorhin beim Arbeiten mit Pointern ein typischer Off-by-One 
Fehler unterlaufen. Dabei kam mir die Frage auf was ein Zugriff auf 
ungültige Adressen bei AVRs bzw. ATmegas denn für Konsequenzen hat. 
Konkret geht es um einen ATmega328P, wobei das vermutlich (?) für die 
ganze Serie gleich sein dürfte und letztendlich ist das natürlich eine 
reine Interessensfrage.

Weder im Datenblatt noch im Instruction Set konnte ich diesbezüglich 
Informationen finden, nicht einmal ein Hinweis auf das ansonsten 
beliebte "undefinierte" Verhalten. Bei meiner etwas komplexeren 
Mikrocontroller-Anwendung war die Konsequenz, dass der Mikrocontroller 
gar nicht mehr ansprechbar war. Leider steht mir derzeit auch kein 
Debugger oder ähnliches zur Verfügung.

In meinem Fall ging es um das Beschreiben des Speichers mit einem 
bestimmten Bitmuster - beginnend beim Start des Heaps (__heap_start) bis 
zum Ende des RAMs (RAMEND). Dafür wollte ich memset verwenden, und habe 
dies zunächst so gelöst:
1
memset(&__heap_start, 0xaa, RAMEND - (uint16_t)&__heap_start);

Das hat, wie gesagt, zum Stillstand des Programms geführt. Mit einem "- 
1" hingegen funktioniert es problemlos:
1
memset(&__heap_start, 0xaa, RAMEND - (uint16_t)&__heap_start - 1);

Im Assembler-Listing von memset sieht man, dass das Ganze auf die 
Instruktion "st" zurückfällt:
1
00003e74 <memset>:
2
    3e74:  dc 01         movw  r26, r24
3
    3e76:  01 c0         rjmp  .+2        ; 0x3e7a <memset+0x6>
4
    3e78:  6d 93         st  X+, r22
5
    3e7a:  41 50         subi  r20, 0x01  ; 1
6
    3e7c:  50 40         sbci  r21, 0x00  ; 0
7
    3e7e:  e0 f7         brcc  .-8        ; 0x3e78 <memset+0x4>
8
    3e80:  08 95         ret

Leider konnte ich keine Informationen zu st erlangen, die mir verraten 
was bei einer ungültigen Adressierung passiert. Kann jemand das Rätsel 
mit Verweisen auf entsprechende Dokumente lösen ;)? Gibt es zumindest 
Erfahrungswerte? Führt das immer zum Absturz/Neustart?

Ich sitze mittlerweile wahrscheinlich schon zu lange vor der Röhre, und 
auch auf die Gefahr hin mich hier extremst lächerlich zu machen, aber so 
ganz nachvollziehen kann ich die o.g. "-1" nämlich nicht nachvollziehen. 
Die war eher per Trial & Error (;)) bestimmt worden und selbst beim 
Aufmalen auf Papier bin ich der Meinung, dass das eigentlich nicht 
notwendig wäre.

Ein kleines Beispiel:
1
+---+---+---+---+---+---+---+---+---+
2
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
3
+---+---+---+---+---+---+---+---+---+
4
          ^                       ^
5
    __heap_start                RAMEND
6
         0x2                     0x8

Der Bereich zwischen __heap_start und RAMEND ist ja genau 7 Byte groß 
(2, 3, 4, 5, 6, 7, 8). RAMEND - __heap_start = 8 - 2 = 6, d.h. ich 
müsste sogar noch 1 dazu addieren, um aus den beiden Variablen die Größe 
des Bereichs zu berechnen. Ich bin mir ziemlich sicher, dass das Problem 
vor dem Monitor sitzt, aber könnte mir da bitte jemand auf die Sprünge 
helfen, warum memset nur mit o.g. Argument funktionieren mag?

Danke!

von holger (Gast)


Lesenswert?

>Das hat, wie gesagt, zum Stillstand des Programms geführt.

Kein Wunder wenn du dir den Stack platt machst.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

memset schrieb:
> 3e80:  08 95         ret

 Und die Adresse wo du zurückspringen sollst, hast du schön
 überschrieben.

von memset (Gast)


Lesenswert?

holger schrieb:
> Kein Wunder wenn du dir den Stack platt machst.

Ja, das erklärt mein o.g. Problem tatsächlich. Habe gar nicht mehr an 
den Stack gedacht bzw. dass dieser verwendet wird, obwohl die 
entsprechende Funktion in in der "init3" Sektion steht. Aber klar, ein 
Blick ins Listing hat verraten, dass memset per "call" angesprungen 
wird. Danke für diesen wertvollen Tipp.

Aktuell sieht es nun so aus:
1
memset(&__heap_start, 0xaa, (SP - (uint16_t)&__heap_start) - 1);

Das funktioniert zwar, aber basiert nun auf der Annahme, dass es nur die 
eine "call" Instruktion gibt, welche den Stack modifiziert. Wenn jetzt 
memcpy einen eigenen Stack-Frame anlegen würde, dann stehe ich vor dem 
selben Problem.

Gibt es hierfür eine Lösung in C? Oder ist die Verwendung von Inline 
Assembler hier tatsächlich sinnvoller, um sich solche Probleme zu 
ersparen?

von Programmierer (Gast)


Lesenswert?

memset schrieb:
> Gibt es hierfür eine Lösung in C?

Wofür? Warum willst den den Speicher auf 0 setzen?? Warum initialisiert 
du nicht, wie es sich gehört, alle globalen und statischen Variablen auf 
0 (bzw. initialisiert sie gar nicht, dann ist 0 der Default) und hast 
somit alles auf 0?

von memset (Gast)


Lesenswert?

Programmierer schrieb:
> Wofür? Warum willst den den Speicher auf 0 setzen??

Ich setzte hier nichts auf 0. Ich schreibe ein bestimmtes Bit-Muster 
hinein. Das dient dem Abschätzen der Stäckgröße während der Laufzeit. So 
wird das auch hier beschrieben 
(http://rn-wissen.de/wiki/index.php/Speicherverbrauch_bestimmen_mit_avr-gcc). 
Ich wollte nur auf den Inline Assembler verzichten und memset() 
verwenden.

von Programmierer (Gast)


Lesenswert?

Äh initialisieren mit 0xAA wäre das bei dir, nicht 0

von Amateur (Gast)


Lesenswert?

Der Zugriff, zu mindest bei Prozessoren wie dem ATMega, hat soweit mir 
bekannt keine Nebeneffekte.

Natürlich wird, beim Überschreiten des erlaubten Bereiches, Blödsinn 
gelesen. Das Schreiben ins Nirwana hat keine mir bekannten Folgen.

... aber beim Schreiben in vorhandene Bereiche wird es richtig 
interessant.

Das Schreiben in vorhandene, interne Register bewirkt genau dass, was 
der Hersteller auch in seinen Datenblättern beschreibt.
Schreiben im RAM hat auch nur die schon vielfach beschriebenen Folgen 
wie: Variablen und Zähler durcheinander bringen.
Den Stack zu überschreiben hat wohl ähnliche Folgen, wie wenn Du Dir den 
Stuhl unter dem Hintern wegziehen lässt.

Das Lesen der jeweiligen Speicherstellen gibt deren aktuellen Zustand 
zurück. Teilweise auch Blödsinn, wenn das Lesen nicht vorgesehen ist.

Alles in allem würde ich sagen: Genau das was zu erwarten ist.

von Peter D. (peda)


Lesenswert?

memset schrieb:
> aber basiert nun auf der Annahme, dass es nur die
> eine "call" Instruktion gibt, welche den Stack modifiziert.

Du weißt aber schon, daß man das SP Register auch auslesen darf.
Im Stack ist nicht nur die Returnadresse, sondern auch lokale Variablen.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Peter Dannegger schrieb:
> Im Stack ist nicht nur die Returnadresse, sondern auch lokale Variablen.

 Dafür sollte es aber einen Variablenstack geben, oder ?

von Sabro (Gast)


Lesenswert?

Fuer Fragen zur AVR Code ausfuehrung wuerde ich den Im AVR Studio 
enthaltenen Simulator empfehlen.

von Leo C. (rapid)


Lesenswert?

Niemand zwingt Dich dazu, memset(), oder sonst irgendeine Funktion zu 
benutzen.
1
__attribute__ ((naked)) __attribute__ ((section (".init3")))
2
void preset_ram (void)
3
{
4
  for (uint8_t *p = RAMSTART; p <= (uint8_t *) RAMEND; p++)
5
    *p = 0xdd;
6
7
}
funktioniert bei mir.

: Bearbeitet durch User
von Kaj (Gast)


Lesenswert?

Marc Vesely schrieb:
> Peter Dannegger schrieb:
>> Im Stack ist nicht nur die Returnadresse, sondern auch lokale Variablen.
>
>  Dafür sollte es aber einen Variablenstack geben, oder ?

Auf einem mC wie z.B. einem AVR gibt es nur einen Stack, Punkt.
So etwas wie stack fuer variablen, stack fuer returnadressen usw gibt es 
nicht: ein Stack, punkt um!

von Amateur (Gast)


Lesenswert?

@memset
In - was auch immer ein richtiges "C" ist - ist es zwar unerwünscht den 
Stack zu beschreiben, aber erlaubt.
Zu Mindest früher wurden lokale Variablen auf dem Stack abgelegt. In 
normalem "C" gibt es keine Sperre, die Dir verbietet, die mit "char 
Etwas [ 2 ];" angelegte lokale Variable an der Stelle Etwas [ 2 ] zu 
befummeln. Sowohl im erlaubten Bereich (0..1), als auch darüber hinaus, 
ist das ein Stackzugriff.

Wie auch Peter bereits gesagt hat:
Bei manchen Mikroprozessoren sind sogar der Stack-Pointer und manchmal 
der Programm-Counter ein normales Register.

von Peter D. (peda)


Lesenswert?

Marc Vesely schrieb:
> Dafür sollte es aber einen Variablenstack geben, oder ?

Das kann jeder Compilerbauer so halten, wie er lustig ist.
AVR-GCC hat keinen, IAR hat einen.

von memset (Gast)


Lesenswert?

Peter Dannegger schrieb:
> Du weißt aber schon, daß man das SP Register auch auslesen darf.

Ja, das tue ich doch mit o.g. Code schon.

Peter Dannegger schrieb:
> Im Stack ist nicht nur die Returnadresse, sondern auch lokale Variablen.

Eben, und daher ist jeder Funktionsaufruf in diesem Kontext 
problematisch, weil ich die Größe der involvierten Stack-Frames nicht 
kenne und diese ggf. überschreibe.

Marc Vesely schrieb:
> Dafür sollte es aber einen Variablenstack geben, oder ?

Nein, nicht bei den AVRs bzw. AVR GCC.

Sabro schrieb:
> Fuer Fragen zur AVR Code ausfuehrung wuerde ich den Im AVR Studio
> enthaltenen Simulator empfehlen.

Das Studio gibt es für meine Plattform (Linux) nicht.

Leo C. schrieb:
> Niemand zwingt Dich dazu, memset(), oder sonst irgendeine Funktion zu
> benutzen.

Ok, das ist eine Lösung. Danke.

Amateur schrieb:
> Wie auch Peter bereits gesagt hat:
> Bei manchen Mikroprozessoren sind sogar der Stack-Pointer und manchmal
> der Programm-Counter ein normales Register.

Ja, und inwiefern bringt mich das weiter? Scheinbar übersehe ich hier 
etwas ...

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Peter Dannegger schrieb:
> Das kann jeder Compilerbauer so halten, wie er lustig ist.
> AVR-GCC hat keinen, IAR hat einen.

 Ich kenne mich beim C nicht so genau aus, deswegen meine Frage. Ein
 Variablenstack scheint mir aber viel besser und vor allem sicherer
 zu sein...

Kaj schrieb:
> So etwas wie stack fuer variablen, stack fuer returnadressen usw gibt es
> nicht: ein Stack, punkt um!

 Warum schreist du den ?
 Ein bißchen rumlesen um sich über Compiler und die Art wie die
 funktionieren zu informieren, wäre auch nicht schlecht...
 Was glaubst du wozu Index Register gut sind ?

: Bearbeitet durch User
von matrixstorm (Gast)


Lesenswert?

Hallo.
Ich habe auch noch eine schoenere Version - Bei Bedarf einfach melden:
matrixstorm@gmx.de
1
/*
2
 * Under normal circumstances, RESET will not clear contents of RAM.
3
 * As always, if you want it done - do it yourself...
4
 */
5
void __attribute__ ((naked))  __attribute__ ((section (".init3"))) __clearram(void);
6
void __clearram(void) {
7
  extern __bss_end;
8
  asm volatile (
9
    "ldi r29, %[ramendhi]\n\t"
10
    "ldi r28, %[ramendlo]\n\t"
11
    "__clearramloop%=:\n\t"
12
    "st -Y , __zero_reg__\n\t"
13
    "cp  r28, %A[bssend]\n\t"
14
    "cpc r29, %B[bssend]\n\t"
15
    "brne __clearramloop%=\n\t"
16
    :
17
    : [ramendhi] "M" (((RAMEND+1)>>8) & 0xff),
18
      [ramendlo] "M" (((RAMEND+1)>>0) & 0xff),
19
      [bssend]   "r" (&__bss_end)
20
    : "memory"
21
      );
22
}

von memset (Gast)


Lesenswert?

Marc Vesely schrieb:
> Ein
>  Variablenstack scheint mir aber viel besser und vor allem sicherer
>  zu sein...

Was soll daran besser sein? Man ist nur unnötig damit beschäftigt beide 
"synchron" zu halten. Inwiefern das sicherer sein soll erschließt sich 
mir auch nicht. Sobald ein Stack "kaputt" ist, kann man mit den Daten 
des anderen kaum mehr etwas anfangen, zumindest nicht im normalen 
Programmablauf.

Und zu Bufferüberläufe durch Böslinge kann es es in beiden Fällen 
kommen. Oder glaubst du ernsthaft, dass die ganze Computerindustrie 
nicht schon lange auf dieses Modell umgestiegen wäre, wenn dem nicht so 
ist?

matrixstorm schrieb:
> Ich habe auch noch eine schoenere Version

Auch Assembler ;).

matrixstorm schrieb:
> Bei Bedarf einfach melden:
> matrixstorm@gmx.de

Warum stellst du es nicht einfach direkt rein?

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

memset schrieb:
> Was soll daran besser sein? Man ist nur unnötig damit beschäftigt beide
> "synchron" zu halten. Inwiefern das sicherer sein soll erschließt sich
> mir auch nicht. Sobald ein Stack "kaputt" ist, kann man mit den Daten

 Das stimmt schon mal nicht, ist eher umgekehrt.

memset schrieb:
> Und zu Bufferüberläufe durch Böslinge kann es es in beiden Fällen
> kommen. Oder glaubst du ernsthaft, dass die ganze Computerindustrie
> nicht schon lange auf dieses Modell umgestiegen wäre, wenn dem nicht so
> ist?

 Variablenstack ist schon lange in Gebrauch, sogar mit Runtime checking.
 Und es ging nicht um Computerindustrie, sondern um Compiler.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

memset schrieb:
> In meinem Fall ging es um das Beschreiben des Speichers mit einem
> bestimmten Bitmuster

Wie's richtig geht steht da:

http://rn-wissen.de/wiki/index.php/Speicherverbrauch_bestimmen_mit_avr-gcc#Dynamischer_RAM-Verbrauch

Portabel auf andere Architekturen ist das eh nicht, selbst wenn du es in 
C hinschreibst.

von Sabro (Gast)


Lesenswert?

>> Sabro schrieb:
>> Fuer Fragen zur AVR Code ausfuehrung wuerde ich den Im AVR Studio
>> enthaltenen Simulator empfehlen.

>Das Studio gibt es für meine Plattform (Linux) nicht.

Man kann sich das Leben vorsaetzlich schwer machen...

von Fütterer (Gast)


Lesenswert?

>Man kann sich das Leben vorsaetzlich schwer machen...

Man kann nutzlose Kommentare verfassen

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


Lesenswert?

Marc Vesely schrieb:
> Ich kenne mich beim C nicht so genau aus, deswegen meine Frage. Ein
> Variablenstack scheint mir aber viel besser und vor allem sicherer
> zu sein...

Kannst du mal erläutern, was da "viel besser" und "sicherer" sein soll?

Ich sehe nur Nachteile:

- man blockiert sich ein weiteres Indexregister als Stackpointer
- die beiden Stacks können jetzt asynchron werden
- man hat jetzt zwei Speicherbereiche (zusammen mit dem Heap: drei) 
deren Wachstum nicht vorhersagbar ist

Speziell für µC mit dem notorisch knappen RAM ist der dritte Punkt 
wahrscheinlich der wichtigste. Während man Heap und Stack von entgegen- 
gesetzten Enden des RAMs aufeinander zu wachsen lassen kann ohne dabei 
an Flexibilität einzubüßen (es knallt wirklich erst dann, wenn das 
Programm mehr Speicher braucht als da ist), stellt sich die Frage wo man 
denn bitte den Variablenstack hinlegen soll.

Legt man ihn zu nahe an den Stack, riskiert man einen Stacküberlauf 
obwohl noch RAM zwischen Heap und Variablenstack frei wäre. Dito wenn 
man ihn zu nah an den Heap legt. Die optimiale Position ist u.U. gar 
nicht festlegbar, weil sie von den verarbeiteten Daten abhängen kann 
(Stichwort Rekursion).


XL

: Bearbeitet durch User
von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Axel Schwenke schrieb:
> - man blockiert sich ein weiteres Indexregister als Stackpointer
 Aha. Und was glaubst du, wie werden die übergebenen Argumente sonst
 von der aufgerufenen Routine geholt ?

> - die beiden Stacks können jetzt asynchron werden
 Soll heissen ?

> - man hat jetzt zwei Speicherbereiche (zusammen mit dem Heap: drei)
> deren Wachstum nicht vorhersagbar ist
> Speziell für µC mit dem notorisch knappen RAM ist der dritte Punkt
> wahrscheinlich der wichtigste.

 Und deshalb hat man weniger RAM ?
 Ein richtiges Heap und uC gehen schon mal nicht zusammen.
 Heapverwaltung ist Codefressend, langsam und bei uC ungefähr so
 nützlich wie die Objektprogrammierung.
 Bei uC ist Heap praktisch nichts anderes als Variablenstack. Nur
 Morons arbeiten bei uC mit malloc und soviel ich weiss, arbeitet
 alloca wiederum nur mit Stack.
 Aber wie ich das auch sehe und begründe ist ja unwichtig, ich arbeite
 nicht mit C, es riecht schon nach Streit, also ja, du hast Recht.

von Gaestchen (Gast)


Lesenswert?

Axel Schwenke schrieb:
> Kannst du mal erläutern, was da "viel besser" und "sicherer" sein soll?

Bei der klassischen Methode,  weist du genau wo die Rücksprungadresse 
liegt, du kannst also gezielt dort eine falsche Rücksprungadresse 
eintragen und gezielt springen. Also ein mögliches Angriffsszenario. Bei 
einem getrennten Rücksprungstack, ist es ggf schwieriger herauszufinden 
wo er ist.
 Beim Atmega spielt das aber keinerlei Rolle, da dort kein fremder Code 
ausgeführt werden kann, Harvard usw und die Gründe die Du schon genannt 
hast.

Marc Vesely schrieb:
> Aha. Und was glaubst du, wie werden die übergebenen Argumente sonst
>  von der aufgerufenen Routine geholt ?

 Zu mindestens nicht von dem zusätzlichen Speicherbereich, der dazu 
benötigt wird den zusätlichen Stack zu verwalten.
 Es geht hier darum einen getrennten Stack für Variablen und 
Rücksprungadressen zu führen, also 2 Stack statt einen. Der Heap kommt 
da noch zusätzlich.

von Rolf M. (rmagnus)


Lesenswert?

Amateur schrieb:
> @memset
> In - was auch immer ein richtiges "C" ist - ist es zwar unerwünscht den
> Stack zu beschreiben, aber erlaubt.

Auf C-Ebene gibt es gar keinen Stack. Der ist nur ein Konzept der 
darunterliegenden Implementation.

> Zu Mindest früher wurden lokale Variablen auf dem Stack abgelegt.

Oder in Registern.

> In normalem "C" gibt es keine Sperre, die Dir verbietet, die mit "char
> Etwas [ 2 ];" angelegte lokale Variable an der Stelle Etwas [ 2 ] zu
> befummeln.

C verbietet eine solche Sperre nicht. Tastsächlich erlaubt es jedes 
beliebige Verhalten.
Und es gibt Compiler, bei denen man so einen Array-Bounds-Check 
aktivieren kann - mit entsprechenden Performance-Einbußen, weil 
natürlich bei jedem Zugriff dieser Check erfolgen muß.

> Sowohl im erlaubten Bereich (0..1), als auch darüber hinaus,
> ist das ein Stackzugriff.

Es sei denn, die Variable liegt gar nicht im Stack, sondern nur in 
Registern.

> Wie auch Peter bereits gesagt hat:
> Bei manchen Mikroprozessoren sind sogar der Stack-Pointer und manchmal
> der Programm-Counter ein normales Register.

Bei ARM ist das zum Beispiel so. Bei manchen ARM-Prozessoren kann man 
einen Sprung durch einfaches Schreiben der Zieladresse nach r15 
auslösen.

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


Lesenswert?

Marc Vesely schrieb:
> Axel Schwenke schrieb:
>> - man blockiert sich ein weiteres Indexregister als Stackpointer
>  Aha. Und was glaubst du, wie werden die übergebenen Argumente sonst
>  von der aufgerufenen Routine geholt ?

Über den Stackpointer?

Und was ist eigentlich unklar an
>> ein weiteres Indexregister
?

>> - die beiden Stacks können jetzt asynchron werden
>  Soll heissen ?

Bist du so dämlich oder stellst du dich nur so? Wenn da nur ein Stack 
ist, dann ist da auch nur ein Stackpointer. Returnadressen und Variablen 
(stack frames) liegen verschachtelt auf dem Stack und der Zusammenhang 
zwischen beiden ergibt sich direkt aus dem Inhalt des Stacks.

Wenn es zwei Stacks sind - einer für Variablen und einer für Return- 
adressen - dann sind da auch zwei Stackpointer. Und die müssen synchron 
modifiziert werden. Wenn nicht, würden merkwürdige Dinge geschehen, wie 
z.B. daß lokale Variablen auf einmal ganz andere Werte haben.

Mit nur einem Stack kann dieses Problem gar nicht auftreten. Und das 
ist ein handfester Vorteil.

>> - man hat jetzt zwei Speicherbereiche (zusammen mit dem Heap: drei)
>> deren Wachstum nicht vorhersagbar ist
>> Speziell für µC mit dem notorisch knappen RAM ist der dritte Punkt
>> wahrscheinlich der wichtigste.
>
>  Und deshalb hat man weniger RAM ?

Habe ich das geschrieben? Hast du überhaupt ansatzweise verstanden, was 
ich geschrieben habe?

>  Ein richtiges Heap und uC gehen schon mal nicht zusammen.

Nun ist es raus. Du hast keine Ahnung.

>  Aber wie ich das auch sehe und begründe ist ja unwichtig

Du hast es nach wie vor nicht begründet.

> ich arbeite nicht mit C, es riecht schon nach Streit

Das rieche ich. Du brichst vollkommen unbegründet einen Streit vom Zaun 
indem du über Sachen redest du du weder verstehst noch verwendest. Du 
bist ein Arschloch. EOD


(ohne Gruß)

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


Lesenswert?

Gaestchen schrieb:
> Axel Schwenke schrieb:
>> Kannst du mal erläutern, was da "viel besser" und "sicherer" sein soll?
>
> Bei der klassischen Methode,  weist du genau wo die Rücksprungadresse
> liegt, du kannst also gezielt dort eine falsche Rücksprungadresse
> eintragen und gezielt springen. Also ein mögliches Angriffsszenario. Bei
> einem getrennten Rücksprungstack, ist es ggf schwieriger herauszufinden
> wo er ist.

Das ist kein Argument. Auch wenn da ein extra Variablenstack ist, gibt 
es ja trotzdem noch den Callstack. Und auch die Position auf diesem ist 
bekannt, die steht ja im Stackpointer. Also kann man den Inhalt des 
Stacks auch manipulieren.

Das ist in dem Szenario mit separatem Variablenstack sogar einfacher. 
Weil man ja weiß daß der Callstack genau an der aktuellen Position die 
Rücksprungadresse enthält und da nicht noch ein stack frame von evtl. 
unbekannter Länge davor liegt.


XL

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Axel Schwenke schrieb:
>>  Aha. Und was glaubst du, wie werden die übergebenen Argumente sonst
>>  von der aufgerufenen Routine geholt ?
>
> Über den Stackpointer?

 LOL.

Axel Schwenke schrieb:
> Wenn es zwei Stacks sind - einer für Variablen und einer für Return-
> adressen - dann sind da auch zwei Stackpointer. Und die müssen synchron
> modifiziert werden.

 Hahahaha.

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.