Hinweis: Wie erstelle ich kleine Programme?
-
Bon soir...
ich such seit geraumer Zeit zu dem Thema und hab immer mal hier und da was gefunden... ich hoffe das wird ne Art Sammelthread
Also... es geht um das erstellen von kleinen Programmen. Mit "klein" meine ich dabei die Dateigröße. Viele werden wahrscheinlich mal 4k oder 64k-intros gesehen haben und gestaunt haben, wieviel manche Menschen da rein pressen.
(einige werden sich auch wahrscheinlich eh nicht weiter damit beschäftigt haben nach dem Motto "ach, das is doch eh alles asm, das lern ich nie" ;)). Aber für die, die es interessiert habe ich hier ein paar interessante Dinge.Hands on: Wie bewegen wir unseren Compiler (in diesem Fall gehe ich von vc++ aus) dazu, möglichst wenig Schrott in die Exe zu stecken?
---
Jeder wird hier wohl mit den Settings gespielt haben. Dort ist unter dem Register "Compiler" eine Optimierungsoption "Minimize size" (clf: /01)---
Viel Size wird durch die sog. default-libs verschwendet. Die sind ganz praktisch fürs debuggen und nehmen bissken "arbeit" ab (darauf werd ich später zurück kommen). In den Settings kann man "Ignore all default libraries" answitchen (clf: /NODEFAULTLIBS)
Dadurch haben wir nun aber keine standard-c-funktionen mehr zur verfügung und müssen api-alternativen finden. (ist größtenteils eigentlich nicht knifflig)
Jetzt müssen wir aber unseren Entrypoint selbst legen (das haben vorher die defaultlibs übernommen und dann WinMain gecalled).Unser Entrypoint heisst jetzt WinMainCRTStartup. Der nimmt allerdings keine Parameter entgegen und wir müssen aus WinMainCRTStartup unsere eigentliche WinMain callen.
Klingt knifflig, ists aber nicht.
Beispiel: (Original von Matt Pietrek)int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR szCmdLine,int iCmdShow) { // unsere "normale" WinMain // mit unserem eigentlichen code. return 0; } #ifdef _RELEASE // wenn wir im release-build sind int WINAPI WinMainCRTStartup(void) // unser "echter" entrypoint { STARTUPINFO StartupInfo={sizeof(STARTUPINFO),0}; int mainret; char *lpszCommandLine = GetCommandLine(); // skip past program name (first token in command line). if( *lpszCommandLine == '"' ) // check for and handle quoted program name { // scan, and skip over, subsequent characters until another // double-quote or a null is encountered while( *lpszCommandLine && (*lpszCommandLine != '"') ) lpszCommandLine++; // if we stopped on a double-quote (usual case), skip over it. if( *lpszCommandLine == '"' ) lpszCommandLine++; } else { // first token wasn't a quote while ( *lpszCommandLine > ' ' ) lpszCommandLine++; } // skip past any white space preceeding the second token. while ( *lpszCommandLine && (*lpszCommandLine <= ' ') ) lpszCommandLine++; GetStartupInfo(&StartupInfo); // nun der call unserer "normalen" WinMain mainret = WinMain( GetModuleHandle(NULL), NULL, lpszCommandLine, StartupInfo.dwFlags & STARTF_USESHOWWINDOW ? StartupInfo.wShowWindow : SW_SHOWDEFAULT ); ExitProcess(mainret); return mainret; } #endif
Garnicht so schwer, oder?
---
inkrementelles linken frisst ne Menge (K)Bytes. Somit machen wir ganz fix das Häkchen neben "link incrementally" in den Settings weg (clf: /INCREMENTAL:NO)---
Das alignment der Datei ist auch ein Punkt bei dem man viel sparen kann.
Per default ist's auf 4kb gestellt (was einer pagegröße entspricht). Wenn man es allerdings auf 512 byte stellt wird unser "Produkt" wesentlich kleiner. Offiziell "verstößt" das gegen die Regeln von Windows 98 aber ich habe bisher keine Beeinträchtigung bemerkt. (obwohl 4kb bei häufigem swappen besser sein soll)Zu den Project Options beim Register "Link" fügen wir dazu einfach die clf /OPT:NOWIN98 hinzu. Dasselbe lässt sich mit der clf /ALIGN:512 realisieren. Bei der letzten Alternative muss allerdings noch der entrypoint gesondert angegeben werden (clf: /entry:"WinMainCRTStartup")
---
Um nun noch das letzte Quentchen rauszuholen muss man tiefer in die Trickkiste greifen. Jetzt hilft nurnoch Unterstützung von "aussen"
Man kann die file noch strippen. Strip wird zB mit dem djgpp und anderen compilern geliefert. Es entfernt noch die letzten symbole die kein Mensch mehr braucht. Ich persönlich bevorzuge den strip des gcc's aus dem cygwin.---
Und dann gibt's da noch die exepacker. UPX sollte mitlerweile jedes kind kennen (falls nicht: http://upx.sourceforge.net/ ).
Allerdings ist UPX nicht immer der beste
Der Packer FSG holt teilweise beachtlich mehr raus, ist allerdings recht buggy. Er hat Probleme mit "größeren" exes und zerstört bei allen exes mit vorliebe imports
An UPX kann man allerdings auch noch weiter schrauben, da es opensource ist.
Allein beim header kann man nochmal ein halbes KB "durchprügeln".Ich hoffe ein paar bytehuntern geholfen zu haben und dass dieser tread wachsen wird. Vielleicht ja auch was für die FAQ
so long,
JF[ Dieser Beitrag wurde am 26.06.2003 um 19:07 Uhr von cetchmoh editiert. ]
-
Hi!
Sind coole Tips. Hab schon immer mal nach sowas gesucht. Danke
Ciao, Julian