Minimalne uruchamialne przykłady w systemie Linux z analizą dezasemblacji
Ponieważ jest to szczegół implementacji, który nie jest określony przez standardy, przyjrzyjmy się tylko, co kompilator robi w określonej implementacji.
W tej odpowiedzi albo podam link do konkretnych odpowiedzi, które wykonują analizę, albo przedstawię analizę bezpośrednio tutaj i podsumuję wszystkie wyniki tutaj.
Wszystkie są w różnych wersjach Ubuntu / GCC, a wyniki są prawdopodobnie dość stabilne we wszystkich wersjach, ale jeśli znajdziemy jakieś różnice, określmy bardziej precyzyjne wersje.
Zmienna lokalna wewnątrz funkcji
Czy to mainczy jakakolwiek inna funkcja:
void f(void) {
int my_local_var;
}
Jak pokazano na: Co oznacza <wartość zoptymalizowana na zewnątrz> w gdb?
-O0: stos
-O3: rejestruje, jeśli się nie rozlewają, stosuj inaczej
Aby dowiedzieć się, dlaczego stos istnieje, zobacz: Jaka jest funkcja instrukcji push / pop używanych w rejestrach w asemblerze x86?
Zmienne globalne i staticzmienne funkcyjne
/* BSS */
int my_global_implicit;
int my_global_implicit_explicit_0 = 0;
/* DATA */
int my_global_implicit_explicit_1 = 1;
void f(void) {
/* BSS */
static int my_static_local_var_implicit;
static int my_static_local_var_explicit_0 = 0;
/* DATA */
static int my_static_local_var_explicit_1 = 1;
}
char * i char c[]
Jak pokazano na: Gdzie są przechowywane zmienne statyczne w C i C ++?
void f(void) {
/* RODATA / TEXT */
char *a = "abc";
/* Stack. */
char b[] = "abc";
char c[] = {'a', 'b', 'c', '\0'};
}
DO ZROBIENIA, czy na stosie zostaną również umieszczone bardzo duże literały ciągów? Albo .data? A może kompilacja się nie udaje?
Argumenty funkcji
void f(int i, int j);
Musi przejść przez odpowiednią konwencję telefoniczną, np .: https://en.wikipedia.org/wiki/X86_calling_conventions dla X86, która określa konkretne rejestry lub lokalizacje stosu dla każdej zmiennej.
Następnie, jak pokazano w Co oznacza <wartość zoptymalizowana na zewnątrz> w gdb? , -O0a następnie wysysa wszystko do stosu, -O3próbując jednocześnie używać rejestrów tak często, jak to możliwe.
Jeśli jednak funkcja zostanie wstawiona, są traktowani tak, jak zwykli lokalni.
const
Uważam, że nie ma to znaczenia, ponieważ można to odrzucić.
I odwrotnie, jeśli kompilator jest w stanie określić, że niektóre dane nigdy nie są zapisywane, teoretycznie mógłby umieścić je w, .rodatanawet jeśli nie jest to const.
Analiza TODO.
Wskaźniki
Są to zmienne (zawierające adresy, które są liczbami), tak samo jak cała reszta :-)
malloc
Pytanie nie ma większego sensu malloc, ponieważ mallocjest funkcją, a w:
int *i = malloc(sizeof(int));
*i jest zmienną, która zawiera adres, więc przypada na powyższy przypadek.
Jeśli chodzi o to, jak malloc działa wewnętrznie, kiedy to nazywasz, jądro Linuksa oznacza określone adresy jako zapisywalne w swoich wewnętrznych strukturach danych, a kiedy program dotyka ich początkowo, pojawia się błąd i jądro włącza tabele stron, co umożliwia dostęp dzieje się bez segfaul: Jak działa stronicowanie x86?
Zauważ jednak, że jest to w zasadzie dokładnie to, co execwywołanie systemowe robi pod maską, kiedy próbujesz uruchomić plik wykonywalny: zaznacza strony, na które chce załadować, i zapisuje tam program, zobacz także: Jak jądro pobiera wykonywalny plik binarny działający pod linux? Z wyjątkiem tego, że execma pewne dodatkowe ograniczenia dotyczące miejsca, do którego należy załadować (np. Czy kodu nie można przenieść ).
Dokładne wywołanie systemowe używane mallocjest mmapwe współczesnych implementacjach 2020, a w przeszłości brkbyło używane: Czy malloc () używa brk () lub mmap ()?
Biblioteki dynamiczne
Zasadniczo pobierz się mmapdo pamięci: /unix/226524/what-system-call-is-used-to-load-libraries-in-linux/462710#462710
envinroment zmienne i mainsargv
Powyższy stos początkowy: /unix/75939/where-is-the-environment-string-actual-stored TODO, czemu nie w .data?