Zaváděcí kód a velikost .EXE souboru -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= There was once a programmer who was attached to the court of the warlord of Wu. The warlord asked the programmer: "Which is easier to design: an accounting package or an operating system?" "An operating system," replied the programmer. The warlord uttered an exclamation of disbelief. "Surely an accounting package is trivial next to the complexity of an operating system," he said. "Not so," said the programmer, "when designing an accounting package, the programmer operates as a mediator between people having different ideas: how it must operate, how its reports must appear, and how it must conform to the tax laws. By contrast, an operating system is not limited my outside appearances. When designing an operating system, the programmer seeks the simplest harmony between machine and ideas. This is why an operating system is easier to design." The warlord of Wu nodded and smiled. "That is all good and well, but which is easier to debug?" The programmer made no reply. -- Geoffrey James, "The Tao of Programming" Po provedení stubu se dostane ke slovu zaváděci kód. Ten má za úkol všechno připravit a zavolat vlastní main. Dělá doho o něco víc, než je zvykem. DJGPP se tím snaží docílit větší kompatibility s UNIXEM. (V UNIXu například expanze příkazové řádky (* a další znaky) nejsou věcí programu, ale věcí shellu, který program volá. DJGPP tedy expanduje tyto znaky automaticky při startu, aby programy už dostaly parametry stejně jako v UNIXU) Například tato automatická konverze je občas nežádoucí, protože pak nemůžete předat programu parametry obsahující znaky jako *. Díky tomu jsou také výsledné .EXE soubory o něco větší. Hodně funkcí jde ale vypnout v případě, že nejsou třeba. Proto lze velikost výsledného .exe souboru změnšit na 6KB, což není tak strašné vzhledem k popsanému cirkusu při inicializaci a DJGPP je tedy i docela vhodné pro psaní krátkých utilit. Všechny prototoypy pro tento kód sídlí v headeru crt0.h. Rúzné parametry pro start programu lze nastavit pomocí proměné _crt0_startup_flags. Nastavíte jí tak, že do svého programu napíšete int 15_crt0_startup_flags=něco. Funkce musí být globální (tedy mimo funkci a bez static) Jde nastavit následující flagy: _CRT0_FLAG_PRESERVE_UPPER_CASE Pokud tento flag je nastaven, nepřevede se argv[0] (jméno programu) na malá písmena. _CRT0_FLAG_USE_DOS_SLASHES Nepřevádí se potom v argv[0] opačná lomítka na normální _CRT0_FLAG_DROP_EXE_SUFFIX Pokud je nastaven, užízne se přípona .exe v argv[0] _CRT0_FLAG_DROP_DRIVE_SPECIFIER pokud je nastaven, užízne se z argv[0] jméno disku (pokud je uvedeno) _CRT0_FLAG_DISALLOW_RESPONSE_FILES Standardně zavaděcí kód projde parametry a pokud najde parametr ve formátu @jmeno, přečte si parametry se souboru jmeno a nahradí je. Pokud je tento flag nastaven, nic takového se nestane. _CRT0_FLAG_FILL_SBRK_MEMORY Pokud je nastaven, každá pamět přidávaná do programu se napřed snuluje. To potřebují některé vadné programy z UNIXU, protože tam se to děje automaticky (kvůli bezpečnosti) _CRT0_FLAG_FILL_DEADBEEF Paměť nenuluje, ale nastavuje na hodnotu 0xdeadbeef, což umožňuje vychytat chyby. _CRT0_FLAG_NEARPTR Pokud je nastaven, od adresy __djgpp_nearptr_base se spřístupní fyzická paměť. Vypne to protekci paměti a proto se to nedoporučuje. _CRT0_FLAG_NULLOK Vypne odchytávání přístupu na ukazatel NULL. _CRT0_FLAG_NMI_SIGNAL Pokud se nastaví, nejsou MNI signály propouštěny do 16ti bitového kódu. To občas dělá potíže s green BIOSy _CRT0_FLAG_NO_LFN Vypne podporu pro dlouhé názvy pod W95 _CRT0_FLAG_UNIX_SBRK Zařídí, aby se sbrk chovalo jako v UNIXu. Tedy aby všechna paměť byla zasebou. To ale občas vyžaduje přesouvání bloků paměti a také některé DPMI servery neumožňují tak naalokovat celou paměť. _CRT0_FLAG_LOCK_MEMORY Uzamkne celý program v paměti a zakáže swapování. To je občas třeba, když chcete psát ovladače interruptů a nechcete je zamykat ručně. Vypne to ale virtuální paměť a tak to není dobrý nápad. Co jsme s ReDoxem testovali, tento flag nějak nefunguje. _CRT0_FLAG_PRESERVE_FILENAME_CASE Vypne převod názvů z velkých písmen na malá. Nastavením této proměné sice můžete vypnout různé funkce, ale pořád se zalinkují do programu. Pokud chcete určité kusy kódu vyhodit, je nutné místo nich napsat prázdné funkce, které potom linker použije místo těch originálních. Startovací kód mimo zavádění programu ještě dělá: - detekci koprocesoru a zavedení emulátoru - načítání kondifuračního souboru djgpp.env do environmentu - expanzi příkazové řádky (*, @ apod) Vypnutí zavedení souboru s environmentem (to jde udělat skoro ve všech programech) se provede pomocí: void __crt0_load_environment_file(char *_app_name) { return; } Expanze zolinkových znaků se provádí pomocí: char **__crt0_glob_function(char *_arg) { return 0; } Pomocí této funkce můžete nastavit i svůj vlastní expander... Přípravu argv a argc provádí funkce: void __crt0_setup_arguments(void);. Pokud váš program nepoužívá parametry, je možné ji nahradit za prázdnou funkci. Dále lze z programu vyhodit exception handling (program potom v případě že například vydělí nulou nevypíše registry, ale zatuhne) void _npxsetup(void) { return; } int __emu387_load_hook; short __djgpp_ds_alias; void __djgpp_exception_setup(void) { return; } int __djgpp_set_ctrl_c(int enable) { return 0; } Poslední šikovná proměná je _stklen, potomcí které můžete nastavit velikost zásobníku bez použítí programu stubedit. Mimochodem jedna z metod jak zmenšit velikost výsledného souboru je nezalinkovat debugovací informace pomocí přepínače -s, nebo je sundat pomocí programu strip. Přestane pak ale chodit užitečná utilitka symify. výheň