2009-08-22 5 views
13
test.c: 

int main() 
{ 
    return 0; 
} 

Nie używałem żadnych flagi (jestem newb do GCC), tylko polecenie:GCC: Pusty program == 23202 bajtów?

gcc test.c 

Użyłem najnowszy TDM build of GCC na win32. Wynikowy plik wykonywalny to prawie 23 KB, czyli zbyt duży dla pustego programu.

Jak zmniejszyć rozmiar pliku wykonywalnego?

+0

Jedna z sugestii: Czy uzyskujesz takie same wyniki przy użyciu wersji minGW GCC? Nie jestem pewien, czy ten rozmiar jest niezwykły, czy nie, ponieważ nie jestem zbytnio przyzwyczajony do C++. – Macha

+0

UPX? http://upx.sourceforge.net/ – bobince

+0

Tak, znam UPX, ale problem tutaj jest następujący: kompilator nie powinien generować ~ 23KB śmieci dla pustego programu. – George

Odpowiedz

36

Nie stosuj się do jej sugestii, ale dla rozrywki, przeczytaj this 'story' o tworzeniu najmniejszego możliwego binarnego ELF.

+6

+1 To fajna lektura! –

+1

Cholera, to nie miało być traktowane poważnie. To jest teraz najbardziej podnoszona odpowiedź, jaką dałem! – Novelocrat

+1

Interesujący jest również artykuł pod adresem http://stackoverflow.com/questions/553029/what-is-the-smallest-possible-windows-pe-executable. – bk1e

10

Domyślnie niektóre standardowe biblioteki (na przykład środowisko wykonawcze C) połączone z plikiem wykonywalnym. Aby uzyskać szczegółowe informacje, zapoznaj się z kluczami --nostdlib --nostartfiles --nodefaultlib. Opcje łącza opisane here.

Dla rzeczywistej drugiej opcji programu należy spróbować optimization options, np. -Os (optymalizuj pod względem wielkości).

+0

Jest to poprawne, ale zazwyczaj jesteś _want_ tych bibliotek. –

+0

Zgadza się. Te klucze użyłem tylko dla systemów wbudowanych. –

+0

Co polecasz na początek?(Jestem nowy w GCC, ale wcześniej dużo użyłem C w VisualCpp) – George

21

Jak mogę zmniejszyć jego rozmiar?

  • Nie rób tego. Po prostu marnujesz swój czas.
  • Użyj opcji -s flag strip symboli (gcc -S)
7

Właściwie, jeśli kod nie robi nic, to jest nawet w porządku, że kompilator nadal tworzy plik wykonywalny? ;-)

Cóż, w systemie Windows dowolny plik wykonywalny nadal będzie miał rozmiar, chociaż może być rozsądnie mały. W starym systemie MS-DOS kompletna aplikacja "nic nie robiąc" to po prostu kilka bajtów. (Wydaje mi się, że cztery bajty używają przerwania 21-godzinnego do zamknięcia programu.) Potem znowu te aplikacje zostały załadowane prosto do pamięci. Gdy format EXE stał się bardziej popularny, sytuacja nieco się zmieniła. Teraz pliki wykonywalne zawierały dodatkowe informacje o samym procesie, takie jak przeniesienie kodu i segmentów danych oraz niektóre sumy kontrolne i informacje o wersji. Wprowadzenie systemu Windows dodało kolejny nagłówek do formatu, aby powiedzieć systemowi MS-DOS, że nie mógł wykonać pliku wykonywalnego, ponieważ musiał on działać w systemie Windows. A Windows rozpoznałby go bez problemów. Oczywiście, format pliku wykonywalnego został również rozszerzony o informacje o zasobach, takie jak bitmapy, ikony i formularze dialogowe i wiele, wiele więcej.

Plik wykonywalny typu "do-nothing" miałby obecnie rozmiar od 4 do 8 kilobajtów, w zależności od kompilatora i każdej metody użytej do zmniejszenia jego rozmiaru. Byłby on w rozmiarze, w którym UPX faktycznie doprowadziłby do większych plików wykonywalnych! Dodatkowe bajty w pliku wykonywalnym mogą zostać dodane, ponieważ dodałeś pewne biblioteki do kodu. Zwłaszcza biblioteki z zainicjalizowanymi danymi lub zasobami dodadzą znaczną ilość bajtów. Dodanie informacji debugowania zwiększa również rozmiar pliku wykonywalnego.

Ale mimo, że wszystko to sprawia przyjemne ćwiczenie przy zmniejszaniu rozmiaru, można się zastanawiać, czy praktyczne jest po prostu ciągłe martwienie się nadmiariem aplikacji. Nowoczesne dyski twarde będą dzieliły pliki w segmentach i na naprawdę duże dyski, różnica byłaby bardzo mała. Jednak ilość kłopotów, które wymagałoby, aby rozmiar był jak najmniejszy, spowolni tempo rozwoju, chyba że jesteś ekspertem od programowania, który jest przyzwyczajony do tych optymalizacji. Tego rodzaju optymalizacje nie mają tendencji do poprawy wydajności i biorąc pod uwagę średnią przestrzeń dyskową większości systemów, nie widzę powodu, dla którego byłoby to praktyczne. (Wciąż jednak optymalizuję własny kod w podobny sposób, ale znowu mam doświadczenie z tymi optymalizacjami.)


Interesuje Cię EXE header? Zaczyna się od liter MZ dla "Mark Żbikowski".Pierwsza część to staromodny nagłówek MS-DOS dla plików wykonywalnych i służy jako skrót do MS-DOS, mówiąc, że program jest , a nie jako plik wykonywalny MS-DOS. (W binarnym, możesz znaleźć tekst "Ten program nie może być uruchomiony w trybie DOS.", Który jest w zasadzie wszystkim, co robi: wyświetlanie tego komunikatu.Następnym jest nagłówek PE, który system Windows rozpozna i użyje zamiast MS-DOS Zaczyna się od liter PE for Portable Executable. Po tym drugim nagłówku będzie sam plik wykonywalny, podzielony na kilka bloków kodu i danych.W nagłówku znajdują się specjalne tabele realokacji, które informują OS, gdzie załadować konkretny blok. zachować to do limitu, ostateczna wykonywalny może być mniejsza niż 4 KB, ale 90% byłoby wtedy nagłówek informacji i nie funkcjonalność.

+3

Jeśli chodzi o aplikację DOS, zrobi to proste ret. To znaczy 1 bajt. –

+0

Zrobiłaby to ret, ale oficjalna zasada polegała na tym, że musieliście przerwać przerwanie "Wyjście". –

+0

Zbudowałem prawdziwe pliki wykonywalne Windows (format PE), które robią użyteczne rzeczy w <4KB, używając VS2005. Tak więc plik wykonywalny typu "nic nie robić" z pewnością nie musi wynosić 8 KB. (Dlaczego? Autorun checker na CD, nie uruchamiaj dużego EXE instalatora, jeśli aplikacja jest już zainstalowana) – MSalters

2

Jaki jest cel tego przedsięwzięcia?

Nawet przy tak niskim poziomie w języku C, nadal musi być dużo ustawień n przed głównym można nazwać. Niektóre z tych ustawień są obsługiwane przez program ładujący (który potrzebuje pewnych informacji), niektóre są obsługiwane przez kod wywołujący główną. I jest prawdopodobnie trochę kodu bibliotecznego, który musiałby mieć każdy normalny program. Co najmniej, prawdopodobnie istnieją odniesienia do standardowych bibliotek, jeśli są one w bibliotekach dll.

Badanie rozmiaru binarnego pustego programu jest bezwartościowym ćwiczeniem samym w sobie. Nic ci to nie mówi. Jeśli chcesz dowiedzieć się czegoś o rozmiarze kodu, spróbuj pisać niepusty (a najlepiej nietrywialne) programy. Porównaj programy korzystające ze standardowych bibliotek z programami, które same wykonują wszystkie czynności.

Jeśli naprawdę chcesz wiedzieć, co się dzieje w tym pliku binarnym (i dlaczego jest tak duży), to znajdź format pliku wykonywalnego, aby uzyskać narzędzie binarnego zrzutu i rozejrzyj się.

+0

Biorąc pod uwagę, że nie znasz motywacji PO, to po prostu nieprawda. Być może zainteresuje go zagnieżdżanie, w którym rozmiar kodu ma duże znaczenie, na przykład. – Novelocrat

+3

Rozmiar kodu pustego programu jest nadal całkowicie nieistotny. A jeśli ma wbudowane programowanie, w którym rozmiar programu ma znaczenie, to wszystko, co robi przy użyciu kompilatora Windows, nie ma znaczenia. –

+0

Rozmiar kodu pustego programu nie jest nieistotny, gdy 1. kodujesz dema, 2. interesuje Cię, jak działa kompilacja, co kończy się końcowym plikiem wykonywalnym, 3. i wreszcie, gdy wiesz, że pusty program nie powinien być ~ 23 KB. Być może nie ma żadnych oczywistych zastosowań czegoś takiego, ale nie powoduje to, że uczenie się o flagach kompilatora nie ma znaczenia. – George

3

Lubię drogę DJGPP nas addressed this wiele, wiele lat temu

Generalnie, sądząc po rozmiarach kodu patrząc na wielkość programów „Hello” nie ma sensu, ponieważ programy te składają się głównie z uruchamianiem kod. ... Większość mocy wszystkich tych funkcji jest marnowana w programach "Hello". Nie ma sensu uruchamiać całego tego kodu, aby wydrukować 15-bajtowy ciąg znaków i wyjść.

+1

Cały punkt pustego programu to zobaczenie narzutu. Interesuje mnie po prostu, jak działa ta kompilacja, co kończy się kompilacją binarną poza kodem, który tam umieściłem. – George

+2

Richard, to wcale nie jest to, o co prosiłeś w swoim pytaniu. Zapytałeś, jak pozbyć się nadmiaru. Nie zapytałeś, na czym polegało obciążenie. –

0

Korzystanie GCC, skompilować program przy użyciu -Os zamiast jednego z innych flag optymalizacyjnych (-O2 lub -O3). To oznacza, że ​​należy optymalizować rozmiar, a nie prędkość. Nawiasem mówiąc, czasami może sprawić, że programy będą działały szybciej, niż byłoby to w przypadku optymalizacji prędkości, jeśli jakiś bardziej interesujący segment będzie pasował. Z drugiej strony, -O3 może faktycznie wywoływać wzrosty rozmiaru kodu.

Może być także kilka flag łącznika, które mówią, aby nie używać nieużywanego kodu z ostatecznego pliku binarnego.

+0

-Os nie ma znaczenia dla tego kodu. –

+1

Niezbyt zaskakujący, w tym przypadku. Nie ma zbyt wielu kodów, które GCC faktycznie tu dotyka. – Novelocrat

11

Poddaj się. W systemie x86 Linux gcc 4.3.2 tworzy plik binarny o wielkości 5 KB. Ale poczekaj! To z dynamicznym łączeniem! Łącznie binarne połączone statycznie wynosi ponad pół megag: 516K. Odpręż się i naucz się żyć z krwawymi.

I powiedzieli, że Modula-3 nigdy nie pojedzie nigdzie z powodu binarnej wersji 200K hello!


W przypadku, gdy zastanawiasz się, co się dzieje, biblioteka GNU C jest skonstruowany tak, aby zawierać pewne cechy czy program od nich zależy, czy nie. Te funkcje obejmują takie trivia jak malloc i free, dlopen, niektóre przetwarzanie ciągów i cały zbiór bucketload rzeczy, które wydają się mieć do czynienia z lokalizacjami i internacjonalizacją, chociaż nie mogę znaleźć żadnych odpowiednich stron man.

Tworzenie małych plików wykonywalnych programów, które wymagają minimalnych usług jest nie celem projektowania dla glibc. Aby być uczciwym, został on również , a nie celem projektu dla każdego systemu operacyjnego, z jakim kiedykolwiek pracowałem (około pół tuzina).

1

Uruchom pasek na pliku binarnym, aby pozbyć się symboli. Z wersją gcc 3.4.4 (cygming special) upuszczam od 10k do 4K.

Możesz spróbować połączyć niestandardowy czas wykonywania (część, która wywołuje główną), aby skonfigurować środowisko wykonawcze. Wszystkie programy używają tego samego do skonfigurowania środowiska wykonawczego dołączonego do gcc, ale w przypadku pliku wykonywalnego nie są potrzebne dane ani pamięć zerowa. Oznacza to, że możesz pozbyć się nieużywanych funkcji bibliotecznych, takich jak memset/memcpy i zmniejszyć rozmiar CRT0. Szukając informacji o tym spojrzeniu na GCC w środowisku osadzonym. Programiści wbudowani to generalnie jedyni użytkownicy korzystający z niestandardowych środowisk uruchomieniowych.

Reszta to koszty ogólne systemu operacyjnego, który ładuje plik wykonywalny. Nie zamierzasz tam tak dużo, chyba że dostroisz to ręcznie?

2

Co mówi "size a.out" o rozmiarze kodu, danych i segmentów bss? Większość kodu jest prawdopodobnie kodem początkowym (klasycznie crt0.o na maszynach uniksowych), który jest wywoływany przez o/s i wykonuje pracę (jak sortowanie argumentów linii poleceń na argc, argv) przed wywołaniem main().

Powiązane problemy