2012-03-29 14 views
5

In gcc doc jeden powód jest podany przy użyciu section.To jest powód to map to special hardware. Ale wydaje się, że nie moja sprawa:
Co może być przyczyną umieszczenia zmiennej dokładnie w sekcji "STACK" z __attribute__ ((sekcja ("STACK"))?

Tak więc podjąłem zadanie modyfikacji biblioteki współdzielonej, której używamy w naszym projekcie.Jest to biblioteka systemu Linux.Biblioteczki, które mnie puzzelują, zawierają zmienne deklaracje, które wyglądają tak (w przybliżeniu):

static int my_var_1 __attribute__((section("STACK"))) = 0; 


aktualizacji 1:
Istnieje kilkanaście zmiennych zdefiniowanych w ten sposób ( __attribute__((section("STACK"))))



Aktualizacja 2:
my_var_1 nie jest stała. my_var_1 może być zmieniona w kodzie podczas inicjalizacji:

my_var_1 = atoi(getenv("MY_VAR_1") ? getenv("MY_VAR_1") : "0"); 

później w bibliotece jest używany tak:

inline void do_something() __attribute__((always_inline)); 
inline void do_something() 
{ 
    if (my_var_1) 
    do_something_else(); 
} 


Co może być punktem w użyciu __attribute__((section("STACK")))? Rozumiem, że section mówi kompilatorowi, aby umieścić zmienną w konkretnej sekcji. Jednak jaki może być sens umieszczenia static int dokładnie w sekcji "STACK"?


Update 3
Linie te są fragmentem wyjściu z readelf -t my_lib.so

[23] .got.plt 
     PROGBITS   00000000002103f0 00000000000103f0 0 
     00000000000003a8 0000000000000008 0     8 
     [0000000000000003]: WRITE, ALLOC 
    [24] .data 
     PROGBITS   00000000002107a0 00000000000107a0 0 
     00000000000000b0 0000000000000000 0     16 
     [0000000000000003]: WRITE, ALLOC 
    [25] STACK 
     PROGBITS   0000000000210860 0000000000010860 0 
     00000000000860e0 0000000000000000 0     32 
     [0000000000000003]: WRITE, ALLOC 
    [26] .bss 
     NOBITS   0000000000296940 0000000000096940 0 
     0000000000000580 0000000000000000 0     32 
     [0000000000000003]: WRITE, ALLOC 


Update 4
udało się uzyskać informacje od autora udostępnionej biblioteki . __attribute__((section("STACK"))) został dodany, ponieważ nie udało mu się zbudować biblioteki w systemie Solaris. Potem znalazł to obejście. Przed obejście definicja my_var_1 było jak:

int my_var_1 = 0; 

i wszystko było OK. Potem zmienił go od my_var_1 był w rzeczywistości potrzebna tylko w tej jednostce Tłumaczenie:

static int my_var_1 = 0; 

A po takiej zmianie, że nie udało się zbudować bibliotekę w systemie Solaris. Więc dodał __attribute__((section("STACK"))) i jakoś pomógł.


+0

Czy Twój projekt działa na zwykłym komputerze z procesorem x86, czy jest to coś w rodzaju systemu ARM na chipie (SoC)? Czy możesz znaleźć skrypt linkera (używany przez ld, a więc zwykle kończy się na ".ld")? To jednoznacznie umieści sekcję STACK w obszarze pamięci, więc znalezienie skryptu linkera da więcej wskazówek. – gbulmer

+0

Program jest używany na zwykłych serwerach x64_86 i na HP-UX Itanium2. Brak systemów ARM. –

+0

może być warte dodania informacji o maszynach na twoje pytanie. Mogę sobie wyobrazić, że Itanium2 _might_ uruchamia coś (wiem bardzo mało o tym, ale jest inaczej :-) – gbulmer

Odpowiedz

5

Pierwsza sekcja STACK nie będzie stosem żadnego uruchomionego zadania.

Umieszczenie zmiennych, funkcji w określonej sekcji pozwala wybrać dla nich obszar pamięci (dzięki skryptowi linkera). W niektórych (głównie osadzonych) architekturach chcesz umieścić często dostępne dane w szybszej pamięci.

Inne rozwiązanie, niektóre po opracowaniu skryptu post-link ustawi wszystkie części STACK na 1: program programistyczny zawsze będzie robił do_something_else(). A zwolnione oprogramowanie może zachować domyślną wartość 0.

Inna możliwość, jeśli istnieją inne zmienne w sekcji STACK, programista chce trzymać je blisko w pamięci. Wszystkie zmienne w sekcji STACK będą znajdować się blisko siebie. Może optymalizacja pamięci podręcznej?

+0

Edytowałem moje pytanie (Update 2), aby być jasnym co do twojej sugestii 'Inne rozwiązanie, jakiś rozwojowy skrypt po linku. ..'. Przepraszam, powinienem był wspomnieć, że 'my_var_1 nie jest stałą'. –

+0

@skwllsp czy istnieje skrypt linkera? Bez skryptu linkera sekcja pomoże tylko pogrupować wszystkie zmienne w tym samym obszarze. 'readelf -t your.so' może podać informację, gdzie znajduje się sekcja' STACK'. – Nimlar

+0

Nie, nie ma skryptu linkera. –

1

Może być wiele przyczyn i trudno powiedzieć, bez szczegółów. Niektóre z powodów może być:

  1. fragmentu zaznaczonego Stos jest połączony w okresie czasu na ściśle sprzężoną pamięć o skrócenie czasu dostępu, a następnie inny RAM. Sensowne jest mapowanie stosu do takiej pamięci RAM, aby uniknąć przeciągnięć podczas wywoływania funkcji. Teraz, jeśli nagle masz zmienną, która jest często dostępna i chcesz ją zmapować do tej samej pamięci RAM o szybkim dostępie, umieszczając ją w tej samej sekcji, co stos ma sens.

  2. Sekcja oznaczona STACK może być mapowana na region pamięci dostępny, gdy inne części pamięci mogą nie być. Na przykład programy ładujące system rozruchowy muszą zainicjować kontroler pamięci, zanim będą mogły uzyskać dostęp do pamięci RAM. Ale naprawdę chcesz móc napisać kod, który robi to w C, co wymaga stosu. Znajdujesz więc specjalną pamięć (taką jak programowanie pamięci podręcznej danych do trybu zapisu) i mapujesz tam stos, dzięki czemu możesz uruchomić kod, aby uruchomić kontroler pamięci, abyś mógł korzystać z pamięci RAM. Jeszcze raz, jeśli zdarzy ci się, że masz zmienną globalną, która wciąż musi być dostępna przed udostępnieniem pamięci RAM, możesz zdecydować, aby umieścić ją w sekcji STOSOWANIE.

Lepszy programista zmieniłby nazwę sekcji STOSOWANIE na coś innego, jeśli jest używany nie tylko do stosu.

0

W niektórych systemach operacyjnych ten sam obszar przestrzeni adresowej jest używany dla każdego stosu wątku; gdy wykonywanie przełącza się między wątkami, mapowanie tej przestrzeni jest odpowiednio zmieniane. W takich systemach każdy wątek będzie miał własny, niezależny zestaw dowolnych zmiennych statycznych znajdujących się w tym obszarze przestrzeni adresowej. Umieszczenie zmiennych, które należy utrzymywać osobno dla każdego wątku w takim zakresie adresów, pozwoli uniknąć konieczności ręcznego ich zamiany przy każdym przełączniku zadań.

Innym sporadycznym użyciem wymuszania zmiennych w obszarze stosu jest dodanie wartowników stosu (zmiennych, które mogą być okresowo sprawdzane, aby zobaczyć, czy przepełnienie stosu je zatarasowało).

Trzecie zastosowanie ma miejsce na platformach 8086 i 80286 (prawdopodobnie nie tyle później w rodzinie): 8086 i 80286 są ograniczone do efektywnego dostępu do rzeczy w czterech segmentach bez konieczności ponownego ładowania rejestrów segmentów. Jeśli kod musi zrobić coś, co odpowiada

for (n=0; n<256; n++) 
    *dest++ = xlat[*src++]; 

i żaden z elementów można umieścić w segmencie kodu, jest w stanie wymusić jedną z pozycji w segmencie stosu można dokonać kod znacznie szybciej. Odręczny kod montażu byłby wymagany, aby osiągnąć przyspieszenie, ale może być bardzo masywny (prawie dwumianowy w niektórych rzeczywistych sytuacjach, które zrobiłem w 8086, a może nawet większy w niektórych sytuacjach na 80286).

Powiązane problemy