C pobiera główne argumenty funkcji. Główne argumenty funkcji. Używanie argumentów wiersza poleceń
Czasami przy uruchamianiu programu warto przekazać mu pewne informacje. Zwykle informacje te są przekazywane do funkcji main() za pośrednictwem argumentów wiersza poleceń. Argument wiersza poleceń to informacja wprowadzana w wierszu poleceń systemu operacyjnego po nazwie programu. Na przykład, aby rozpocząć kompilację programu, po znaku zachęty w wierszu poleceń należy wpisać coś podobnego do poniższego:
Dw Nazwa programu
Nazwa programu jest argumentem wiersza poleceń; określa nazwę programu, który zamierzasz skompilować.
Aby zaakceptować argumenty wiersza poleceń, używane są dwa specjalne wbudowane argumenty: argc i argv. Parametr argc zawiera liczbę argumentów w wierszu poleceń i jest liczbą całkowitą, przy czym zawsze wynosi co najmniej 1, ponieważ pierwszym argumentem jest nazwa programu. Parametr argv jest wskaźnikiem do tablicy wskaźników do ciągów znaków. W tej tablicy każdy element wskazuje na argument wiersza poleceń. Wszystkie argumenty wiersza poleceń są ciągami znaków, więc konwersja dowolnych liczb na żądany format binarny musi być zapewniona w programie podczas jego tworzenia.
Oto prosty przykład użycia argumentu wiersza poleceń. Na ekranie zostanie wyświetlone słowo Hello i Twoje imię, które należy podać jako argument wiersza poleceń.
#włączać
Jeśli nazwałeś ten program nazwą (nazwą) i masz na imię Tomek, to aby uruchomić program powinieneś wpisać nazwę Tom w wierszu poleceń. W wyniku uruchomienia programu na ekranie pojawi się komunikat Witaj, Tomku.
W wielu środowiskach wszystkie argumenty wiersza poleceń muszą być oddzielone spacją lub tabulatorem. Przecinki, średniki i podobne znaki nie są uważane za ograniczniki. Na przykład,
Biegnij Spot, biegnij
składa się z trzech ciągów znaków, natomiast
Eryk, Rick, Fred
reprezentuje pojedynczy ciąg znaków - przecinki z reguły nie są uważane za ograniczniki.
Jeśli ciąg zawiera spacje, w niektórych środowiskach można go ująć w cudzysłów, aby zapobiec tworzeniu wielu argumentów. W rezultacie cały ciąg zostanie uznany za jeden argument. Aby dowiedzieć się więcej o tym, jak system operacyjny ustawia parametry wiersza poleceń, przejrzyj dokumentację systemu operacyjnego.
Bardzo ważne jest prawidłowe zadeklarowanie argv. Oto jak najczęściej się to robi:
Char *argv;
Puste nawiasy kwadratowe wskazują, że tablica ma nieokreśloną długość. Dostęp do poszczególnych argumentów można teraz uzyskać poprzez indeksowanie tablicy argv. Na przykład argv wskazuje na pierwszy ciąg znaków, który zawsze jest nazwą programu; argv wskazuje na pierwszy argument i tak dalej.
Innym małym przykładem użycia argumentów wiersza poleceń jest następujący program odliczający. Program ten liczy wstecz, zaczynając od pewnej wartości (określonej w wierszu poleceń) i wydaje sygnał dźwiękowy, gdy osiągnie 0. Należy zauważyć, że pierwszy argument, zawierający wartość początkową, jest konwertowany na wartość całkowitą przy użyciu standardowej funkcji atoi (). Jeżeli drugim argumentem linii poleceń (a jeśli jako argument potraktujemy nazwę programu, to trzecim) będzie linia „display” (display), wówczas na ekranie zostanie wyświetlony wynik zliczenia (w odwrotnej kolejności).
/* Program do liczenia w odwrotnej kolejności. */ #włączać
Należy pamiętać, że jeśli argumenty wiersza poleceń nie zostaną określone, zostanie wyświetlony komunikat o błędzie. Programy pobierające argumenty wiersza poleceń często wykonują następujące czynności: Kiedy użytkownik uruchamia te programy bez wprowadzenia wymaganych informacji, wyświetlają instrukcje dotyczące prawidłowego określania argumentów.
Aby uzyskać dostęp do pojedynczego znaku jednego z argumentów wiersza poleceń, wprowadź drugi indeks w argv. Na przykład następujący program wypisuje znak po znaku wszystkie argumenty, z którymi został wywołany:
#włączać Pamiętaj, że pierwszy indeks argv zapewnia dostęp do ciągu, a drugi indeks zapewnia dostęp do jego poszczególnych znaków. Zwykle argc i argv służą do wydawania programowi początkowych poleceń, których będzie potrzebował podczas uruchamiania. Na przykład argumenty wiersza poleceń często określają informacje, takie jak nazwa pliku, opcja lub alternatywne zachowanie. Używanie argumentów wiersza poleceń nadaje programowi „profesjonalny wygląd” i ułatwia jego użycie w plikach wsadowych. Nazwy argc i argv są tradycyjne, ale nie wymagane. Możesz wywołać te dwa parametry w funkcji main(), jakkolwiek chcesz. Ponadto niektóre kompilatory mogą obsługiwać dodatkowe argumenty funkcji main(), dlatego należy sprawdzić dokumentację kompilatora. Jeśli program nie wymaga parametrów wiersza poleceń, najczęściej jawnie deklaruje się funkcję main() jako nie posiadającą parametrów. W tym przypadku na liście parametrów tej funkcji używane jest słowo kluczowe void. Tagi: Opcje wiersza poleceń C jest językiem skompilowanym. Po złożeniu program jest plikiem wykonywalnym (nie rozważamy tworzenia bibliotek dynamicznych, sterowników itp.). Nasze programy są bardzo proste i nie zawierają bibliotek Runtime, dzięki czemu można je przenieść na komputer z tym samym systemem operacyjnym (i podobną architekturą) i tam uruchomić. Program może akceptować parametry podczas uruchamiania. Są argumentami funkcji main. Ogólny widok funkcji głównej jest następujący Pustka main(int argc, char **argv) (...) Pierwszym argumentem argc jest liczba parametrów przekazanych do funkcji. Drugi argument to tablica ciągów znaków – same parametry. Ponieważ parametry funkcji mogą być dowolne, są one przekazywane jako ciągi znaków, a sam program musi je przeanalizować i przekonwertować na żądany typ. Pierwszym argumentem (argv) jest zawsze nazwa programu. W tym przypadku nazwa wyświetlana jest w zależności od tego, skąd program został uruchomiony. #włączać Teraz nauczmy się trochę pracować z wierszem poleceń. Będzie to potrzebne do przekazania argumentów do naszego programu. Kombinacja klawiszy Win+R powoduje wyświetlenie okna Uruchom. Wpisz cmd, a otworzysz wiersz poleceń. Plik cmd.exe można także znaleźć, wyszukując go w menu Start. W systemach operacyjnych typu Unix można wywołać program terminalowy. Nie będziemy uczyć się zbyt wielu poleceń. Tylko te, które są potrzebne do pracy. Polecenie cd, standardowe dla wszystkich systemów operacyjnych, powoduje przejście do żądanego folderu. Istnieją dwie zastrzeżone nazwy - . (kropka) i.. (dwie kropki). Kropka to nazwa bieżącego folderu. Nie idzie nigdzie Dostęp do folderu nadrzędnego Przejdź do folderu nadrzędnego Aby przejść do żądanego, wpisz adres CD. Na przykład musisz przejść do systemu Windows do folderu C:\Windows\System32 Płyta C:\Windows\System32 W systemie Linux, jeśli chcesz przejść do folderu /var/mysql CD /var/mysql Jeżeli ścieżka zawiera spacje, jest ona zapisana w cudzysłowie CD "D:\Docuents and Settings\Prolog" Terminal posiada następujące przydatne funkcje: jeśli naciśniesz strzałkę w górę, pojawi się poprzednio wykonane polecenie. Jeśli naciśniesz klawisz Tab, terminal spróbuje dokończyć linię znanego mu polecenia lub uzupełni ścieżkę, przechodząc przez wszystkie foldery i pliki w bieżącym folderze. Kolejne ważne polecenie, dir w systemie Windows i ls w systemie Linux, wyświetla zawartość bieżącego folderu (folderu, w którym aktualnie się znajdujesz) na konsoli. Twój program zwrócił swoją pełną nazwę. Przejdź do folderu, w którym znajduje się Twój program i sprawdź jego zawartość Teraz, gdy już przeszliśmy do naszego folderu, możemy uruchomić nasz program. Aby to zrobić, wpisz jej imię. Uwaga, nazwa uległa zmianie. Ponieważ program jest wywoływany z własnego folderu, wyświetlana jest nazwa względna. Zmieńmy teraz program i sprawmy, aby wypisał wszystkie argumenty. które jej dano. #włączać Złóż projekt. Przed montażem upewnij się, że program jest zamknięty. Teraz wywołaj program, przekazując mu różne argumenty. Aby to zrobić, wpisz nazwę programu i argumenty oddzielone spacją Napiszmy teraz program, który pobiera dwa argumenty liczbowe i wyświetla ich sumę #włączać Zbierzmy się i zadzwońmy Tak działa większość programów. Klikając na skrót wywołujesz program, do którego się odnosi. Większość programów akceptuje także różne argumenty. Na przykład możesz wywołać przeglądarkę Firefox z wiersza poleceń i przekazać argumenty Wiele standardowych poleceń ma również parametry. W Windows zwyczajowo zaczynają się od ukośnika, w Unixie od minusa lub dwóch minusów. Na przykład Wyświetla tylko foldery, ale w terminalu Linux Ls -l wyświetla listę wszystkich plików i folderów z atrybutami Aby wyświetlić dodatkowe polecenia systemu Windows, wpisz pomoc w wierszu poleceń lub zapoznaj się z instrukcją (łatwo ją znaleźć w Internecie). W przypadku Linuksa poleceń i ich opcji jest znacznie więcej, a część z nich to niezależne języki programowania, dlatego warto poznać chociaż minimalny zestaw i ich opcje. Borland C++ obsługuje trzy argumenty funkcji main(). Pierwsze dwa to tradycyjne argc i argv. Są to jedyne argumenty funkcji main() zdefiniowane w standardzie ANSI C. Umożliwiają przekazywanie do programu argumentów wiersza poleceń. Argumenty wiersza poleceń to informacje występujące po nazwie programu w wierszu poleceń systemu operacyjnego. Na przykład, gdy program jest kompilowany przy użyciu kompilatora liniowego Borland, zwykle wpisuje się go jako bcc Nazwa programu Gdzie Nazwa programu to program, który należy skompilować. Nazwa programu jest przekazywana do kompilatora jako argument. Parametr argc zawiera liczbę argumentów wiersza poleceń i jest liczbą całkowitą. Jest zawsze równa co najmniej 1, ponieważ nazwa programu kwalifikuje się jako pierwszy argument. Parametr argv jest wskaźnikiem do tablicy wskaźników znakowych. Każdy element tej tablicy wskazuje na argument wiersza poleceń. Wszystkie argumenty wiersza poleceń są ciągami znaków. Wszystkie liczby są konwertowane przez program do formatu wewnętrznego. Poniższy program wypisuje słowo „Hello”, po którym następuje nazwa użytkownika, jeśli zostanie wpisana bezpośrednio po nazwie programu: #włączać Jeśli wywołasz tę nazwę programu, a nazwa użytkownika to Sergey, to aby uruchomić program, powinieneś wpisać: Argumenty wiersza poleceń muszą być oddzielone spacjami lub tabulatorami. Przecinki, średniki i podobne znaki nie są uważane za ograniczniki. Na przykład: Składa się z trzech linii, podczas gdy Herb, Rick, Fred To jest jedna linia – przecinki nie są ogranicznikami. Jeśli chcesz przekazać ciąg zawierający spacje lub tabulatory jako pojedynczy argument, musisz ująć go w cudzysłów. Na przykład jest to jeden z argumentów: "to jest test" Ważne jest, aby poprawnie zadeklarować argv. Najbardziej typową metodą jest: Puste nawiasy wskazują, że tablica nie ma stałej długości. Dostęp do poszczególnych elementów można uzyskać za pomocą indeksowania argv. Na przykład argv wskazuje pierwszą linię, która zawsze zawiera nazwę programu. argv wskazuje następną linię i tak dalej. Poniżej znajduje się mały przykład użycia argumentów wiersza poleceń. Odlicza od wartości określonej w wierszu poleceń i emituje sygnał, gdy osiągnie zero. Zauważ, że pierwszy argument zawiera liczbę przekonwertowaną na liczbę całkowitą przy użyciu standardowej funkcji atoi(). Jeżeli jako drugi argument występuje ciąg „display”, to na ekranie zostanie wyświetlony sam licznik. /* program liczący */ #włączać Należy pamiętać, że jeśli nie zostaną określone żadne argumenty, pojawi się komunikat o błędzie. Jest to najbardziej typowe w przypadku programów, które używają argumentów wiersza poleceń do wydawania instrukcji, jeśli podjęto próbę uruchomienia programu bez poprawnych informacji. Aby uzyskać dostęp do poszczególnych znaków wiersza poleceń, dodaj drugi indeks do argv. Na przykład następujący program wypisuje po jednym znaku wszystkie argumenty, z którymi został wywołany: #włączać Musimy pamiętać, że pierwszy indeks służy do dostępu do ciągu, a drugi do dostępu do znaku w ciągu. Zazwyczaj do uzyskiwania poleceń źródłowych używa się argc i argv. Teoretycznie możliwe jest posiadanie do 32767 argumentów, ale większość systemów operacyjnych nie pozwala nawet się do tego zbliżyć. Zwykle te argumenty służą do określenia nazwy pliku lub opcji. Używanie argumentów wiersza poleceń nadaje programowi profesjonalny wygląd i umożliwia używanie programu w plikach wsadowych. Jeśli dołączysz plik WILDARGS.OBJ dostarczony z Borland C++, możesz używać szablonów w argumentach typu *.EXE. (Borland C++ automatycznie obsługuje symbole wieloznaczne i odpowiednio zwiększa argc.) Na przykład, jeśli podłączysz plik WILDARGS.OBJ do następującego programu, wyświetli się informacja, ile plików odpowiada nazwie pliku określonej w wierszu poleceń: /* Połącz ten program z WILDARGS.OBJ */ #włączać Jeśli nazwiemy ten program WA, to uruchomimy go w następujący sposób, otrzymamy ilość plików z rozszerzeniem EXE oraz listę nazw tych plików: Oprócz argc i argv, Borland C++ udostępnia także trzeci argument wiersza poleceń -env. Parametr env umożliwia programowi dostęp do informacji o środowisku systemu operacyjnego. Parametr env musi występować po argc i argv i jest zadeklarowany w następujący sposób: Jak widać, env deklaruje się w taki sam sposób jak argv. Podobnie jak argv, jest to wskaźnik do tablicy ciągów. Każda linia jest ciągiem środowiskowym zdefiniowanym przez system operacyjny. Parametr env nie ma równoważnego parametru argc, który określa liczbę wierszy środowiska. Zamiast tego ostatnia linia środowiska ma wartość null. Poniższy program wypisuje wszystkie ciągi znaków środowiska aktualnie zdefiniowane w systemie operacyjnym: /* ten program wyświetla wszystkie linie środowiska */ #włączać Należy pamiętać, że chociaż argc i argv nie są używane przez program, muszą znajdować się na liście parametrów. C nie zna nazw parametrów. Zamiast tego o ich użyciu decyduje kolejność deklarowania parametrów. W rzeczywistości możesz wywołać parametr, jak chcesz. Ponieważ argc, argv i env są nazwami tradycyjnymi, najlepiej jest ich nadal używać, aby każdy czytający program mógł od razu zrozumieć, że są to argumenty funkcji main(). Typowym zadaniem programów jest wyszukanie wartości zdefiniowanej w ciągu znaków środowiska. Na przykład zawartość linii PATH umożliwia programom korzystanie ze ścieżek wyszukiwania. Poniższy program demonstruje, jak znaleźć ciągi znaków deklarujące standardowe ścieżki wyszukiwania. Wykorzystuje standardową funkcję biblioteczną strstr(), która ma następujący prototyp: Char *strstr(stała char *str1, stała char *str2); Funkcja strstr() wyszukuje ciąg znaków wskazany przez str1 w ciągu znaków wskazanym przez str2. Jeżeli taki ciąg zostanie znaleziony, zwracany jest wskaźnik do pierwszej pozycji. Jeśli nie zostaną znalezione żadne dopasowania, funkcja zwraca wartość NULL. /* program wyszukuje wśród ciągów środowiskowych linię zawierającą PATH */ #włączać Zdarza się, że dane są przesyłane do programu z wiersza poleceń w momencie jego wywołania. Takie dane nazywane są argumentami wiersza poleceń. Wygląda to na przykład tak: ./a.out test.txt ls -lt /home/peter/ Tutaj wywoływane są programy a.out (z bieżącego katalogu) i ls (z tego samego katalogu określonego w zmiennej środowiskowej PATH). Pierwszy program z linii poleceń otrzymuje jedno słowo - test.txt, drugi - dwa: -lt i /home/peter/. Jeśli program jest napisany w C, to po jego uruchomieniu sterowanie jest natychmiast przekazywane do funkcji main(), zatem to właśnie funkcja otrzymuje argumenty wiersza poleceń przypisane do jej zmiennych parametrów. Poprzednio definiowaliśmy funkcję main() tak, jakby nie pobierała żadnych parametrów i nic nie zwracała. Tak naprawdę w języku C każda funkcja domyślnie (jeśli nie zdefiniowano nic innego) zwraca liczbę całkowitą. Możesz być tego pewien. Jeśli napiszesz kod w ten sposób: main() ( printf („Cześć \N") ; zwróć 0; ) Wtedy podczas kompilacji nie pojawi się żadne ostrzeżenie ani błąd. To samo stanie się, jeśli napiszesz int main() . Dowodzi to, że funkcja domyślnie zwraca liczbę całkowitą, a nie nic (void). Chociaż to, co zwraca funkcja, zawsze można „przesłonić”, na przykład voidmain() lub float main() . Podczas wywoływania programu z wiersza poleceń przekazywana jest do niego zawsze następująca para danych: Pamiętaj, że liczy się także sama nazwa programu. Na przykład, jeśli wywołanie wygląda tak: ./a.out 12 temat 2 Wtedy pierwszy argument programu ma wartość 4, a tablica ciągów znaków jest zdefiniowana jako (./a.out", "12", "motyw", "2"). Zwróć uwagę na terminologię, istnieją tylko dwa argumenty programu (liczba i tablica), ale tyle argumentów wiersza poleceń, ile chcesz. Argumenty wiersza poleceń są „konwertowane” na argumenty programu (na argumenty funkcji main()). To, że dane są przekazywane do programu, nie oznacza, że funkcja main() musi je zaakceptować. Jeśli funkcja main() jest zdefiniowana bez parametrów, nie jest możliwy dostęp do argumentów wiersza poleceń. Chociaż nic nie stoi na przeszkodzie, aby je przesłać. Nie będzie żadnego błędu. Aby uzyskać dostęp do danych przekazanych do programu, należy je przypisać do zmiennych. Ponieważ argumenty są natychmiast przekazywane do funkcji main(), jej nagłówek powinien wyglądać następująco: Pierwsza zmienna (n) zawiera liczbę słów, a druga zmienna zawiera wskaźnik do tablicy ciągów znaków. Często drugi parametr jest zapisywany jako **arr . Jednak to jest to samo. Przypomnijmy, że sama tablica ciągów znaków zawiera wskaźniki do ciągów znaków jako swoje elementy. I przekazujemy do funkcji wskaźnik na pierwszy element tablicy. Okazuje się, że przekazujemy wskaźnik do wskaźnika, tj. **opr. Ćwiczenia #włączać Wyświetla liczbę słów w wierszu poleceń po wywołaniu i każde słowo w nowym wierszu. Wywołaj to bez argumentów wiersza poleceń i z argumentami. W programie wykorzystaliśmy zmienne parametrów argc i argv. Zwyczajowo używa się tych nazw, ale w rzeczywistości mogą one być dowolne. Lepiej trzymać się tego standardu, aby Twoje programy były bardziej zrozumiałe nie tylko dla Ciebie, ale także dla innych programistów. Jeśli masz jakiekolwiek doświadczenie z wierszem poleceń GNU/Linux, wiesz, że większość poleceń ma przełączniki i argumenty. Na przykład podczas przeglądania zawartości katalogów, kopiowania, przenoszenia, jako argumenty podawane są obiekty systemu plików, na których wykonywane jest polecenie. Funkcje jego realizacji określa się za pomocą kluczy. Na przykład w zespole Cp -r ../les_1 ../les_101 cp to nazwa polecenia, -r to przełącznik, a ../les_1 i ../les_101 to argumenty polecenia. Ogólnie rzecz biorąc, najczęściej adresy plików i „modyfikatory” (są to klucze) procesu wykonywania programu są przesyłane do programów po ich uruchomieniu. Napiszmy program, który otwiera określone przez użytkownika w wierszu poleceń pliki do zapisu lub dodania i zapisuje (dodaje) tam te same informacje, które użytkownik wprowadza z klawiatury podczas wykonywania programu: #włączać Objaśnienia do kodu: Któregoś dnia zainteresowałem się zawartością stosu głównej funkcji procesu w Linuksie. Zrobiłem trochę badań i teraz przedstawiam wam wynik. Opcje opisu funkcji głównej: Argc - liczba parametrów Rozmiar segmentu stosu można znaleźć w pliku map: Zanim moduł ładujący przekaże kontrolę do main, inicjuje zawartość tablic parametrów wiersza poleceń, zmiennych środowiskowych i wektora pomocniczego. Nie sprawdzałem, czy są 32 bity, ale najprawdopodobniej wystarczy podzielić rozmiary przez dwa. 1. Dostęp do adresów powyżej górnego punktu powoduje błąd Segfault. Wektor pomocniczy Drugi sposób uzyskania zawartości wektora: Najbardziej czytelną reprezentację uzyskuje się poprzez ustawienie zmiennej środowiskowej LD_SHOW_AUXV. LD_SHOW_AUXV=1 lz Powrót z głównego() Mam nadzieję, że było ciekawie. Dziękujemy użytkownikowi Xeor za przydatną wskazówkę.Opcje wiersza poleceń
Wpisz CD C:\
naciśnij Tab i zobacz co się stanie.
firefox.exe „www.mozilla.org” „site” i natychmiast otworzy witryny pod określonymi adresami w dwóch zakładkach.
{
jeśli(argc!=2)
{
printf("Zapomniałeś wpisać swoje imię\n");
zwróć 1;
}
printf("Witam %s", argv);
zwróć 0;
}
imię Siergiej.
W wyniku działania programu wyświetli się:
„Witam, Siergiej”.
#włączać
#włączać
int main(int argc, char *argv)
{
int disp, liczba;
jeśli (argc<2)
{
printf("Musisz podać długość licznika\n");
printf("w wierszu poleceń. Spróbuj ponownie.\n");
zwróć 1;
}
if (argc==3 && !strcmp(argv,"wyświetlacz")) disp = 1;
w przeciwnym razie disp = 0;
for(count=atoi(argv); liczba; -liczba)
if (disp) printf("%d ", liczba);
printf("%c", "\a"); /* na większości komputerów jest to wywołanie */
zwróć 0;
}
int main(int argc, char *argv)
{
int t, i;
dla(t=0; t
ja = 0;
podczas(argv[t][i])
{
printf("%c", argv[t][i]);
}
printf(" ");
}
zwróć 0;
}
int main(int argc, char *argv)
{
zarejestruj się w ja;
printf("%d plików pasuje do podanej nazwy\n", argc-1);
printf("Są to: ");
dla (i=1; tj
zwróć 0;
}
int main(int argc, char *argv, char *env)
{
int t;
for(t=0; środowisko[t]/t++)
printf("%s\n", env[t]);
zwróć 0;
}
#włączać
int main (int argc, char *argv, char *env)
{
int t;
for(t=0; środowisko[t]; t++)
{
if(strstr(env[t], "ŚCIEŻKA"))
printf("%s\n", env[t]);
}
zwróć 0;
}
Te dane (liczba i wskaźnik) są przekazywane do programu nawet wtedy, gdy zostanie on po prostu wywołany po nazwie, bez przekazywania mu czegokolwiek: ./a.out. W tym przypadku pierwszy argument ma wartość 1, a drugi wskazuje na tablicę składającą się tylko z jednej linii („./a.out”).
main (int n, char *arr)
Napisz taki program:Praktyczne znaczenie przesyłania danych do programu
1. int główna()
2. int main(int argc, char **argv)
3. int main(int argc, char **argv, char **env)
4. int main(int argc, char **argv, char **env, ElfW(auxv_t) auxv)
5. int main(int argc, char **argv, char **env, char **jabłko)
argv - tablica wskaźników zerowych do ciągów parametrów wiersza poleceń
env to kończąca się zerowo tablica wskaźników do ciągów zmiennych środowiskowych. Każda linia w formacie NAZWA=WARTOŚĆ
auxv - tablica wartości pomocniczych (dostępna tylko dla PowerPC)
apple - ścieżka do pliku wykonywalnego (na MacOS i Darwin)
Wektor pomocniczy to tablica zawierająca różne dodatkowe informacje, takie jak efektywny identyfikator użytkownika, atrybut bitowy setuid, rozmiar strony pamięci itp.
kot /proc/10918/maps
…
7ffffffa3000-7ffffffff000 rw-p 00000000 00:00 0
…
Po inicjalizacji góra stosu wygląda mniej więcej tak dla wersji 64-bitowej.
Adres seniora na górze.1.
0x7ffffffff000
Górny punkt segmentu stosu. Wywołanie powoduje błąd seg
0x7ffffffff0f8
ZERO
próżnia*
8
0x00"
2.
Nazwa pliku
zwęglać
1+
"/tmp/a.out"
zwęglać
1
0x00
...
śr
zwęglać
1
0x00
...
zwęglać
1
0x00
3.
0x7ffffffffe5e0
śr
zwęglać
1
..
zwęglać
1
0x00
...
argumentacja
zwęglać
1
0x00
...
zwęglać
1
0x00
4.
0x7ffffffffe5be
argumentacja
zwęglać
1+
"/tmp/a.out"
5.
Tablica o losowej długości
6.
dane dla auxv
próżnia*
48"
AT_NULL
Elf64_auxv_t
16
{0,0}
...
auxv
Elf64_auxv_t
16
7.
auxv
Elf64_auxv_t
16
Np.: (0x0e,0x3e8)
ZERO
próżnia*
8
0x00
...
śr
zwęglać*
8
8.
0x7ffffffffe308
śr
zwęglać*
8
0x7ffffffffe5e0
ZERO
próżnia*
8
0x00
...
argumentacja
zwęglać*
8
9.
0x7ffffffffe2f8
argumentacja
zwęglać*
8
0x7ffffffffe5be
10.
0x7ffffffffe2f0
argc
długi wew
8"
liczba argumentów + 1
11.
Zmienne lokalne i argumenty funkcji wywoływanych przed funkcją main
12.
Zmienne lokalne główne
13.
0x7ffffffffe1fc
argc
wew
4
liczba argumentów + 1
0x7ffffffffe1f0
argumentacja
zwęglać**
8
0x7ffffffffe2f8
0x7ffffffffe1e8
śr
zwęglać**
8
0x7ffffffffe308
14.
Lokalne zmienne funkcyjne
" - Nie znalazłem opisów pól w dokumentach, ale są one wyraźnie widoczne w zrzucie.
2. Ciąg zawierający ścieżkę do pliku wykonywalnego.
3. Tablica stringów ze zmiennymi środowiskowymi
4. Tablica ciągów znaków z parametrami wiersza poleceń
5. Tablica o losowej długości. Jego wybór można wyłączyć za pomocą poleceń
sysctl -w kernel.randomize_va_space=0
echo 0 > /proc/sys/kernel/randomize_va_space
6. Dane dla wektora pomocniczego (na przykład ciąg „x86_64”)
7. Wektor pomocniczy. Więcej szczegółów poniżej.
8. Zerowa tablica wskaźników do ciągów zmiennych środowiskowych
9. Tablica wskaźników z terminalem zerowym do ciągów parametrów wiersza poleceń
10. Słowo maszynowe zawierające liczbę parametrów wiersza poleceń (jeden z argumentów funkcji „głównych”, patrz akapit 11)
11. Zmienne lokalne i argumenty funkcji wywoływanych przed main(_start,__libc_start_main..)
12. Zmienne zadeklarowane w main
13.Argumenty funkcji głównej
14. Zmienne i argumenty funkcji lokalnych.
Dla i386 i x86_64 nie jest możliwe uzyskanie adresu pierwszego elementu wektora pomocniczego, ale zawartość tego wektora można uzyskać w inny sposób. Jednym z nich jest dostęp do obszaru pamięci znajdującego się bezpośrednio za tablicą wskaźników do ciągów zmiennych środowiskowych.
Powinno to wyglądać mniej więcej tak:
#włączać
Struktury Elf(32,64)_auxv_t są opisane w /usr/include/elf.h. Funkcje wypełniania struktur w linux-kernel/fs/binfmt_elf.c
hexdump /proc/self/auxv
AT_HWCAP: bfebfbff //możliwości procesora
AT_PAGESZ: 4096 //rozmiar strony pamięci
AT_CLKTCK: 100 //częstotliwość aktualizacji razy()
AT_PHDR: 0x400040 //informacje nagłówka
AT_PHENT: 56
AT_PHNUM: 9
AT_BASE: 0x7fd00b5bc000 //adres interpretera, czyli ld.so
AT_FLAGS: 0x0
AT_ENTRY: 0x402490 //punkt wejścia programu
AT_UID: 1000 //identyfikatory użytkowników i grup
AT_EUID: 1000 //nominalny i skuteczny
AT_GID: 1000
AT_EGID: 1000
AT_SECURE: 0 //czy podniesiona jest flaga setuid
AT_RANDOM: 0x7fff30bdc809 //adres 16 losowych bajtów,
generowane przy uruchomieniu
AT_SYSINFO_EHDR: 0x7fff30bff000 //wskaźnik do strony używanej
//wywołania systemowe
AT_EXECFN: /bin/ls
NA PLATFORMIE: x86_64
Po lewej stronie znajduje się nazwa zmiennej, po prawej wartość. Wszystkie możliwe nazwy zmiennych i ich opisy znajdziesz w pliku elf.h. (stałe z przedrostkiem AT_)
Po zainicjowaniu kontekstu procesu sterowanie jest przekazywane nie do funkcji main(), ale do funkcji _start().
main() została już wywołana z __libc_start_main. Ta ostatnia funkcja ma ciekawą cechę - przekazuje wskaźnik do funkcji, która powinna zostać wykonana po funkcji main(). Wskaźnik ten jest w naturalny sposób przekazywany przez stos.
Ogólnie argumenty __libc_start_main wyglądają tak, zgodnie z plikiem glibc-2.11/sysdeps/ia64/elf/start.S
/*
* Argumenty za __libc_start_main:
* out0: główne
* out1: argc
* out2: argv
* out3:inicj
* out4: fini //funkcja wywoływana po main
* out5: rtld_fini
* out6: koniec_stosu
*/
Te. aby uzyskać adres wskaźnika fini, musisz przesunąć dwa słowa maszynowe z ostatniej zmiennej lokalnej main.
Oto, co się stało (wykonalność zależy od wersji kompilatora):
#włączać
Powodzenia.