2012-06-24 15 views
6

Czy jest jakiś sposób, aby powiedzieć GCC, aby nie zainicjować konkretnej globalnej tablicy do zera?Wymuś GCC aby zrezygnować z niektórych globali

Chcę zarezerwować sporą część pamięci na przechowywanie dużej struktury danych, że mój kod zarządza, więc mówię:

#define SIZE_16_MB 0x01000000 
BYTE mChunkSpace[SIZE_16_MB]; 

Problemem jest to, że crtinit() trwa miliony lat, aby zainicjować tę przestrzeń do zera, a to wcale nie jest konieczne.

Czy mogę go wymusić, aby nie zainicjować tego miejsca?

Obecnie trudniej jest kodować adres pamięci, który znajduje się poza linkiem, który zna linker, ale nie jest to szczególnie solidny sposób robienia rzeczy.

Dodatkowo jest to powolny proces wbudowany (mikroblazę 50 MHz), więc nie zakładaj, że mówię o komputerze. Zerowanie tej przestrzeni zajmuje naprawdę dużo czasu.

Odpowiedz

6

Można użyć atrybutów gcc do przechowywania obiektu w innej nowej sekcji pamięci, na przykład w sekcji pamięci .noinit.

BYTE mChunkSpace[SIZE_16_MB] __attribute__ ((section (".noinit"))); 
+0

Natknęłam się na to samo, ale trudno mi było dokładnie określić, w jaki sposób jest on realizowany i czy byłby dostępny dla OP na swojej docelowej platformie. Z tego co wiem, sekcja '.noinit' jest tworzona w sekcji' .bss'. Czy to znaczy, że nie jest zero inicjalizowane * i * nie zajmuje ~ 16MB przestrzeni w pliku wykonywalnym? –

+0

@EdS. "size -A -x" pokazuje mi, że adresy sekcji pamięci są inne niż adresy sekcji '.bss'. – ouah

+0

Powtarzam to, co przeczytałem tutaj: http://www.nongnu.org/avr-libc/user-manual/mem_sections.html –

-2

Standard stwierdza, że ​​dane statyczne, które nie zostały jawnie zainicjowane w punkcie deklaracji, zostaną zainicjowane zerowo. Można uniknąć inicjalizacji wykonania przez inicjowanie pierwszego elementu na wartość niezerową siebie:

#define SIZE_16_MB 0x01000000 
BYTE mChunkSpace[SIZE_16_MB] = {1}; 

zauważyć, że jeśli podasz 0, kompilator będzie prawdopodobnie tylko przechowywać go w sekcji .bss tak, to znaczy, że będzie nadal być inicjowane w czasie wykonywania. Nie musi tego robić, ale byłoby głupio. Teraz twoja tablica zostaje wrzucona do segmentu .data.

Oczywiście spowoduje to, że wypadkowy plik wykonywalny będzie znacznie większy (~ 16MB większy, aby być dokładnym), ale pamięć nie zostanie zainicjalizowana w czasie wykonywania. Więc pytanie sprowadza się do tego, co macie do ciebie; czas potrzebny na wyzerowanie pamięci lub wynikowy rozmiar pliku wykonywalnego?

+0

Przepraszam za ten niekonstruktywny komentarz - nie mam dobrego rozwiązania, prawie zasugerowałem zrobienie 'mChunkSpace' lokalną z' main() ', jako żartu, ale jest mało prawdopodobne, aby działało w praktyce. W każdym razie, gdy powiesz "ale pamięć nie zostanie zainicjalizowana w czasie wykonywania": zamiast tego zostanie ona załadowana ze stałego magazynu. To raczej nie będzie szybsze. –

+1

Możesz kontrolować, czy gcc umieszcza zmienne z inicjalizacją zerową w .bss z opcją -f [no-] zero-initialized-in-bss. Wartością domyślną jest -fzero-initialized-in-bss –

+0

@PascalCuoq: Prawie nie-konstruktywny! Myślę, że jest to bardzo konstruktywne, ponieważ w ogóle o tym nie myślałem. –

4

Spróbuj dynamicznej inicjalizacji:

BYTE* mChunkSpace = (BYTE*)malloc(SIZE_16_MB * sizeof(BYTE)); 

Następnie dane te są niezainicjowany i czeka, aby go zainicjować.

+0

To dobre rozwiązanie, ale oznaczałoby to, że mój segment sterty byłby o wiele większy. Może to być OK, jeśli nie ma wpływu na wydajność sterty w innych kontekstach. – NXT

0

Czy rzeczywiście pomyślałem, że pamięć niestatyczna jest domyślnie niezainicjowana na zero?

+1

Obiekty zdefiniowane w zasięgu pliku mają stały czas przechowywania, więc są inicjowane do zera. – ouah

+0

To wcale nie jest prawdą (czy jest to pytanie czy stwierdzenie?). Czy wierzysz, że 'i' jest inicjowane na' 0' w poniższym kodzie?'int main() {int i; return 0; } ' –

+0

Przypuszczam, że mogę * umieścić * na stosie i umieścić na nim wskaźnik w postaci globalnej, ale to naprawdę wydaje się nadużyciem stosu. :-) – NXT

2

Większość odpowiedzi, które otrzymasz na SO, będzie pochylona w stronę Visual Studio lub GCC, zarówno na platformach ogólnego przeznaczenia (np. Komputerach PC, systemach Windows i Linux), i będzie ciężka na "standard mówi .. . "Cytowań, z których żadna nie ma zastosowania dla małych systemów wbudowanych, chyba że działasz z wbudowanym systemem Linux lub Windows CE.

Odpowiedź ouah jest prawdopodobnie najbliższa temu, czego potrzebujesz ... być może DOKŁADNIE tego, czego potrzebujesz, jeśli naprawdę używasz GCC. Ponieważ fragment pamięci, który chcesz, jest tak duży, prawdopodobnie zużywa lwią część pamięci twojego systemu, najlepiej jest zdefiniować specjalną sekcję w pliku poleceń linkera twojej kompilacji lub dyrektywami łącznika w pliku C, C++ lub złożeniu . Składnia tego będzie różnić się w zależności od kompilatora. Jeśli użyjesz dyrektyw łącznika w pliku źródłowym/złożeniowym, prawdopodobnie będziesz musiał określić atrybuty dotyczące zdolności odczytu/zapisu w regionie pamięci itp. ...a może nie, jeśli mikroblaza nie ma MMU/kontrolera pamięci. Będziesz musiał umieścić symbol linkera na początku sekcji, a także w swoim kodzie C, używając dyrektywy "external char symName []", aby Twój kod C mógł kompilować się w relocs, które linker zastąpi rzeczywistym adresem Sekcja. W zależności od kompilatora i architektury, może być również konieczne zadeklarowanie nazwy elementu symName [] z jakimś atrybutem "daleko"; Nie wiem wystarczająco dużo o Microblaze, żeby cokolwiek o tym powiedzieć.

Powiązane problemy