avr-gcc - velikost stacku v nejhorším případě?

Jan Waclawek konfera na efton.sk
Úterý Květen 27 00:05:12 CEST 2014


> zjistit, zda je velikost bufferu ještě bezpečná, tedy zda nehrozí kolize 
> stacku a sekce .bss.

Toto je oblubena tema, ktora sa diskutuje priemerne raz za pol roka na avr-gcc subfore avrfreaks.net... naposledy napr. http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=141602 , ale oplati sa mozno pohladat aj starsie vlakna na tuto temu.

Najprv je dobre si ujasnic, co vsetko sa na stacku moze vyskytnut - predovsetkym navratove adresy pri volani podprogramov (a to nemusia byt volane "vedome" ako explicitne volanie funkcie, ale aj ako implicitne volanie nejakej zabudovanej funkcie ktoru tam vlozi prekladac) a registre ukladane prekladacom pri volani rutin podla predpisu (ABI); dalej registre docasne ukladane pri vykonavani nejakej zlozitejsej operacie (toto u avr-gcc myslim ze sa nevyskytuje); pamat vyuzivana na lokalne a automaticke premenne funkcii; pamat explicitne alokovana pomocou funkcie alloca(); zasobnikova pamat akymkolvek sposobom vyuzivana vlozenymi asemblerovskymi rutinami, bud uzivatelskymi alebo kniznicnymi - mozno som este na nieco zabudol.

V zasade sa vyskytuju tri sposoby, ziadny z nich nie je dokonaly, vsetky su relativne pracne a neposkytuju nejake definitivne vysledky.

Jeden sposob je taky, ze v startup kode sa naplni cela pamat nejakym vzorom (s oblubou sa pouziva 0xDEADBEEF, takze toto mozete pouzit aj na vyhladavanie diskusie na tuto temu), necha sa bezat program, ak je moznost nejako jeho beh ovplyvnit, tak sa treba snazit ho prehnat co najviac roznymi stavmi, no a potom sa najekym spobobom (napr. pomocou debuggera, alebo zavolanim nejakej specializovanej rutiny, alebo "za jazdy" v hlavnej slucke alebo v preruseni - toto poskytuje zaujimavu moznost spatnej vazby ak je k dispozicii napr. display) zistuje, ako hlboko prepisal stack tuto hodnotu.

Druhy sposob vychadza z udajov prekladaca o pouziti zasobnika na ulozenie registrov a lokalnych/automatickych premennych pri volani funkcii (prekladac v prologu funkcie vytvara tzv. stack frame), nadnesene by sme to mohli nazvat statickou analyzou. Prekladac tuto informaciu za urcitych okolnosti uklada do asemblerovskeho medzisuboru, z coho sa to ocitne v listfile asemblera; ale od urcitej verzie sa da prinutit aby to ulozil aj do samostatneho suboru (-fstack-usage). K tomuto treba este vytvorit strom volani, aby sa zistila maximalna hlbka. (Aj) na tento ucel som zbastlil http://www.efton.sk/misc/checkmap.zip , uzivatelsky maximalne neprivetivu utilitu s mnozstvom chyb a nedostatkov (z ktorych cast je popisana aj v "dokumentacii" - asi najvacsi je ten, ze buduje len strom od main() a neberie do uvahy prerusenia, ktore pochopitelne v strome nenajde).

Treti sposob by mna osobne nikdy nebol napadol, a rozhodne by som sa nepustil do jeho mimoriadne pracnej implementacie - ide o rekurzivnu simulaciu kompletnej cesty programu, t.j. cez vsetky moznosti vetvenia. Tusim zahrna aj (aspon tie lahko vypocitatelne) nepriame volania a aj prerusenia. Ten chlapik co to napisal sa na avrfreaks vyskytuje pod nickom ezharkov a program je http://home.comcast.net/~ezstack/ezstack.c - ano, je vo forme zdrojaku, *nixaci plesaju ;-)

> Ještě mi vrtá hlavou jedna související otázka. Hodilo by se mi, aby se 
> můj commandBuffer umístil úplně na konec sekce .bss. To z toho důvodu, 

Ak sa nemylim (nie som pri kompe s avr-gcc), tak za .bss je v defaultnom linker skripte este mapovana sekcia .noinit, takze najjednoduchie je ju umiestnit tam.  Ina moznost je pouzit vlastny linker skript v ktorom sa nejaka sekcia umiestni za .bss a premenna sa umiestni tam. 

wek




On Mon, 26 May 2014 21:11:21 +0200
Ondrej Stanek <ostan89 at gmail.com> wrote:

> Zdravím konferenci,
> programuji pro mikrokontroléry AVR v C (avr-gcc). V programu potřebuji 
> buffer značné velikosti, čím větší tím lepší. Hledám způsob jakým 
> zjistit, zda je velikost bufferu ještě bezpečná, tedy zda nehrozí kolize 
> stacku a sekce .bss.
> 
> Tedy abych byl více konkrétní, mám deklarovaný buffer:
> 
> static command_t commandBuffer[MAX_COMMAND_COUNT];
> 
> který se při kompilaci umístí do .bss sekce.
> 
> Při zkompilování mi gcc hlásí, kolik paměti SRAM je využito:
> 
> Data:       1067 bytes (52.1% Full)
> (.data + .bss + .noinit)
> 
> Tedy ještě je alespoň 1kB volný pro stack (Poznámka: heap - dynamicky 
> alokovanou paměť nevyužívám). No a mě by hrozně moc zajímalo, o kolik 
> můžu můj buffer ještě zvětšit. Nebo obráceně, jak velikou paměť zabere 
> stack v nejhorším případě.
> 
> Poradíte nějaké metody, jak zjistit (offline nebo za běhu), kam až může 
> stack narůst v nejhorším případě? Připomínám, že mi jde konkrétně o 
> embedded aplikaci, MCU ATmega328.
> 
> Ještě mi vrtá hlavou jedna související otázka. Hodilo by se mi, aby se 
> můj commandBuffer umístil úplně na konec sekce .bss. To z toho důvodu, 
> že kdyby nedejbože náhodou došlo ke kolizi, tak stack začne prvně 
> přepisovat právě tenhle buffer, a né nějaké jiné důležité proměnné. Jak 
> na to? Napadlo mě alokovat commandBuffer jako jediný na heapu při 
> inicializaci, ale tím se mi do binárky přibalí celá malloc mašinerie, a 
> kód už se pak nevejde do flash paměti mikrokontroléru. Poradíte nějaké 
> pěkné řešení?
> 
> Ondra Staněk
> _______________________________________________
> HW-list mailing list  -  sponsored by www.HW.cz
> Hw-list at list.hw.cz
> http://list.hw.cz/mailman/listinfo/hw-list


Další informace o konferenci Hw-list