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ň