• Advertisement


This topic is now archived and is closed to further replies.

Smallest .exe possible...

This topic is 5145 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

did you mean issue #27, with darkblade? if so, there is a second aritlce in the series at ukscene.org.
there are other methods to reduce the exe size, by changing the size of the alignments, but you then loose win98 portability, and, since in that article he demonstrates how to compress the exe header the size difference is typically only a few bytes : basically not worth it.
if you want to give it a shot, set align and filealign to 16 each.

if you want to make a really small exe, use assembly. there are examples floating around.

Share this post

Link to post
Share on other sites

This even works in vc7.1

..Then, after compilation, you could use UPX on the executable to make it even smaller.


[edited by - shrt on January 7, 2004 1:34:44 AM]

Share this post

Link to post
Share on other sites
Actually the alignment tweak won''t remove compatibility with Windows 98. The tweak controls the section alignment; under Windows 98 it is optimal to align sections on a 4k boundary to improve load time but this obviously results in larger executables. If you don''t do this (specify /opt:nowin98 in VS or change Properties->Linker->Optimisation->Optimise for Windows98) then it''ll just load a little slower under Win98.


Share this post

Link to post
Share on other sites
I wrote a tutorial a while back.. maybe it can help.

Share this post

Link to post
Share on other sites
Thanks Eddycharly,

Those ''#pragma'' statements will be in my next source.

How bad would the performance penalty be for something like a game?


Share this post

Link to post
Share on other sites
I don''t think you''ll notice a change..
Maybe it will be a bit slower to start, but once it''s started, it should run at the same speed than an uncompressed exe.

Share this post

Link to post
Share on other sites
Would DWORD (32 bit) alignment be affected at all?


In fact, you cannot reduce them more than the size of the biggest structure used in your program.

If a structure is aligned in the .exe in a particular way, are all structures created in the memory heap by the .exe aligned the same way, or are they re-aligned (DWORD) for efficiency there?


(That is the best article I have read on the subject BTW)

[edited by - reaction on January 7, 2004 7:18:07 AM]

Share this post

Link to post
Share on other sites
Eddycharly: nice article, thanks! I was on a similar 'squeeze the hell out of my first demo' trip a while back That's an interesting idea with RLE for the header. My approach was to interleave the headers, and fit as much data in there as possible; apack would hopefully compress the remaining zeros effectively. I'll have to try your scheme (when I have time ).

You can save quite a bit in the dropper (52 -> 27!) - here's mine:

; exe dropper
; Jan Wassenberg 2003

; free mem
mov ah, 0x49
int 0x21

; fopen
mov ah, 0x3c
pop cx ; cx = 0 (attrib)
mov dx, 0x100+exe ; filename == "MZ."
int 0x21

; fwrite
xchg ax, bx
mov ah, 0x40
dec cx ; 64 kb
int 0x21

; fclose
mov ah, 0x3e
int 0x21

; exec
mov ax, 0x4b00
int 0x21

incbin "w.exe"

(Note: the filename seems to require a '.').

And the crazy header:

db 'MZ' ; e_magic
db '.',0 ; dropped file name
dd 'PE' ; Signature
dw 0x014c ; Machine = x86
dw 1 ; NumberOfSections
dd 0,0,0
dw 0x0070 ; SizeOfOptionalHeader
dw 0x010f ; Characteristics = 32 bit exe
dw 0x010b ; Magic
db 'glu32.dll',0 ; Name (RVA 30)
dd 0
dd rva(start) ; AddressOfEntryPoint
dd 0,0
dd 0x400000 ; ImageBase
dd 4 ; SectionAlignment, e_lfanew
dd 4 ; FileAlignment
dd 0,0
dw 4 ; MajorSubsystemVersion
db 'EDIT',0 ; wnd class name (RVA 78)
db 0
dd 0x10000 ; SizeOfImage (virtual)
dd 0xa4 ; SizeOfHeaders
dd 0
dw 2 ; Subsystem = WIN32_GUI
dw 0
dd 0x400000 ; SizeOfStackReserve
dd 0x400000 ; SizeOfStackCommit
dd 30 ; Name (RVA 108)
dd rva(imp_tbl) ; FirstThunk
dd 0
dd 2 ; NumberOfRvaAndSizes (# data dirs)
dd 0 ; Export VirtualAddress
dd 0 ; Export Size, End Import
dd 96 ; Import VirtualAddress
dd 40 ; Import Size
dd 0,0
dd 0 ; VirtualSize
dd 0 ; VirtualAddress
dd 0x10000 ; SizeOfRawData FIXME?
dd 0 ; PointerToRawData

(Notes: I just saw it won't run on 9x at all - section alignment is set to 4. Total size = 160 bytes, including embedded import table; there's plenty of room for more data, but I didn't have any)

Another worthwhile thing to squeeze is OpenGL imports in the exe.
Specify the ordinals of functions you need (unfortunately, some idiot at MS removed the DllInitialize function in opengl32.dll for WinXP, so the ordinals are decreased by one. *sigh*); the ORD macro builds a table of deltas to the next value (1 byte). If there's a large gap, specify a dummy value to bridge it.
ORD glBegin, 12
ORD glClear, 18

now the import code:

; import gl functions
mov esi, ord_tbl
mov edi, ogl_funcs
push byte num_ords
pop ebp
xor ebx, ebx ; (xchg eax, ebx if eax == 0)?
.1: xor eax, eax
lodsb ; delta to next ordinal
add ebx, eax ; ebx = current ordinal
push ebx
push opengl32
call GetProcAddress
dec ebp
jnz .1

ogl_funcs is our import table, so to speak. call glClear translates to call [ebp-4] - 3 bytes! (Note: ebp points to my BSS; the table comes before it).

Great fun

[edited by - Jan Wassenberg on January 7, 2004 7:20:29 AM]

Share this post

Link to post
Share on other sites

  • Advertisement