Brechen Sie den Stapel in STM8

Beim Schreiben des STM8uLoader-Bootloaders für STM8-Mikrocontroller wurde es erforderlich, die Tiefe des Stapels zu messen.

Stellen wir Fragen:

  • Was passiert, wenn Sie versuchen, mehr Informationen auf den Stapel zu übertragen als seine Tiefe?
  • Was passiert, wenn Sie versuchen, mehr Informationen aus dem Stapel zu extrahieren, als Sie platziert haben?
  • Was passiert, wenn Sie den Stapelzeiger SP mit einer Adresse initialisieren, die über die Grenzen des Stapels hinausgeht?

RAM-Speicher und Stapeltiefe können für verschiedene STM8-Modelle variieren.
Für die Studie wurde das Modell STM8S103F3 ausgewählt.

Die Dokumentation zum STM8S103F3 enthält folgende Daten:
- Stapeltiefe 513 Bytes;
- Beim Zurücksetzen wird der SP-Zeiger auf 0x03FF (RAM END) initialisiert.
- Der Stapel wächst in Richtung abnehmender Adressen.

Die Berechnung zeigt, dass die Untergrenze des Stapels ist:

0x03FF - 513 = 0x01FF 

Um diese Grenze zu überschreiten, müssen Sie einige mehr als 513 Bytes auf dem Stapel verschieben.

Der Inhalt des Stapels interessiert uns nicht. Es reicht aus, den Inhalt des Zeigers auf den SP-Stapel zu kennen, der die Adresse der nächsten nicht verwendeten RAM-Speicherzelle enthalten sollte.
Wir platzieren die Bytes nacheinander mit einem beliebigen Push-Befehl (z. B. Push A) und senden vor jedem Schritt den Inhalt des höchsten SPH- und unteren SPL-Bytes des SP-Stapelzeigers an den UART.

Verfahrensalgorithmus:

1 Initialisieren Sie den Stapelzeiger mit dem Wert 0x03FF und konfigurieren Sie den UART.
2 Wir warten auf ein Byte aus dem Terminalprogramm.
3 Bytes akzeptiert;
4 Senden Sie den Inhalt des SP-Zeigers an den UART.
5 Wir schieben den Inhalt der Batterie mit dem Befehl push A auf den Stapel.
6 Wenn die Sendezyklen kleiner als 64 sind, fahren Sie mit Schritt 4 fort.
7 Wenn die Sendezyklen 64 sind, fahren Sie mit Schritt 2 fort.

 ;  UART 9600/8N1 mov UART1_BRR2, #$00 ;     mov UART1_BRR1, #$0D ;  / mov UART1_CR2, #%00001100 ;   SP  $03FF ldw X, #$03FF ; X <= RAM END ldw SP, X ; SP <= X ;     wait_rx_byte: btjf UART1_SR, #5, wait_rx_byte ; ld A, UART1_DR ;   bset PB_DDR,#5 bset PB_CR1,#5 ldw Y, #64 ; Y <= 64 stack_cycle: ldw X, SP ; X <= SP ;  SPH  UART ; rlwa X ; A <- XH <- XL <- A ld A, XH ; A <- XH ld UART1_DR, A ; UART1_DR <= A wait_tx_byte_XH: btjf UART1_SR, #7, wait_tx_byte_XH ;  SPL  UART ; rlwa X ; A <- XH <- XL <- A ld A, XL ; A <- XL ld UART1_DR, A ; UART1_DR <= A wait_tx_byte_XL: btjf UART1_SR, #7, wait_tx_byte_XL ;  A   push A ; M(SP--) <= A decw Y jrne stack_cycle ;   bres PB_DDR,#5 bres PB_CR1,#5 jra wait_rx_byte 

Wir beobachten, wie das Terminalprogramm den Inhalt des SP-Zeigers ab 0x03FF sequentiell akzeptiert:

  03 FF 03 FE 03 FD 03 FC 03 FB 03 FA 03 F9 03 F8 03 F7 03 F6 03 F5 03 F4 03 F3 03 F2 03 F1 03 F0 03 EF 03 EE 03 ED 03 EC 03 EB 03 EA 03 E9 03 E8 03 E7 03 E6 03 E5 03 E4 03 E3 03 E2 03 E1 03 E0 03 DF 03 DE 03 DD 03 DC 03 DB 03 DA 03 D9 03 D8 

Nachdem der Wert 0x01FF erreicht hat (zuvor berechneter Stapelrand)
Der SP-Zeiger nahm erneut den Wert 0x03FF an (der Stapel wurde in einem Ring geschlossen).
und begann die ältesten Daten zu überschreiben

  02 0F 02 0E 02 0D 02 0C 02 0B 02 0A 02 09 02 08 02 07 02 06 02 05 02 04 02 03 02 02 02 01 02 00 01 FF 03 FF 03 FE 03 FD 03 FC 03 FB 03 FA 03 F9 03 F8 03 F7 03 F6 03 F5 03 F4 03 F3 03 F2 03 F1 03 F0 03 EF 03 EE 03 ED 03 EC 03 EB 03 EA 03 E9 

Nun wollen wir sehen, wie sich der Inhalt des SP-Zeigers verhält, wenn wir versuchen, den Inhalt unbegrenzt vom Stapel abzurufen.

Verfahrensalgorithmus:

1 Initialisieren Sie den Stapelzeiger mit dem Wert 0x03FF und konfigurieren Sie den UART.
2 Wir warten auf ein Byte aus dem Terminalprogramm.
3 Bytes akzeptiert;
4 Wir extrahieren den Inhalt aus dem Stapel mit dem Befehl „pop A“ in die Batterie.
5 Sendet den Inhalt des SP-Zeigers an den UART.
6 Wenn die Sendezyklen kleiner als 64 sind, fahren Sie mit Schritt 3 fort.
7 Wenn die Sendezyklen 64 sind, fahren Sie mit Schritt 2 fort.

Die Punkte 4 und 5 des Algorithmus und der Befehl "Push A" werden gegen den Befehl "Pop A" ausgetauscht.
Trotz der Tatsache, dass wir den SP-Zeiger bereits nach dem ersten Pop-A-Befehl mit dem Wert 0x03FF initialisiert haben, nahm der Zeiger den Wert 0x01FF an und stieg weiter in Richtung 0x03FF an.

  01 FF 02 00 02 01 02 02 02 03 02 04 02 05 02 06 02 07 02 08 02 09 02 0A 02 0B 02 0C 02 0D 02 0E 02 0F 02 10 02 11 02 12 02 13 02 14 02 15 02 16 02 17 02 18 02 19 02 1A 02 1B 02 1C 02 1D 02 1E 02 1F 02 20 02 21 02 22 02 23 02 24 02 25 02 26 

Erreichen des Wertes 0x03FF. Nach dem nächsten Pop-A-Befehl nahm der Zeiger wieder den Wert 0x01FF an und stieg weiter in Richtung 0x03FF an.

  03 EF 03 F0 03 F1 03 F2 03 F3 03 F4 03 F5 03 F6 03 F7 03 F8 03 F9 03 FA 03 FB 03 FC 03 FD 03 FE 03 FF 01 FF 02 00 02 01 02 02 02 03 02 04 02 05 02 06 02 07 02 08 02 09 02 0A 02 0B 02 0C 02 0D 02 0E 02 0F 02 10 02 11 02 12 02 13 02 14 02 15 

In der entgegengesetzten Richtung wird der Stapel mit einer übermäßigen Anzahl von Pop (w) -Anweisungen auch in einem 513-Byte-Ring geschlossen.

Der Stapel in STM8S103F3 ist linear, bis Sie einen seiner Ränder 0x01FF oder 0x03FF durchbrechen.

Sobald Sie eine der Grenzen überschreiten, wird der Stapel zu einem 513-Byte-Ring.
Es spielt keine Rolle, wo sich im Ring (an den Adressen 0x01FF ... 0x03FF) die Ober- / Unterseite des Stapels befindet. Wir können eine unbegrenzte Anzahl von Bytes auf den Stapel legen, aber wir können nicht mehr als 513 unbeschädigte Bytes (die neuesten) extrahieren.

Jetzt, da der Stapel bei 0x01FF ... 0x03FF lokalisiert ist, ist es Zeit, diesen Bereich zu brechen, wenn der SP-Zeiger initialisiert wird.

In Schritt 1 der ersten Prozedur ersetzen wir den Wert 0x03FF zum Initialisieren des SP-Zeigers durch den Wert 0x01FE.

Wir beobachten, wie der Stapel von der Adresse 0x01FE in Richtung abnehmender Adressen ging.

  01 FE 01 FD 01 FC 01 FB 01 FA 01 F9 01 F8 01 F7 01 F6 01 F5 01 F4 01 F3 01 F2 01 F1 01 F0 01 EF 01 EE 01 ED 01 EC 01 EB 01 EA 01 E9 01 E8 01 E7 01 E6 01 E5 01 E4 01 E3 01 E2 01 E1 01 E0 01 DF 01 DE 01 DD 01 DC 01 DB 01 DA 01 D9 01 D8 01 D7 

Nachdem der Stapel die Adresse 0x0000 erreicht hatte, verließ er den RAM-Speicher und trat in die FLASH-Speicherzellen ein, auf die der STM8S103F3 nicht zugreifen konnte.

  00 16 00 15 00 14 00 13 00 12 00 11 00 10 00 0F 00 0E 00 0D 00 0C 00 0B 00 0A 00 09 00 08 00 07 00 06 00 05 00 04 00 03 00 02 00 01 00 00 FF FF FF FE FF FD FF FC FF FB FF FA FF F9 FF F8 FF F7 FF F6 FF F5 FF F4 FF F3 FF F2 FF F1 FF F0 FF EF 

Es kann nicht von Unterprogrammaufrufen oder Unterbrechungen gesprochen werden, nachdem der Zeiger den RAM-Speicher verlassen hat. Zwar blieben irgendwo in den Tiefen des Stapels noch die „ältesten“ Daten übrig, die glücklicherweise im RAM-Speicher gespeichert wurden.

Versuchen wir nun, Daten mit der "verbotenen" (außerhalb des Bereichs 0x01FF ... 0x03FF) Initialisierung des SP-Zeigers vom Stapel abzurufen.

Beginnen wir mit Adressen außerhalb des Arbeitsspeichers. In Schritt 1 der zweiten Prozedur ersetzen wir den Wert 0x03FF der Initialisierung des Zeigers SP durch den Wert 0xFFF8.

Wir beobachten, wie der Stapel in den RAM-Speicher gelangt ist.

  FF E9 FF EA FF EB FF EC FF ED FF EE FF EF FF F0 FF F1 FF F2 FF F3 FF F4 FF F5 FF F6 FF F7 FF F8 FF F9 FF FA FF FB FF FC FF FD FF FE FF FF 00 00 00 01 00 02 00 03 00 04 00 05 00 06 00 07 00 08 00 09 00 0A 00 0B 00 0C 00 0D 00 0E 00 0F 00 10 

Der Stapel überquerte den unteren Rand 0x01FF und betrat sein Territorium.

  01 E9 01 EA 01 EB 01 EC 01 ED 01 EE 01 EF 01 F0 01 F1 01 F2 01 F3 01 F4 01 F5 01 F6 01 F7 01 F8 01 F9 01 FA 01 FB 01 FC 01 FD 01 FE 01 FF 02 00 02 01 02 02 02 03 02 04 02 05 02 06 02 07 02 08 02 09 02 0A 02 0B 02 0C 02 0D 02 0E 02 0F 02 10 

Nachdem die Adresse 0x03FF erreicht war, schloss sich der Stapel in einem Ring.

  03 E9 03 EA 03 EB 03 EC 03 ED 03 EE 03 EF 03 F0 03 F1 03 F2 03 F3 03 F4 03 F5 03 F6 03 F7 03 F8 03 F9 03 FA 03 FB 03 FC 03 FD 03 FE 03 FF 01 FF 02 00 02 01 02 02 02 03 02 04 02 05 02 06 02 07 02 08 02 09 02 0A 02 0B 02 0C 02 0D 02 0E 02 0F 

Schlussfolgerungen:

Der Stack in STM8S103F3 kann seine Aufgaben nur im Bereich 0x01FF ... 0x03FF ausführen.

Um die größte lineare Tiefe zu erhalten, muss der SP-Stapelzeiger in STM8S103F3 auf 0x03FF initialisiert werden.

Der Stapel in STM8S103F3 ist linear, bis Sie die untere Grenze von 0x01FF durchbrechen.
Sobald Sie die Untergrenze überschreiten, wird der Stapel zu einem 513-Byte-Ring.

Source: https://habr.com/ru/post/de417203/


All Articles