{"id":11650,"date":"2021-09-20T10:24:05","date_gmt":"2021-09-20T08:24:05","guid":{"rendered":"https:\/\/sii.pl\/blog\/?p=11650"},"modified":"2023-10-06T08:48:17","modified_gmt":"2023-10-06T06:48:17","slug":"o-krolu-ram-ie-i-rycerzach-kontekstu","status":"publish","type":"post","link":"https:\/\/sii.pl\/blog\/o-krolu-ram-ie-i-rycerzach-kontekstu\/","title":{"rendered":"O kr\u00f3lu RAM-ie i rycerzach kontekstu"},"content":{"rendered":"\n<p class=\"has-text-align-right\">Kr\u00f3tki przewodnik po pami\u0119ciach<br>\u201eRAM, jaki jest, ka\u017cdy widzi\u201d.<br>ks. Benedykt RAM-owski<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">RAM retrospekcja<\/h2>\n\n\n\n<p>Parafrazuj\u0105c stwierdzenie zaczerpni\u0119te z XVIII-wiecznej encyklopedii, RAM, jaki jest, ka\u017cdy widzi. Na dodatek ka\u017cdy, kto napisa\u0142 cho\u0107 kawa\u0142ek kodu z u\u017cyciem jednej zmiennej, mo\u017ce \u015bmia\u0142o powiedzie\u0107, \u017ce wie o RAM-ie tyle, ile mu potrzeba. Jednak, jak pokazuje praktyka projektowa, nie zawsze jest to prawda.<\/p>\n\n\n\n<p>Zrozumienie wewn\u0119trznych podzia\u0142\u00f3w tego wydawa\u0142oby si\u0119 sp\u00f3jnego obszaru oraz mechanizm\u00f3w nim rz\u0105dz\u0105cych pozwoli nam:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>zaplanowa\u0107 i przydzieli\u0107 wystarczaj\u0105co du\u017cy obszar stosu potrzebny dla naszej aplikacji<\/li>\n\n\n\n<li>diagnozowa\u0107 i debugowa\u0107 typowe problemy zwi\u0105zane z b\u0142\u0119dn\u0105 inicjalizacj\u0105 b\u0105d\u017a przepe\u0142nieniem kt\u00f3rego\u015b z obszar\u00f3w<\/li>\n\n\n\n<li>zastosowa\u0107 kilka programistycznych sztuczek, celem ograniczenia u\u017cycia pami\u0119ci RAM<\/li>\n<\/ul>\n\n\n\n<p>W ramach tego artyku\u0142u zwr\u00f3cimy wi\u0119ksz\u0105 uwag\u0119 na kwesti\u0119 kontekstu oraz jego wp\u0142ywu na zaj\u0119to\u015b\u0107 stosu w urz\u0105dzeniach wbudowanych.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Stos, sterta, dane statyczne<\/h2>\n\n\n\n<p>Og\u00f3lnie, pami\u0119\u0107 RAM mo\u017cemy podzieli\u0107 na 3 zasadnicze obszary:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Stos (stack) \u2013 obszar, w kt\u00f3rym przechowywane s\u0105 wszystkie zmienne lokalne oraz odk\u0142adany jest kontekst przy wywo\u0142ywaniu funkcji lub przerwania. Stos zwykle umieszcza si\u0119 na ko\u0144cu pami\u0119ci RAM i ro\u015bnie on w kierunku malej\u0105cych adres\u00f3w, czyli graficznie w d\u00f3\u0142<\/li>\n\n\n\n<li>Stert\u0119 (heap) \u2013 jest to obszar, do kt\u00f3rego trafiaj\u0105 wszystkie zmienne dynamicznie zaalokowane za pomoc\u0105 polecenia <em>malloc()<\/em>. Od stosu oddziela go pas (ziemi) pami\u0119ci niczyjej<\/li>\n\n\n\n<li>Obszar danych statycznych \u2013 po\u0142o\u017cony przy najni\u017cszych adresach RAM-u zawiera w sobie wszelkie dane globalne, przechowywane w naszym programie, np. wszystkie zmienne czy struktury globalne oraz zmienne statyczne.<br>S\u0142owem \u2013 wszystkie te warto\u015bci, kt\u00f3ra maj\u0105 przetrwa\u0107 mi\u0119dzy wywo\u0142aniami funkcji. Wielko\u015b\u0107 obszaru danych statycznych jest ustalana na etapie kompilacji i sta\u0142a przez ca\u0142y czas dzia\u0142ania programu.<br>Obszar ten dzieli si\u0119 dodatkowo na dwa podobszary: \n<ul class=\"wp-block-list\">\n<li>.bss<\/li>\n\n\n\n<li>.data\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image aligncenter wp-image-11652\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/09\/Stos.jpg\"><img decoding=\"async\" width=\"702\" height=\"1024\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/09\/Stos-702x1024.jpg\" alt=\"Og\u00f3lnikowy podzia\u0142 pami\u0119ci RAM na obszary: stos, wolny obszar pami\u0119ci, sterta i obszar danych statystycznych\" class=\"wp-image-11652\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/09\/Stos-702x1024.jpg 702w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/09\/Stos-206x300.jpg 206w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/09\/Stos.jpg 1583w\" sizes=\"(max-width: 702px) 100vw, 702px\" \/><\/a><figcaption class=\"wp-element-caption\">Rys. 1 Og\u00f3lnikowy podzia\u0142 pami\u0119ci RAM na obszary<\/figcaption><\/figure>\n\n\n\n<p>W dalszych rozwa\u017caniach skupimy si\u0119 g\u0142\u00f3wnie na stosie. Jest to bowiem ten obszar, kt\u00f3rego rozmiar potrafi zmienia\u0107 si\u0119 w szerokim zakresie i kt\u00f3ry mo\u017ce przysporzy\u0107 nieoczekiwanych problem\u00f3w.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Stos<\/h2>\n\n\n\n<p>Stos jest kolejk\u0105 typu <strong>LIFO (Last-In-First-Out)<\/strong>. Ostatni element od\u0142o\u017cony na stosie jest pierwszym elementem, kt\u00f3ry mo\u017cemy z tego stosu zdj\u0105\u0107. Odk\u0142adanie warto\u015bci na stosie przypomina uk\u0142adanie ksi\u0105\u017cek na stole, p\u0142asko jedna na drugiej. Pami\u0119taj\u0105c jednocze\u015bnie o kierunku, w kt\u00f3rym wspomniany ju\u017c stos ro\u015bnie, chyba powinni\u015bmy jednak por\u00f3wna\u0107 odk\u0142adanie na nim danych do pr\u00f3by od\u0142o\u017cenia ksi\u0105\u017cki na suficie.<\/p>\n\n\n\n<p>Zasadniczo na stos odk\u0142adamy dane \u017cyj\u0105ce kr\u00f3tko, przechowywane w pami\u0119ci na potrzeby tych kilku milisekund, kiedy wywo\u0142ywana jest konkretna funkcja, kt\u00f3ra dodatkowo wo\u0142a jeszcze jedn\u0105 b\u0105d\u017a kilka innych funkcji. Nad po\u0142o\u017ceniem wierzcho\u0142ka stosu czuwa dedykowany rejestr sprz\u0119towy (SFR) zwany <strong>wska\u017anikiem stosu<\/strong>.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter wp-image-11654\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/09\/LIFO.jpg\"><img decoding=\"async\" width=\"1024\" height=\"526\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/09\/LIFO-1024x526.jpg\" alt=\"LIFO (Last-in-first-out) na przyk\u0142adzie graficznym\" class=\"wp-image-11654\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/09\/LIFO-1024x526.jpg 1024w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/09\/LIFO-300x154.jpg 300w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/09\/LIFO.jpg 1375w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">Rys. 2 LIFO na przyk\u0142adzie graficznym<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Wska\u017anik stosu<\/h2>\n\n\n\n<p>Wska\u017anik stosu przechowuje aktualny adres wierzcho\u0142ka stosu. Jest to wi\u0119c pierwszy adres, spod kt\u00f3rego nast\u0105pi odczyt ze stosu za po\u015brednictwem instrukcji <em>pop<\/em>.&nbsp;Kolejny adres po adresie wska\u017anika stosu b\u0119dzie pierwszym, pod kt\u00f3ry wykonany zostanie zapis za po\u015brednictwem instrukcji <em>push<\/em>.<strong><br>Wska\u017anik stosu jest swoist\u0105 zak\u0142adk\u0105 w ksi\u0105\u017cce<\/strong> \u2013 pozwala m.in. na szybkie odszukanie kontekstu funkcji wo\u0142aj\u0105cej podczas powrotu z funkcji wo\u0142anej.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter wp-image-11655\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/09\/SP.jpg\"><img decoding=\"async\" width=\"1024\" height=\"425\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/09\/SP-1024x425.jpg\" alt=\"Nieco przejaskrawiony wska\u017anik stosu\" class=\"wp-image-11655\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/09\/SP-1024x425.jpg 1024w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/09\/SP-300x125.jpg 300w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/09\/SP.jpg 1506w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">Rys. 3 Nieco przejaskrawiony wska\u017anik stosu<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Kontekst i skok do funkcji<\/h2>\n\n\n\n<p>Wo\u0142aj\u0105c funkcj\u0119 z dowolnego miejsca w programie, \u0142adujemy argumenty do rejestr\u00f3w procesora b\u0105d\u017a wrzucamy je na stos. Nast\u0119pnie wykonujemy skok pod adres pocz\u0105tku wywo\u0142ywanej funkcji. Po wykonaniu okre\u015blonego przez wywo\u0142an\u0105 funkcj\u0119 zadania, programu musi powr\u00f3ci\u0107 do miejsca, z kt\u00f3rego nast\u0105pi\u0142 skok. <strong>Powinni\u015bmy wi\u0119c jako\u015b zapami\u0119ta\u0107 adres tego miejsca, aby p\u00f3\u017aniej \u0142atwo do niego wr\u00f3ci\u0107<\/strong>.<\/p>\n\n\n\n<p>Sytuacja komplikuje si\u0119, je\u017celi wywo\u0142ana przez nas funkcja wywo\u0142a\u0142a kolejn\u0105, kolejna kolejn\u0105 i tak dalej. Na dobr\u0105 spraw\u0119, powinni\u015bmy zachowa\u0107 wszystkie adresy, spod kt\u00f3rych nast\u0105pi\u0142o wywo\u0142anie ka\u017cdej z funkcji we wspomnianym \u0142a\u0144cuchu. Dodatkowo, z ka\u017cd\u0105 funkcj\u0105 w chwili wywo\u0142ania kolejnej, zwi\u0105zany jest pewien stan programu lub procesora, reprezentowany przez zawarto\u015b\u0107 rejestr\u00f3w CPU.<br>Z chwil\u0105 powrotu z funkcji wo\u0142anej do funkcji wo\u0142aj\u0105cej powinni\u015bmy ten stan rejestr\u00f3w odtworzy\u0107.<\/p>\n\n\n\n<p>I tutaj przychodzi nam z pomoc\u0105 wspomniany wcze\u015bniej stos. Na nim bowiem zachowujemy (odk\u0142adamy):<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>zawarto\u015b\u0107 rejestr\u00f3w og\u00f3lnego przeznaczenia<\/li>\n\n\n\n<li>rejestr statusu (SR)<\/li>\n\n\n\n<li>aktualn\u0105 warto\u015b\u0107 wska\u017anika stosu (SP)<\/li>\n\n\n\n<li>aktualn\u0105 warto\u015b\u0107 licznika programu (PC)<\/li>\n\n\n\n<li>wspomniany wcze\u015bniej adres powrotu (LR)<\/li>\n<\/ul>\n\n\n\n<p>Wymienione wy\u017cej dane, zgrupowane w logiczn\u0105 struktur\u0119, nazywamy <strong>kontekstem<\/strong>. Jest on odk\u0142adany na stos w momencie wywo\u0142ania funkcji b\u0105d\u017a wywo\u0142ania procedury obs\u0142ugi przerwania.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter wp-image-11657\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/09\/Odk\u0142adanie.jpg\"><img decoding=\"async\" width=\"552\" height=\"1024\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/09\/Odk\u0142adanie-552x1024.jpg\" alt=\"Odk\u0142adanie kontekstu na stos przy okazji skoku do kolejnych funkcji na przyk\u0142adzie graficznym\" class=\"wp-image-11657\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/09\/Odk\u0142adanie-552x1024.jpg 552w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/09\/Odk\u0142adanie-162x300.jpg 162w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/09\/Odk\u0142adanie.jpg 1281w\" sizes=\"(max-width: 552px) 100vw, 552px\" \/><\/a><figcaption class=\"wp-element-caption\">Rys. 4 Odk\u0142adanie kontekstu na stos przy okazji skoku do kolejnych funkcji<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Kontekstowa pu\u0142apka<\/h2>\n\n\n\n<p>Mechanizm odk\u0142adania i \u015bci\u0105gania kontekstu ze stosu pozwoli\u0142 nam na \u0142atwe i uporz\u0105dkowane przeskakiwanie mi\u0119dzy kolejnymi funkcjami, zachowuj\u0105c i odtwarzaj\u0105c przy tym stan programu po ka\u017cdym skoku. Wszelkie istotne dane s\u0105 bowiem bezpiecznie zachowane na stosie i odtwarzane podczas powrot\u00f3w z kolejnych funkcji. Jednak wraz ze wzrostem skomplikowania naszego programu mo\u017cemy natkn\u0105\u0107 si\u0119 na szereg niespodzianek, kt\u00f3re zaowocuj\u0105 nieoczekiwanym resetem i nie b\u0119d\u0105 wcale \u0142atwe do odtworzenia i debugowania.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Wywo\u0142anie g\u0142\u0119boko zagnie\u017cd\u017conych funkcji<\/h2>\n\n\n\n<p>Skoro ka\u017cde wywo\u0142anie funkcji powoduje od\u0142o\u017cenie na stosie \u2013 lekko licz\u0105c \u2013 o\u015bmiu rejestr\u00f3w (ilo\u015b\u0107 od\u0142o\u017conych rejestr\u00f3w r\u00f3\u017cni si\u0119 w zale\u017cno\u015bci od konkretnego rdzenia), to, zale\u017cnie od ich wielko\u015bci, pami\u0119\u0107 RAM zostanie uszczuplona o 8 do 32 bajt\u00f3w.<\/p>\n\n\n\n<p>Je\u017celi wi\u0119c wywo\u0142ana przez nas funkcja wywo\u0142a kolejn\u0105, ta nast\u0119pn\u0105 i jeszcze kolejn\u0105 a\u017c do, powiedzmy, siedmiu razy, mo\u017ce si\u0119 okaza\u0107, \u017ce lekk\u0105 r\u0119k\u0105 \u201ewydali\u015bmy\u201d siedmiokrotno\u015b\u0107 wielko\u015bci kontekstu. Przy za\u0142o\u017ceniu, \u017ce pojedynczy rejestr ma 4 bajty, sumarycznie b\u0119d\u0105 to 224 bajty. I te 224 bajty zaj\u0119li\u015bmy (a mo\u017ce raczej zmarnowali\u015bmy?) jedynie na potrzeby zachowania kontekst\u00f3w poszczeg\u00f3lnych funkcji, nie przechowuj\u0105c przy tym \u017cadnych danych przetwarzanych przez nasz program.<\/p>\n\n\n\n<p>Je\u017celi szcz\u0119\u015bliwie mamy do czynienia z platform\u0105, dysponuj\u0105c\u0105 setkami kB, a nawet MB pami\u0119ci RAM, skutki utracenia 224 bajt\u00f3w b\u0119d\u0105 niezauwa\u017calne. Jednak w przypadku mikrokontrolera, dysponuj\u0105cego kilkunastoma kB pami\u0119ci RAM, nale\u017cy uwa\u017ca\u0107 na tego typu nieplanowane i cz\u0119sto niewidoczne go\u0142ym okiem \u201ewydatki\u201d.<\/p>\n\n\n\n<p>Wyobra\u017amy sobie bowiem sytuacj\u0119, w kt\u00f3rej wywo\u0142anie ci\u0105gu wielokrotnie zagnie\u017cd\u017conych funkcji zostanie wyw\u0142aszczone przez przerwanie sygnalizuj\u0105ce na przyk\u0142ad odebranie danej po interfejsie szeregowym. Wtedy na stos zostanie od\u0142o\u017cony kolejny kontekst. Je\u017celi dodatkowo (o zgrozo) wo\u0142amy z procedury obs\u0142ugi przerwania jeszcze kilka zagnie\u017cd\u017conych funkcji, w\u00f3wczas mo\u017ce doj\u015b\u0107 do nieoczekiwanego spotkania nadmiernie spuchni\u0119tego stosu ze stert\u0105. Sko\u0144czy\u0107 si\u0119 to mo\u017ce na wiele sposob\u00f3w:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>nadpisaniem zawarto\u015bci sterty przez stos<\/li>\n\n\n\n<li>wygenerowaniem wyj\u0105tku<\/li>\n\n\n\n<li>resetem platformy<\/li>\n<\/ul>\n\n\n\n<p>M\u00f3wi\u0105c obrazowo \u2013 program mo\u017ce \u201eniespodziewanie przewr\u00f3ci\u0107 si\u0119 na twarz\u201d natychmiast lub przy okazji kolejnej interakcji ze stert\u0105. Na dodatek <strong>b\u0119dzie to trudne do odtworzenia, gdy\u017c wymaga\u0107 b\u0119dzie pojawienia si\u0119 wspomnianego ju\u017c przerwania przy dok\u0142adnie identycznym wype\u0142nieniu stosu!<\/strong><\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter wp-image-11658\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/09\/kontekstOdk\u0142adanie.jpg\"><img decoding=\"async\" width=\"1024\" height=\"356\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/09\/kontekstOdk\u0142adanie-1024x356.jpg\" alt=\"Wizualizacja przepe\u0142nienia stosu w momencie pojawienia si\u0119 przerwania\" class=\"wp-image-11658\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/09\/kontekstOdk\u0142adanie-1024x356.jpg 1024w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/09\/kontekstOdk\u0142adanie-300x104.jpg 300w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">Rys. 5 Wizualizacja przepe\u0142nienia stosu w momencie pojawienia si\u0119 przerwania<\/figcaption><\/figure>\n\n\n\n<p>Z powy\u017cszego rysunku odczyta\u0107 mo\u017cemy:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>lewa strona: wype\u0142nienie stosu praktycznie na styk, brak widocznych problem\u00f3w<\/li>\n\n\n\n<li>prawa strona: przepe\u0142nienie stosu wywo\u0142anie przerwaniem, kt\u00f3re pojawi\u0142o si\u0119 nieszcz\u0119\u015bliwie akurat w momencie skrajnego wype\u0142nienia stosu<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Wczesne wykrywanie problemu<\/h2>\n\n\n\n<p>W teorii monitorowanie ilo\u015bci zaj\u0119tej pami\u0119ci na stosie nie jest trudne. Na dobr\u0105 spraw\u0119 potrzebna jest do tego znajomo\u015b\u0107 3 element\u00f3w:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>adresu pocz\u0105tku stosu<\/li>\n\n\n\n<li>maksymalnego rozmiaru stosu<\/li>\n\n\n\n<li>warto\u015bci aktualnego wska\u017anika stosu<\/li>\n<\/ul>\n\n\n\n<p>Por\u00f3wnuj\u0105c adres pocz\u0105tku stosu do poziomu minimum i adres odpowiadaj\u0105cy maksymalnemu rozmiarowi stosu do poziomu maksimum, mo\u017cemy \u015bmia\u0142o powiedzie\u0107, \u017ce warto\u015b\u0107 wska\u017anika stosu powinna le\u017ce\u0107 pomi\u0119dzy nimi. Im bli\u017cej minimum tym lepiej.<\/p>\n\n\n\n<p>Jednak jest to zbyt du\u017ce uproszczenie problemu. Zaj\u0119to\u015b\u0107 stosu zmienia si\u0119 bowiem bardzo dynamicznie i obliczenie jego aktualnego u\u017cycia powie nam niewiele. Du\u017co bardziej powinna nas interesowa\u0107 maksymalna zaj\u0119to\u015b\u0107 stosu, czyli moment w kt\u00f3rym:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>wywo\u0142ana jest najwi\u0119ksza ilo\u015b\u0107 zagnie\u017cd\u017conych funkcji<\/li>\n\n\n\n<li>wszystkie funkcje od\u0142o\u017cy\u0142y ju\u017c na stos swoje zmienne lokalne<\/li>\n\n\n\n<li>pojawi\u0142o si\u0119 najbardziej pami\u0119cio\u017cerne przerwanie<\/li>\n<\/ul>\n\n\n\n<p><strong>I dok\u0142adnie w tym momencie musimy odczyta\u0107 warto\u015b\u0107 wska\u017anika stosu.<\/strong> Prawda, \u017ce proste?<\/p>\n\n\n\n<p>Zamiast polowa\u0107 na ten moment, lepiej pos\u0142u\u017cy\u0107 si\u0119 jednym z kilku dost\u0119pnych sposob\u00f3w i mechanizm\u00f3w.<\/p>\n\n\n\n<p>Zanim jednak do nich przejdziemy, podzielmy dost\u0119pny obszar stosu na trzy podobszary:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>najwi\u0119kszy, kt\u00f3rego zaj\u0119cie uznajemy za normalne w trakcie dzia\u0142ania naszego programu<\/li>\n\n\n\n<li>obszar marginesu bezpiecze\u0144stwa, w kt\u00f3rym oczekujemy ostrze\u017cenia o jego przekroczeniu, ale jednocze\u015bnie nie wymaga to z naszej strony \u017cadnej reakcji<\/li>\n\n\n\n<li>obszar krytyczny, kt\u00f3rego zaj\u0119cie b\u0119dzie dla nas znakiem powa\u017cnych problem\u00f3w i wymagana jest z naszej strony niezw\u0142oczna reakcja\n<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image aligncenter wp-image-11661\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/09\/podzia\u0142.jpg\"><img decoding=\"async\" width=\"806\" height=\"1024\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/09\/podzia\u0142-806x1024.jpg\" alt=\"Stos podzielony na podobszary: zwyk\u0142y, ostrzegawczy i alarmowy\" class=\"wp-image-11661\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/09\/podzia\u0142-806x1024.jpg 806w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/09\/podzia\u0142-236x300.jpg 236w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/09\/podzia\u0142.jpg 1483w\" sizes=\"(max-width: 806px) 100vw, 806px\" \/><\/a><figcaption class=\"wp-element-caption\">Rys. 6 Stos podzielony na podobszary: zwyk\u0142y, ostrzegawczy i alarmowy<\/figcaption><\/figure>\n\n\n\n<p>Nale\u017cy zaznaczy\u0107, \u017ce czerwony alarm powinien zosta\u0107 podniesiony, zanim nast\u0105pi przepe\u0142nienie stosu. Fragment kodu obs\u0142uguj\u0105cy wygenerowane przerwanie lub funkcje obs\u0142uguj\u0105ce wspomniany alarm r\u00f3wnie\u017c potrzebuj\u0105 tych kilkunastu bajt\u00f3w stosu, aby si\u0119 poprawnie wykona\u0107. Z tego powodu <strong>alarmowanie w momencie, gdy zapisany zosta\u0142 ostatni wolny bajt stosu, jest alarmowaniem sp\u00f3\u017anionym.<\/strong><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">MMU\/MPU<\/h2>\n\n\n\n<p>Rozbudowane platformy dysponuj\u0105 jednostk\u0105 zarz\u0105dzania lub ochrony pami\u0119ci (MMU\/MPU), w kt\u00f3rej mo\u017cemy okre\u015bli\u0107 obszary, pod kt\u00f3re zapis jest zabroniony. Upraszczaj\u0105c nieco \u2013 konfiguracja MMU\/MPU polega na podaniu trzech parametr\u00f3w dla pojedynczego, chronionego obszaru:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>adres pocz\u0105tku<\/li>\n\n\n\n<li>rozmiar<\/li>\n\n\n\n<li>dozwolony typ dost\u0119pu (zapis, odczyt, wykonywanie kodu)<\/li>\n<\/ul>\n\n\n\n<p>W efekcie, gdy nast\u0105pi zapis pod kt\u00f3rykolwiek z adres\u00f3w nale\u017c\u0105cych do wcze\u015bniej zdefiniowanego obszaru, wygenerowany zostanie wyj\u0105tek procesora. Takich obszar\u00f3w mo\u017cemy zwykle zdefiniowa\u0107 kilka. Dok\u0142adna ich liczba zale\u017cy od procesora i zastosowanego MMU\/MPU.<\/p>\n\n\n\n<p>W momencie wygenerowania wyj\u0105tku pozostaje jeszcze kwestia okre\u015blenia, kt\u00f3ry z chronionych obszar\u00f3w zosta\u0142 naruszony. W zale\u017cno\u015bci od konkretnego procesora mo\u017cemy to odczyta\u0107 z rejestr\u00f3w MMU\/MPU lub rejestr\u00f3w przechowuj\u0105cych stan pami\u0119ci lub szyny danych (np. <em>bus fault address register<\/em> w procesorach rodziny STM32).<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Zapisywanie wzorca na stosie<\/h2>\n\n\n\n<p>Dzi\u0119ki wype\u0142nieniu przypisanej do stosu pami\u0119ci znanym i sta\u0142ym wzorcem (patternem), mo\u017cemy bezb\u0142\u0119dnie oceni\u0107, jak daleko obszar stosu zosta\u0142 zapisany w szczytowym momencie jego zaj\u0119to\u015bci. Kolejne, odk\u0142adane na stos dane b\u0119d\u0105 bowiem niszczy\u0107 zapisany wcze\u015bniej wzorzec.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter wp-image-11662\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/09\/Watermark.jpg\"><img decoding=\"async\" width=\"1024\" height=\"305\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/09\/Watermark-1024x305.jpg\" alt=\"Przyk\u0142ady u\u017cycia wzorca do okre\u015blania maksymalnej zaj\u0119to\u015bci stosu \" class=\"wp-image-11662\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/09\/Watermark-1024x305.jpg 1024w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/09\/Watermark-300x89.jpg 300w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">Rys. 7 Przyk\u0142ad u\u017cycia wzorca do okre\u015blania maksymalnej zaj\u0119to\u015bci stosu<\/figcaption><\/figure>\n\n\n\n<p>Analizuj\u0105c powy\u017csz\u0105 grafik\u0119 od lewej do prawej mo\u017cemy zauwa\u017cy\u0107 nast\u0119puj\u0105cy proces: od niewielkiego zaj\u0119cia stosu, przez znaczne zaj\u0119cie stosu, po ponownie wolny stos. Co istotne \u2013 raz nadpisany fragment wzorca znika na zawsze.<\/p>\n\n\n\n<p>Cykliczne sprawdzanie, jak daleko wzorzec zosta\u0142 nadpisany, pozwoli nam okre\u015bli\u0107 maksymaln\u0105 zaj\u0119to\u015b\u0107 stosu w d\u0142u\u017cszym okresie dzia\u0142ania naszego programu. W przypadku system\u00f3w jednow\u0105tkowych jest to wystarczaj\u0105ca metryka, pozwalaj\u0105ca okre\u015bli\u0107 do\u015bwiadczalnie (in vivo), jak du\u017cy obszar stosu jest wymagany na potrzeby konkretnej aplikacji.<\/p>\n\n\n\n<p>W przypadku <strong>system\u00f3w wielow\u0105tkowych metoda wzorca mo\u017ce nas zaprowadzi\u0107 na manowce<\/strong>. Temat przybli\u017c\u0119 w kolejnym artykule dotycz\u0105cym stosu.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Jak du\u017cy powinien by\u0107 obszar stosu?<\/h2>\n\n\n\n<p>Ci\u0119\u017cko jest poda\u0107 jednoznaczn\u0105 odpowied\u017a na pytanie, jak du\u017cy obszar RAM-u nale\u017cy przeznaczy\u0107 na stos. W idealnym \u015bwiecie mogliby\u015bmy odpowiedzie\u0107 \u2013 tak du\u017cy, jak tylko si\u0119 da. W wi\u0119kszo\u015bci realnych przypadk\u00f3w nie mamy takiej mo\u017cliwo\u015bci. Dodatkow\u0105 trudno\u015bci\u0105 jest konieczno\u015b\u0107 nieco arbitralnego okre\u015blenia tej wielko\u015bci przed napisaniem pierwszej linii kodu.<\/p>\n\n\n\n<p>Mo\u017cemy posi\u0142kowa\u0107 si\u0119 warto\u015bci\u0105 procentow\u0105 b\u0105d\u017a obliczy\u0107 w spos\u00f3b przybli\u017cony potrzebn\u0105 ilo\u015b\u0107 stosu bior\u0105c pod uwag\u0119:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>ilo\u015b\u0107 dzia\u0142aj\u0105cych jednocze\u015bnie w\u0105tk\u00f3w\n<ul class=\"wp-block-list\">\n<li>systemy jednow\u0105tkowe wymagaj\u0105 mniejszego stosu od wielow\u0105tkowych<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>dost\u0119pn\u0105 ilo\u015b\u0107 RAM-u w procesorze\n<ul class=\"wp-block-list\">\n<li>przyk\u0142adowo przy 10 kB dost\u0119pnego RAM-u, po\u015bwi\u0119cenie 30% na stos wydaje si\u0119 warto\u015bci\u0105 rozs\u0105dn\u0105, pami\u0119taj\u0105c przy tym, aby nie pisa\u0107 kodu zawieraj\u0105cego wielokrotnie zagnie\u017cd\u017cone funkcje<\/li>\n\n\n\n<li>w przypadku platformy wyposa\u017conej w 128 kB RAM-u ustawienie wielko\u015bci stosu na 30% mo\u017ce si\u0119 okaza\u0107 rozrzutno\u015bci\u0105, szczeg\u00f3lnie je\u017celi uruchamiany na niej program jest prosty<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>z\u0142o\u017cono\u015b\u0107 naszego programu\n<ul class=\"wp-block-list\">\n<li>nawet rozbudowany program, b\u0119d\u0105cy kombinacj\u0105 funkcjonalno\u015bci opartych o proste modu\u0142y, jak np. GPIO, RTC, UART czy implementuj\u0105cego prosty protok\u00f3\u0142 szeregowy, wymaga zdecydowanie mniej stosu od mniej rozbudowanego programu wykorzystuj\u0105cego stos TCP\/IP, biblioteki graficzne do obs\u0142ugi wy\u015bwietlacza dotykowego czy biblioteki kryptograficzne<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>konieczno\u015b\u0107 u\u017cycia zewn\u0119trznych bibliotek\n<ul class=\"wp-block-list\">\n<li>nie mamy bowiem wp\u0142ywu na ilo\u015b\u0107 zagnie\u017cd\u017ce\u0144 funkcji oraz generalnie u\u017cycie zasob\u00f3w przez bibliotek\u0119<\/li>\n\n\n\n<li>w dokumentacji od biblioteki powinni\u015bmy znale\u017a\u0107 informacj\u0119 na temat oczekiwanej zaj\u0119to\u015bci stosu (tzw. <em>footprint<\/em>)<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>szacowan\u0105 ilo\u015b\u0107 zagnie\u017cd\u017ce\u0144 funkcji<\/li>\n<\/ul>\n\n\n\n<p>Je\u017celi ju\u017c kompletnie nie wiemy, jak\u0105 warto\u015b\u0107 przyj\u0105\u0107 \u2013 <strong>przydzielmy 30% dost\u0119pnej pami\u0119ci<\/strong>,<strong> a nast\u0119pnie dokonajmy pomiaru maksymalnej zaj\u0119to\u015bci stosu i zaktualizujmy przyj\u0119t\u0105 warto\u015b\u0107, zachowuj\u0105c 10-20% marginesu bezpiecze\u0144stwa.<\/strong><\/p>\n\n\n\n<p>Wielko\u015b\u0107 wspomnianego marginesu powinna by\u0107 tym wi\u0119ksza, im bardziej odpowiedzialne zadanie b\u0119dzie wykonywa\u0142o nasze urz\u0105dzenie. Nieoczekiwany, wynikaj\u0105cy z przepe\u0142nienia stosu, reset domowego nawil\u017cacza powietrza podczas zmiany ustawie\u0144 g\u0142\u0119boko w menu nie b\u0119dzie czym\u015b strasznym. Inaczej jednak b\u0119dzie to wygl\u0105da\u0142o np. w przypadku sterownika obrabiarki numerycznej \u2013 tutaj mo\u017ce doj\u015b\u0107 do zaburzenia procesu produkcji, co prze\u0142o\u017cy si\u0119 na realne straty finansowe.<\/p>\n\n\n\n<p>Dodatkowym czynnikiem decyduj\u0105cym o wielko\u015bci wspomnianego marginesu, powinna by\u0107 mo\u017cliwo\u015b\u0107 (lub niemo\u017cno\u015b\u0107) wykonania \u0142atwej aktualizacji oprogramowania urz\u0105dzenia u klienta lub w polu.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Podsumowanie<\/h2>\n\n\n\n<p>O RAM-ie i jego obszarach mo\u017cna spokojnie napisa\u0107 opas\u0142\u0105 ksi\u0105\u017ck\u0119 oraz obroni\u0107 doktorat i habilitacj\u0119 naukow\u0105. Zadaniem praktyk\u00f3w jest jednak zrozumie\u0107 go na tyle, aby m\u00f3c efektywnie i zarazem bezpiecznie z niego korzysta\u0107. Na nieostro\u017cnego i nie\u015bwiadomego programist\u0119 czyha tam bowiem wiele pu\u0142apek \u2013 jedn\u0105 z nich przybli\u017cy\u0142em w ramach tego artyku\u0142u.<\/p>\n\n\n\n<p>Zach\u0119cam wszystkich czytaj\u0105cych do przyjrzenia si\u0119 ustawieniom skrypt\u00f3w linkera w swoich projektach, ze szczeg\u00f3lnym naciskiem na po\u0142o\u017cenie oraz rozmiar obszar\u00f3w stosu oraz sterty.<\/p>\n\n\n\n<p class=\"has-text-align-right\">.223rem<\/p>\n\n\n<div class=\"kk-star-ratings kksr-auto kksr-align-left kksr-valign-bottom\"\n    data-payload='{&quot;align&quot;:&quot;left&quot;,&quot;id&quot;:&quot;11650&quot;,&quot;slug&quot;:&quot;default&quot;,&quot;valign&quot;:&quot;bottom&quot;,&quot;ignore&quot;:&quot;&quot;,&quot;reference&quot;:&quot;auto&quot;,&quot;class&quot;:&quot;&quot;,&quot;count&quot;:&quot;21&quot;,&quot;legendonly&quot;:&quot;&quot;,&quot;readonly&quot;:&quot;&quot;,&quot;score&quot;:&quot;5&quot;,&quot;starsonly&quot;:&quot;&quot;,&quot;best&quot;:&quot;5&quot;,&quot;gap&quot;:&quot;11&quot;,&quot;greet&quot;:&quot;&quot;,&quot;legend&quot;:&quot;5\\\/5 ( votes: 21)&quot;,&quot;size&quot;:&quot;18&quot;,&quot;title&quot;:&quot;O kr\u00f3lu RAM-ie i rycerzach kontekstu&quot;,&quot;width&quot;:&quot;139.5&quot;,&quot;_legend&quot;:&quot;{score}\\\/{best} ( {votes}: {count})&quot;,&quot;font_factor&quot;:&quot;1.25&quot;}'>\n            \n<div class=\"kksr-stars\">\n    \n<div class=\"kksr-stars-inactive\">\n            <div class=\"kksr-star\" data-star=\"1\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"2\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"3\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"4\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"5\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n    <\/div>\n    \n<div class=\"kksr-stars-active\" style=\"width: 139.5px;\">\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n    <\/div>\n<\/div>\n                \n\n<div class=\"kksr-legend\" style=\"font-size: 14.4px;\">\n            5\/5 ( votes: 21)    <\/div>\n    <\/div>\n","protected":false},"excerpt":{"rendered":"<p>Kr\u00f3tki przewodnik po pami\u0119ciach\u201eRAM, jaki jest, ka\u017cdy widzi\u201d.ks. Benedykt RAM-owski RAM retrospekcja Parafrazuj\u0105c stwierdzenie zaczerpni\u0119te z XVIII-wiecznej encyklopedii, RAM, jaki &hellip; <a class=\"continued-btn\" href=\"https:\/\/sii.pl\/blog\/o-krolu-ram-ie-i-rycerzach-kontekstu\/\">Continued<\/a><\/p>\n","protected":false},"author":161,"featured_media":11674,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_editorskit_title_hidden":false,"_editorskit_reading_time":0,"_editorskit_is_block_options_detached":false,"_editorskit_block_options_position":"{}","inline_featured_image":false,"footnotes":""},"categories":[1314],"tags":[563,1119,1121],"class_list":["post-11650","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-development-na-twardo","tag-embedded","tag-ram","tag-stos"],"acf":[],"aioseo_notices":[],"republish_history":[],"featured_media_url":"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/09\/O-kr\u00f3lu-RAM-ie-1.png","category_names":["Development na twardo"],"_links":{"self":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/11650"}],"collection":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/users\/161"}],"replies":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/comments?post=11650"}],"version-history":[{"count":2,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/11650\/revisions"}],"predecessor-version":[{"id":24868,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/11650\/revisions\/24868"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/media\/11674"}],"wp:attachment":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/media?parent=11650"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/categories?post=11650"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/tags?post=11650"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}