AVR gcc .bss .heap i stos

Jun 21, 2012 14 Replies

Czy jakieś nieświadome użycie, zadeklarowanie zmiennej lokalnej np. float w funkcji może prowadzić do używania obszaru poniżej stosu i powyżej .bss czyli heap? Z pliku .map niewiele widać.



.bss kończy się 0x733 stos na 0x800 podglądany stack pointer schodzni najniżej do 0x795



Czyli pomiędzy 0x733 a 0x795 jest teoretycznie heap ale wzmianki o tym w pliku map nie ma. No ale stos mi nachodzi czasem na zmienne. Jak zmniejszę bufor[512] o kilkadziesiąt to się uspokaja. Co można zrobić ? Skąd wiadomo czy heap jest używany? I co się dzieje w tym obszarze? Z wyliczeń jest miejsce. Wstawiam pułapki w różne miejsca kodu i czytam ile wynosi aktualnie SP i nie ma siły, nie spotykają się. A jednak się kwasi.



.bss .... ....



0x008005f3 RXVAL


0x008005f5 V_TEST


0x008005f7 PROVIDE (__bss_end, .)


0x00006d76 __data_load_start = LOADADDR (.data)


0x00006d76 __data_load_end = (__data_load_start + SIZEOF (.data))

.noinit 0x008005f7 0x13d


0x008005f7 PROVIDE (__noinit_start, .)


*(.noinit*)



.noinit 0x008005f7 0x13d main.o


0x008005f7 my_bufer


0x00800733 my_noinit


0x00800734 PROVIDE (__noinit_end, .)


0x00800734 _end = .


0x00800734 PROVIDE (__heap_start, .)

.eeprom 0x00810000 0x0


*(.eeprom*)


0x00810000 __eeprom_end = .


Te zmienne będą alokowane na stosie i na bieżąco zwalniane, więc nie.

W .map są tylko statyczne rzeczy.

Wstaw pułapki przy zapisie do pamięci. Można też postawić pułapki na fragmentach kodu (wywołania funkcji) i drogą eliminacji dojść, która bruździ (w podglądzie pamięci widać, które obszary zostały zmienione). Może to niekoniecznie stos, a np. wskaźniki. Poza tym jeszcze są przerwania. Miałem kiedyś ten sam problem i się nie udało dojść do źródła, a najgorsze było to, że potrafiło poprawnie działać przez kilkanaście godzin. Skończyło się na zmniejszeniu zapotrzebowania na RAM. Tu chyba winna była zewnętrzna dość duża biblioteka (CanFestival).

W³a¶nie to zauwa¿y³em . Tak mam. Jak trochê przyoszczêdzi³em na tablicach - dos³ownie wczoraj- to zaraz mu przesz³o. Ale jasnego powodu nie ma. Przynajmniej je¶li chodzi o wyliczenia i obecno¶æ heap. Natomiast heap mi siê pojawia gdy napiszê:

__malloc_margin = 32;

to pojawiaj± sie w ramie zmienne 3 sztuki 16 bitowe od adresu 0x60 wskazuj±ce na ten margin, pocz±tek i koniec heapu.

A internet przepisuje tylko jeden za drugim i nikt nic nie wyja¶nia tylko kopiuj± info z libc. Mo¿e kto¶ ma pojêcie jak ten margin dzia³a i czemu go nie ma bez zadeklarowania chocia¿ podobno defaultowy to 32 ??? To jest heap czy nie ma bez tej deklaracji? Ja niby rozumiem ideê ale gdy nagle wyskoczy przerwanie mimo marginesu 32 i pusznie 32 rejestry plus jeszcze kilka skoków to jest szansa, ¿e stos nadpisze heap.

  1. Przydzielenie jakiegos obszaru pamięci na stos nie oznacza iż przekroczenia jego rozmiaru nie nastapi (chyba, że w prologu wywoływanej funkcji jest kontrolowana granica stosu).
  2. Typowa sytuacja dla embedded : wywoływanie funkcji rekurencyjnie szybko spowoduje przekroczenie stosu. Alokowanie agregatów na stosie, np. tablic lub głebokie drzewo wywołań funkcji (odkładanie kontekstu na stosie) spowoduje przekroczenie stosu.
  3. Kompilator sie nie myli. Wszystkie zmienne statyczne znajdą sie w odpowienich sekcjach tj. .bbs lub .data a automatyczne na stosie. Przyczyna opisywanego powyżej stanu rzeczy jest zwykle przekroczenie stosu (patrz punkt 2), "urwany" wskażnik itp. (...)

Nie wiem jak w Twoim przypadku ale widziałem taka implementacje : adres stosu był przypisany w skrypcie lnikera do końca pamięci i obszar między końsem bss-ów a końcem RAM był stosem. I tu nastepował wielkie ździwienie iz program sie wywraca a po zmniejszeniu jakis tablic działa. Przecież mniejszy rozmiar na dane to wiekszy stos.

Oszacować niezbedny rozmiar stosu, np. tak (przykład dla architektury ARM) :

// A minimal, optimized stack frame, rounded up - no autos #define CYGNUM_HAL_STACK_FRAME_SIZE (4 * 20)

// Stack needed for a context switch: this is implicit in the estimate for // interrupts so not explicitly used below: #define CYGNUM_HAL_STACK_CONTEXT_SIZE (4 * 20)

// Interrupt + call to ISR, interrupt_end() and the DSR #define CYGNUM_HAL_STACK_INTERRUPT_SIZE \ ((4 * 20) + 2 * CYGNUM_HAL_STACK_FRAME_SIZE)

// Space for the maximum number of nested interrupts, plus room to call functions #define CYGNUM_HAL_MAX_INTERRUPT_NESTING 4

#define CYGNUM_HAL_STACK_SIZE_MINIMUM \ (CYGNUM_HAL_MAX_INTERRUPT_NESTING * CYGNUM_HAL_STACK_INTERRUPT_SIZE

  • \ 2 * CYGNUM_HAL_STACK_FRAME_SIZE)

#define CYGNUM_HAL_STACK_SIZE_TYPICAL \ (CYGNUM_HAL_STACK_SIZE_MINIMUM + \ 16 * CYGNUM_HAL_STACK_FRAME_SIZE)

Należy expicite wywołać funkcje typu *alloc() lub impicite przez uzycie bibliteki wymagającej dynamicznej alokacji pamięci.

Alokator rezerwuje porcje pamięci i zwraca wskaźnik do niej.

nie ma siły, nie spotykają się. A jednak się kwasi. Nie tak. Stos oraz obszar ponizej (jesli nic tam nie ma) nalezy zainicjować wzorcem typu 0xaa55aa55 a nastepnie sprawdzić czy rzeczony wzorzec nie został całkowicie zamazany zmiennymi - podczas normalnej pracy odkładane zmienne NIGDY nie powinny przekroczyc dolnej granicy stosu.

Napisałeś dużo ciekawych rzeczy ale powiedz mi skąd mam wiedzieć czy nie używam bibliteki wymagającej dynamicznej alokacji pamięci ? Używam zmiennego przecinka, memcpy, memcmp. Alloców expicitenie używam, niczego takiego co trzeba by później zwalniać. Nie wiem co libc czy libm wyprawia. Do czasu aż był ram nie zastanawiałem się nad tym :-)

Teraz troszkę wywaliłem, użyłem też -mrelax i troszkę stos mniej zajmuje bo branches relaxation. Jednak zamiana tych call na rcall przy nested callach pomogło. Teraz sie nie wali. Ale to walenie się było takie subtelnie perfidne :-) Nikt tego nie zauważył :-)

To sa podstawy.

dynamicznej alokacji pamięci ? Z dokumentacji oraz zrodel.

(..)

Jak wyzej.

Chyba raczej zmniejszenie rozmiaru kodu : -mrelax Enable linker relaxation. Linker relaxation is a process whereby the linker will attempt to reduce the size of a program by finding shorter versions of various instructions. Disabled by default.

Można też poszukać symboli z grupy .*brk.* czy po prostu malloc.

Użytkownik "Profesor" napisał w wiadomości grup

No bo to dynamicznie uzywane. Zobacz opcje kompilatora - byc moze da sie wlaczyc kontrole stosu .. ale to dziala tylko w normalnych funkcjach, a jeszcze sa przerwania.

Na gccavr sie nie znam, ale w C czesto wlasnie heap zapelnia z jednej strony, a stos z drugiej.

Moze jakis maxmem da sie ustawic i moze jakas funkcja grzecznie zglosi ze pamieci nie moze zaalokowac.

Jeszcze mozesz ten obszar wypelnic jakas stala zawartoscia, a po przebiegu programu zobaczyc w jakim obszarze zawartosc pozostala nienaruszona.

J.

Już wiadomo. Stos był od dawien dawna ustawiony na 0x800 zamiast na 0x85F :-) Brakowało mi tych ~100 bajtów :-)

Join the Discussion

Have something to add? Share your thoughts — no account required.

Didn't find your answer?

Ask the community — no account required