Jak zvětšit návratový zásobník v AVR Studiu?
Moderátor: Moderátoři
Jak zvětšit návratový zásobník v AVR Studiu?
Potřeboval bych zvětšit návratový zásobník (STACK) v AVR studiu.
V ASM to umím, ale jak na to v Céčku ?
Kód: Vybrat vše
.EQU SPCNT =0x10 ;Velikost Stacku
.DSEG
.ORG RAMEND-SPCNT ;Na konec paměti
STACK: .BYTE SPCNT ;reservuj paměť pro Stack
V podstatě tím překladači sdělím, že tato paměť je vyhrazena,
takže pokud pak svou blbostí či jinou chybou pokusím sáhnout,
tak mi překladač vyhodí chybu.
matajovsky: Mohl by jsi být podrobnější? Nějaká ukázka by mohla být vhod.
A nevíš náhodou jak zjistím současnou velikost (překladačem definovaného) stacku?
divous píše:V podstatě tím překladači sdělím, že tato paměť je vyhrazena,
takže pokud pak svou blbostí či jinou chybou pokusím sáhnout,
tak mi překladač vyhodí chybu.
Assembler vyhodí chybu, jen když si dáš dvě statické proměnné přes sebe nebo se ti nevejdou do paměti, ale to, kam programem saháš, nekontroluje ani to, jestli ti zásobník nepřetejká a nepřepisuje proměnné.
Proč ten zásobník vlastně chceš zvětšit, když ani nevíš, jak je velký?
Tj. pokud mám takto reservovaný stack a pokusím se jej "překrýt" jinou proměnnou.
Zpět však k tvé otázce proč...
Main() -> funkce1() -> funkce2() -> funkce3() -> funkce4()
Z funkce3 se nevracel do funkce2 ale na náhodné místo v programu.
Problém jsem však již nalezl.
Nebylo to velikostí stacku ani mi do něj přímo nezasahovala nějaká proměnná.
Já (ani původní autor mnou přebraného programu) si neuvědomil,
že parametry funkcí se také uchovávají ve stacku.
No a právě v té funkci3 se měnil (vypočítával) vlastní parametr.
Dál už si jen domýšlím, že během výpočtu pravděpodobně docházelo
k přetečení proměnné a tím zasahoval do návratové adresy.
Jakmile jsem tento zádrhel vyřešil, tak najednou vše funguje bez problémů.
Kód: Vybrat vše
.EQU SPCNT =0x10 ;Velikost Stacku
.DSEG
.ORG RAMEND-SPCNT ;Na konec paměti
STACK: .BYTE SPCNT ;reservuj paměť pro Stack
V podstatě tím překladači sdělím, že tato paměť je vyhrazena,
Tímto postupem jsi rezervoval posledních 16 bajtů v RAM pro proměnnou nazvanou "STACK", která ale s opravdovým stackem nemá nic společného.
Na začátku programu většinou nastavujeme stack_pointer na konec RAM.
Stack se postupně zaplňuje od konce RAM směrem dolů, k nižším adresám. Toto zaplňování není ničím omezené, takže stack má k dispozici celou RAM.
Větší prostor už nemůže mít, takže se nedá nijak "zvětšit".
Ale v RAM jsou také globální proměnné. Ty se naopak ukládají od začátku RAM směrem nahoru, k vyšším adresám. Tyto dvě věci (proměnné a stack) do sebe nesmí narazit, jinak se začnou vzájemně přepisovat.
Není obtížné zjistit velikost oblasti RAM obsazené proměnnými.
Horší je to se stackem. Překladač (Avr-gcc) neví v době překladu kam až může stack při běhu programu zasáhnout. Takže odpovědnost je na programátorovi.
Doporučuje se např. aby globální proměnné nezabíraly víc než asi 70% RAM.
Přednostně používat lokální proměnné.
Funkce, které jsou v kódu použity jen jednou deklarovat jako inline.
Existuje metoda, při které se na úplném začátku programu vyplní celá RAM nějakými znaky, třeba 'A'. Při simulaci pak jsou tyto znaky přepisovány proměnnými a stackem. Sledujeme obsah RAM a vidíme mezeru mezi proměnnými a stackem jako řadu těchto znaků. Pokud stack zasáhne do proměnných, znaky zmizí.
- ZdenekHQ
- Významný člen
- Příspěvky: 25519
- Registrován: 21 črc 2006, 00:00
- Bydliště: skoro Brno
- Kontaktovat uživatele:
Správně navržené zapojení je jako recept na dobré jídlo.
Můžete vynechat půlku ingrediencí, nebo přidat jiné,
ale jste si jistí, že vám to bude chutnat[?]
AB1 píše:Tímto postupem jsi rezervoval posledních 16 bajtů v RAM pro proměnnou nazvanou "STACK", která ale s opravdovým stackem nemá nic společného.
Všimni si však, že jsem je rezervoval na konci paměti, tj. přesně tam,
kde se stack nachází.
Samozřejmě tím nezabráním ,aby stack přetekl mimo toto vymezení,
ani to nezabrání aby se mi do této oblasti nezasáhla nějaká dynamická proměnná.
Bude mi však hlásit v případě, když už budu mít zbytek paměti zaplácaný
statickými proměnnýma a pokusím se tam vecpat "ještě jednu navíc".
Ve většině případů to není potřeba,
ale dvakrát či třikrát jsem vyvíjel paměťově náročný program,
a tam mi to bylo docela vhod.
Pro jistotu tuto reservaci paměti pro stack používám pokaždé.
Ničemu to nevadí a může jen pomoci.
A v podstatě něco takového jsem chtěl i v Céčku.
Prostě dát překladači najevo, aby počítal s větším nárokem na stack
a necpal tam statické proměnné.
A v podstatě něco takového jsem chtěl i v Céčku.
Prostě dát překladači najevo, aby počítal s větším nárokem na stack
a necpal tam statické proměnné.
Zkusím to jinak:
V AvrStudiu v okně "Build" vidíš po překladu kolik ramky zabírají proměnné.
Celý zbytek RAM může použít stack.
Na obrázku je příklad.
V řádku "Data" vidíme kolik místa zabírají deklarované globální a statické lokální proměnné. Zde 425 bajtů (41.5% RAM).
RAM má 1024 bajtů.
Takže stack může použít 1024-425 = 599 bajtů.
Neboli velikost stacku je 599 bajtů.
Z toho je zřejmé, že zvětšit stack můžeš jen tím, že ubereš proměnných.
Mimochodem, kolik procent zabírají proměnné v tom programu, který měl problémy se stackem?
- Přílohy
-
build.gif- (10.46 KiB) Staženo 109 x
Jestli mohu...
-Z(DATA)RSTACK+40=E0-11F
Princip je takový,že než se spustí program C funkcí main,proběhne tzv. startup program(assemblerovský),který je výrobcem kompilátoru dodán do zdrojového textu a objektového kódu.Ten program se jmenuje cstartup.s90.Celé ti to tu nemohu popsat,dávám odkaz na knihu v pdf,můžeš si ji stahnout a tam se dočteš víc,od str.143
http://www.edisk.sk/stahni/82334/C_pro_ ... 9.6MB.html
....klikni na pomalé stažení,ať se nemusíš registrovat:-)...