The MASM Forum

General => The Laboratory => Topic started by: frktons on January 17, 2013, 09:29:34 AM

Title: The smallest executable
Post by: frktons on January 17, 2013, 09:29:34 AM
I'd like to create the smallest executable with the attached source.

If anybody has experimented combinations of assembler/linker to get
the smallest running executable, please give it a shoot, post your
complete command lines/batch files, and the executable and obj file
you get. Any combination of Masm/JWasm/Any compatible and Link/Polink...
that you are aware of and can create an exe file with the attached
source is welcome.

Thanks

Frank
Title: Re: The smallest executable
Post by: jj2007 on January 17, 2013, 09:49:03 AM
These global variables produce very bloated code:
    mov windowSize.Left, 0
    mov windowSize.Right, 79
    mov windowSize.Top, 0
    mov windowSize.Bottom, 24
Make them local, or use a register to load them. Besides, m2m is often shorter than mov.
Title: Re: The smallest executable
Post by: frktons on January 17, 2013, 09:54:50 AM
Quote from: jj2007 on January 17, 2013, 09:49:03 AM
These global variables produce very bloated code:
    mov windowSize.Left, 0
    mov windowSize.Right, 79
    mov windowSize.Top, 0
    mov windowSize.Bottom, 24
Make them local, or use a register to load them. Besides, m2m is often shorter than mov.

Thanks for the note Jochen. That's surely a way of sparing some bytes.  :t

However I was asking about Assemblers/Linkers and their options to make an
executable program smaller compared to the same program assembled/linked
with different parameters and/or tools.
And an "exe compactor" could do the final job to get the smallest executable
program as the final touch.
Title: Re: The smallest executable
Post by: nidud on January 17, 2013, 10:29:45 AM
deleted
Title: Re: The smallest executable
Post by: frktons on January 17, 2013, 10:36:02 AM
Quote from: nidud on January 17, 2013, 10:29:45 AM
JWasm ascii.asm
JWlink format win pe file ascii.obj

12288 byte

upx ascii.exe
3072 byte


Hi nidud. I've tried using these instructions in a bat file:

\masm32\bin\JWASM.exe /c /coff /Cp /Zg /zlf /zls /nologo ASCII.asm
\masm32\bin\polink /SUBSYSTEM:CONSOLE /ALIGN:4096 ASCII.obj


and I get an executable file of 3072 bytes, as you did with your commands.
I'm wondering if a small file like this is compressable, considering the new
exe has to contain the decompressor code as well.
So I think upx is not useful in this case. Maybe a better combination of
parameters for Assembler/Linker could gain some bytes.  ::)
Title: Re: The smallest executable
Post by: dedndave on January 17, 2013, 10:41:04 AM
    mov windowSize.Left, 0
    mov windowSize.Right, 79
    mov windowSize.Top, 0
    mov windowSize.Bottom, 24

    mov bufferSize.x, 80
    mov bufferSize.y, 25

    mov startPoint.x, 0
    mov startPoint.y, 0


nah - put them in initialized data
it takes more bytes of code to initialize them, whether it's local or global, than it does to stick them in
initialized data
the exception to that is startPoint
put that one in uninitialized data - it's initialized to 0 automatically   :P

now - i know that's not what you were asking about - lol
if you use PoLink, you will get an EXE that is 512 bytes smaller
or, you can use ms Link, and combine sections like this

Link /SUBSYSTEM:CONSOLE /OPT:NOREF /MERGE:.data=.text /ALIGN:4 MyFile.obj
Title: Re: The smallest executable
Post by: Antariy on January 17, 2013, 10:47:56 AM
Quote from: frktons on January 17, 2013, 10:36:02 AM
Quote from: nidud on January 17, 2013, 10:29:45 AM
JWasm ascii.asm
JWlink format win pe file ascii.obj

12288 byte

upx ascii.exe
3072 byte


Hi nidud. I've tried using these instructions in a bat file:

\masm32\bin\JWASM.exe /c /coff /Cp /Zg /zlf /zls /nologo ASCII.asm
\masm32\bin\polink /SUBSYSTEM:CONSOLE /ALIGN:4096 ASCII.obj


and I get an executable file of 3072 bytes, as you did with your commands.
I'm wondering if a small file like this is compressable, considering the new
exe has to contain the decompressor code as well.
So I think upx is not useful in this case. Maybe a better combination of
parameters for Assembler/Linker could gain some bytes.  ::)

Frank, have a look into \masm32\examples\exampl10\MemInfoMicro, there should be a batch file with commands to build that old version of this prog.
Also have a look into the BAT file used for building MemInfoMicro25 (http://masm32.com/board/index.php?topic=44.0). Take your notice on the /MERGE options, and, especially for an old linkers, /OPT:NOWIN98.
Title: Re: The smallest executable
Post by: frktons on January 17, 2013, 11:03:34 AM
Using Polink with these options, I get an executable of 2,560 bytes  :t

\masm32\bin\polink.exe /SUBSYSTEM:CONSOLE /MERGE:.data=.text /SECTION:.text,rwe "ascii.obj" > nul


Probably for this program only source code changes [as Dave and Jochen suggest] can spare some
more bytes.
Title: Re: The smallest executable
Post by: nidud on January 17, 2013, 11:11:44 AM
deleted
Title: Re: The smallest executable
Post by: dedndave on January 17, 2013, 11:23:09 AM
Frank,
if you want to make it smaller, look at the code and data  :P

a lot of times, looking at the disassembled code will bring out things you don't notice in the source
and - when you have related data - put them in a structure
then, instead of...
    mov     SomeData1,1
    mov     SomeData2,20
    mov     SomeData3,30

use
    mov     edx,offset SomeStruct
    mov     [edx].SOMESTRUCT.SomeData1,1
    mov     [edx].SOMESTRUCT.SomeData2,20
    mov     [edx].SOMESTRUCT.SomeData3,30


look at those 2 snippets in a disassembled listing   :P

as Jochen mentioned, using m2m makes code smaller when the constants are small
    push    20
    pop     [edx].SOMESTRUCT.SomeData2

that's because the immediate data (20) is stored in the code stream in a reduced form
whereas
    mov     [edx].SOMESTRUCT.SomeData2,20
the immediate data (20) is stored in the code stream as a dword (assuming SomeData2 is a dword)

however, push/pop is slower
it quite often doesn't matter when API calls are involved, anyway
Title: Re: The smallest executable
Post by: frktons on January 17, 2013, 11:34:29 AM
Hi nidud.

About compressing the exe see my previous post.
Regarding the Text File Compressor and Scanner I'm collecting
the one thousand PROC I need, and the 10,000 necessary info.

The overall scheme is ready. Probably one of this ideas would
give the program the capability to compress a little even the
considered impossible to compress random files, it'd be a surprise
but I'm not sure for the time being it'll work as expected, after
all if it is considered an impossible task it has to mean something.
In few months I'll see and in case I'll show the results on the forum.

As they say the project is still work in progress, and all the
threads I started have something to do with it in a way or another.

I'm quite slow  (http://masm32.com/board/index.php?action=dlattach;topic=1091.0;attach=926)
so don't expect fast results, and the project is quite complex to manage in Assembly
for a n00bist of my level  :P
Title: Re: The smallest executable
Post by: dedndave on January 17, 2013, 11:36:56 AM
i should mention that talking about small code, we will get a message from Hutch - lol
be sure to use LODSB, STOSB, and LOOP, wherever possible   :lol:

(http://img195.imageshack.us/img195/9819/crocodilesign.png)
Title: Re: The smallest executable
Post by: frktons on January 17, 2013, 11:40:55 AM
Dave, your suggestions and Jochen's ones intrigue me. Considering you
have far more knowledge/experience than me I've to take these notes
in great consideration, so as time permits I'll try them and post the results.

QuoteLODSB, STOSB, and LOOP

whooooaaa, I've never used them, are they nice ones?  :lol:
Title: Re: The smallest executable
Post by: dedndave on January 17, 2013, 11:47:10 AM
i use them all the time, where speed isn't critical - like parsing the command line or something

Hutch barks at me every time - but, he probably likes you more than me   :lol:
Title: Re: The smallest executable
Post by: frktons on January 17, 2013, 11:57:30 AM
Quote from: dedndave on January 17, 2013, 11:47:10 AM
i use them all the time, where speed isn't critical - like parsing the command line or something

Hutch barks at me every time - but, he probably likes you more than me   :lol:

So they aren't fast, but I hope they are small at least  :lol:

You know what they say, the more far away you are the more they like you :super-lol:
Title: Re: The smallest executable
Post by: nidud on January 17, 2013, 12:10:02 PM
deleted
Title: Re: The smallest executable
Post by: hutch-- on January 17, 2013, 12:17:00 PM
 :biggrin:

> Hutch barks at me every time - but, he probably likes you more than me

Yeah yeah, teach people bad habits so they write garbage.  :P (But HAY, it was really host stuff on an i386SX under MS-DOS)
Title: Re: The smallest executable
Post by: frktons on January 17, 2013, 12:30:05 PM
Quote from: nidud on January 17, 2013, 12:10:02 PM
/MERGE:.data=.text
the AV scanners will love this one   :lol:

QuoteRegarding the Text File Compressor and Scanner I'm collecting
the one thousand PROC I need,

hence the library then

Quote
if it is considered an impossible task it has to mean something

not impossible, but difficult -- if there is a will there is usually a way

Quotethe project is quite complex to manage in Assembly

true

QuoteI'm quite slow

perfection takes time  :P


1] Yes
2] Yes
3] Yes
4] Yes
5] Yes

well I can say I couldn't agree more  :lol:
Title: Re: The smallest executable
Post by: frktons on January 17, 2013, 12:50:55 PM
Well, I tried Dave's suggestion, but something went wrong.

.data
    windowSize SMALL_RECT <0,79,0,24>
    bufferSize COORD      <80,25>
    startPoint COORD      <0,0>


so I got rid of these code:


    mov windowSize.Left, 0
    mov windowSize.Right, 79
    mov windowSize.Top, 0
    mov windowSize.Bottom, 24

   

    mov bufferSize.x, 80
    mov bufferSize.y, 25


    mov startPoint.x, 0
    mov startPoint.y, 0


But the console is displayed black, with nothing inside.  :icon_rolleyes:
Title: Re: The smallest executable
Post by: dedndave on January 17, 2013, 12:51:56 PM
from the movie "Mission Impossible II"
QuoteThis isn't Mission Difficult, it's Mission Impossible. "Difficult" should be a walk in the park for you.

the order for SMALL_RECT members is Left, Top, Right, Bottom   :P
windowSize SMALL_RECT <0,0,79,24>

put this one in uninitialized data - it will be filled with 0's
startPoint COORD      <>
Title: Re: The smallest executable
Post by: frktons on January 17, 2013, 01:07:31 PM
Quote from: dedndave on January 17, 2013, 12:51:56 PM
from the movie "Mission Impossible II"
QuoteThis isn't Mission Difficult, it's Mission Impossible. "Difficult" should be a walk in the park for you.

the order for SMALL_RECT members is Left, Top, Right, Bottom   :P
windowSize SMALL_RECT <0,0,79,24>

put this one in uninitialized data - it will be filled with 0's
startPoint COORD      <>

I suspected it, about the walk in the park I mean  :lol:

Yes Master Dave, that's the correct order. Anyway, and I suspected it
as well, no gain at all in the exe size: still 2,560 bytes.
But at least it works again  :P
Title: Re: The smallest executable
Post by: dedndave on January 17, 2013, 01:13:14 PM
well - each section is allocated in 512 byte chunks, as i recall
so, you have to get down to the next 512-byte step to notice an improvement

that line was from the character played by Anthony Hopkins
it wasn't the greatest movie, but he's always good
not as great of an actor as everyone may say - he's a bit one-dimensional, actually
i still like him
he made a good Hannibal - lol
Title: Re: The smallest executable
Post by: frktons on January 17, 2013, 01:16:10 PM
Quote from: dedndave on January 17, 2013, 01:13:14 PM
well - you each section is allocated in 512 byte chunks, as i recall
so, you have to get down to the next 512-byte step to notice an improvement

that line was from the character played by Anthony Hopkins
it wasn't the greatest movie, but he's always good
not as great of an actor as everyone may say - he's a bit one-dimensional, actually
i still like him
he made a good Hannibal - lol

That was my suspect  ;)
I like Anthony Hopkins as well, a nice English styled actor  :t
and yes He is a bit one-dimensional
Title: Re: The smallest executable
Post by: jj2007 on January 17, 2013, 05:17:23 PM
.data?
windowSize SMALL_RECT <>
windowRSize RECT <>
.code
   mov windowSize.Left, 127   ; 9
   m2m windowSize.Left, 127   ; 11
   add windowSize.Left, 127   ; 8

   mov windowRSize.left, 127   ; 10
   m2m windowRSize.left, 127   ; 8
   add windowRSize.left, 127   ; 7
;)
Title: Re: The smallest executable
Post by: dedndave on January 17, 2013, 05:32:10 PM
    .data
windowSize SMALL_RECT <0,0,79,24>  ;8
bufferSize COORD      <80,25>      ;4


total clock cycles = 0

;)
Title: Re: The smallest executable
Post by: sinsi on January 17, 2013, 05:52:27 PM
Quote from: dedndave on January 17, 2013, 05:32:10 PM
    .data
windowSize SMALL_RECT <0,0,79,24>  ;8
bufferSize COORD      <80,25>      ;4


total clock cycles = 0

;)
If they don't change then put them in .code
Of course, some APIs will expect to write to it...
Title: Re: The smallest executable
Post by: frktons on January 17, 2013, 08:17:29 PM
Quote from: jj2007 on January 17, 2013, 05:17:23 PM
.data?
windowSize SMALL_RECT <>
windowRSize RECT <>
.code
   mov windowSize.Left, 127   ; 9
   m2m windowSize.Left, 127   ; 11
   add windowSize.Left, 127   ; 8

   mov windowRSize.left, 127   ; 10
   m2m windowRSize.left, 127   ; 8
   add windowRSize.left, 127   ; 7
;)

Thanks Jochen, good to know :t

Quote from: dedndave on January 17, 2013, 05:32:10 PM
    .data
windowSize SMALL_RECT <0,0,79,24>  ;8
bufferSize COORD      <80,25>      ;4


total clock cycles = 0

;)

Yes Dave, the most compact and fast should be like that.  :biggrin:

Quote from: sinsi on January 17, 2013, 05:52:27 PM

If they don't change then put them in .code
Of course, some APIs will expect to write to it...

Don't understand why to put them in .code.  ::)
Title: Re: The smallest executable
Post by: dedndave on January 17, 2013, 11:35:02 PM
if you merge sections at link-time, the advantage of putting it in the code section is gone
but, the idea is to reduce one section so that the 512-byte step is met

if you spend time on the code, you can probably get the EXE down to 1.5 kb   :P

almost everything you had in the .DATA section (except for the string) could be an EQUate
.data

ConTitle  db " -----------   **  Extended ASCII chart displayable characters  **  ----------", 0
PtrConTitle DWORD ConTitle + 17  ; Points to "  Extended..." part of ConTitle

NewProcSize DWORD FromPoint - ToPoint

inpbyte   DWORD  1

;----------------------------------------------------------------------
; ASCII chars to draw a simple box
;----------------------------------------------------------------------

    TopLeft      db   218
    TopRight     db   191
    BottomLeft   db   192
    BottomRight  db   217
    HorizLine    db   196
    VerticLine   db   179

;----------------------------------------------------------------------

    Unit     BYTE One
    Ten      BYTE Space
    Hundred  BYTE Space
    EndOfTask  BYTE 0

    AsciiCode  DWORD 205F2000H  ; 4 bytes = 1 CHAR_INFO
                                ; char 1 White on Magenta Attribute


your string is not modified, as it exists in .DATA
so, you could take sinsi's suggestion....
put the string and the structures we mentioned in the .CODE section
that would eliminate the .DATA section, altogether
you cannot modify data that you place in the .CODE section
at least, not without changing the section attribute - probably not a good practice

the .DATA? section consumes no space in the EXE, other than the entries to create the section   :P

after that, there are several little things, here and there
look at the disassembled code to see how many bytes things use
    lea  eax, ConsoleScreen
    add  eax, TitleStartPoint

    mov     eax,offset ConsoleScreen+TitleStartPoint
Title: Re: The smallest executable
Post by: frktons on January 18, 2013, 05:17:51 AM
We are moving aside and far away from my first intention,
that was to know something about switches and parameters
used by assemblers/linkers to reduce the size of an executable.

When I created this small program a couple of years ago, it was
a challenge to reduce 12k size of a prog and its file, to something
less, and the result was a prog that can be assembled and linked
in 2.5K, which means about 80% less than the original.

But we are now in the compressor time so let's move forward and see
if we can shrink it from 2.5K to 2K or less.

Another nice deviation that stays inside the "compressing matter"
anyway.  :lol:
Title: Re: The smallest executable
Post by: dedndave on January 18, 2013, 05:43:38 AM
still, these should be made into EQUates - no need for all that data
PtrConTitle DWORD ConTitle + 17  ; Points to "  Extended..." part of ConTitle

NewProcSize DWORD FromPoint - ToPoint

inpbyte   DWORD  1

;----------------------------------------------------------------------
; ASCII chars to draw a simple box
;----------------------------------------------------------------------

    TopLeft      db   218
    TopRight     db   191
    BottomLeft   db   192
    BottomRight  db   217
    HorizLine    db   196
    VerticLine   db   179

;----------------------------------------------------------------------

    Unit     BYTE One
    Ten      BYTE Space
    Hundred  BYTE Space
    EndOfTask  BYTE 0

    AsciiCode  DWORD 205F2000H  ; 4 bytes = 1 CHAR_INFO
                                ; char 1 White on Magenta Attribute

the first one, you have already done - you can probably get rid of it

it's also likely to reduce the code size
    mov     al,TopLeft
    mov     [edx],al

as an EQUate...
    mov byte ptr [edx],TopLeft
Title: Re: The smallest executable
Post by: Vortex on January 18, 2013, 06:14:16 AM
Creating small executables is interesting also while working with HLLs.
Title: Re: The smallest executable
Post by: Gunther on January 18, 2013, 07:36:05 AM
Quote from: Vortex on January 18, 2013, 06:14:16 AM
Creating small executables is interesting also while working with HLLs.

But the EXE files generated by compilers are not so small.

Gunther
Title: Re: The smallest executable
Post by: jj2007 on January 18, 2013, 08:27:00 AM
Quote from: Gunther on January 18, 2013, 07:36:05 AM
But the EXE files generated by compilers are not so small.

Erol is a genius, he can produce a 1.5k C executable. The problem with such tiny programs is that a) they can't fill a hard drive sector (4k) and b) they don't do anything useful (but wait until Alex logs in :lol:)
Title: Re: The smallest executable
Post by: frktons on January 18, 2013, 02:11:38 PM
I've done some refinement to the code, and got rid of about
20 instructions, sparing some 50-60 bytes, but still not sufficient
to reduce the size to 2K. It's actually fixed at 2,5K.

I've seen that there is a lot of space for size reduction, so the 2K
goal is quite feasible.

Attached the shrinked version 0.4.

Frank
Title: Re: The smallest executable
Post by: frktons on January 18, 2013, 04:59:29 PM
In order to get rid of the .data section altogether, I need
to transform this line of .data:

ConTitle  db " -----------   **  Extended ASCII chart displayable characters  **  ----------", 0


in a line of LOCAL to put inside the PROC that uses it.

I have no clue how to do it. Any help is welcome.
Title: Re: The smallest executable
Post by: dedndave on January 18, 2013, 05:01:21 PM
it doesn't need to be local
what you want is to put it in the code section

if you did want it to be local, you could push it onto the stack in reverse order - very clumsy
Title: Re: The smallest executable
Post by: frktons on January 18, 2013, 05:13:46 PM
Quote from: dedndave on January 18, 2013, 05:01:21 PM
it doesn't need to be local
what you want is to put it in the code section

if you did want it to be local, you could push it onto the stack in reverse order - very clumsy

I want to put it in the .code section, but I don't know how.
How I define it, where I put these bytes?
Title: Re: The smallest executable
Post by: dedndave on January 18, 2013, 05:18:22 PM
stick it any place you like, really - someplace where it won't be executed   :P
DisplaySequence ENDP

ConTitle  db " -----------   **  Extended ASCII chart displayable characters  **  ----------", 0

; -------------------------------------------------------------------------
; Writes the Screen Title with enhanced color attribute White on Magenta
;--------------------------------------------------------------------------

WriteScreenTitle PROC


as a matter of practice, i try to define things earlier in the source than where i use them
that isn't always practical
Title: Re: The smallest executable
Post by: frktons on January 18, 2013, 05:23:11 PM
Quote from: dedndave on January 18, 2013, 05:18:22 PM
stick it any place you like, really - someplace where it won't be executed   :P
DisplaySequence ENDP

ConTitle  db " -----------   **  Extended ASCII chart displayable characters  **  ----------", 0

; -------------------------------------------------------------------------
; Writes the Screen Title with enhanced color attribute White on Magenta
;--------------------------------------------------------------------------

WriteScreenTitle PROC


as a matter of practice, i try to define things earlier in the source than where i use them
that isn't always practical

In this way the .data section is not created? Because this is my goal here.
Title: Re: The smallest executable
Post by: dedndave on January 18, 2013, 05:24:53 PM
if there is nothing left in the .DATA section, don't use .DATA and it won't be created
Title: Re: The smallest executable
Post by: frktons on January 18, 2013, 05:28:58 PM
Quote from: dedndave on January 18, 2013, 05:24:53 PM
if there is nothing left in the .DATA section, don't use .DATA and it won't be created

OK, good.  :t My .data section is empty and deleted from the program,
but nothing changes in the size of the prog. 2,560 bytes  ::)
Title: Re: The smallest executable
Post by: frktons on January 18, 2013, 05:47:12 PM
The prog without the .data section attached. Anyone can see where I can
save some other bytes?

Title: Re: The smallest executable
Post by: jj2007 on January 18, 2013, 08:03:05 PM
DisplayFmt PROC szFmtName:DWORD
LOCAL rc:SMALL_RECT
  movlps xmm0, windowSize        ; make a copy
  movlps rc, xmm0
  INVOKE WriteConsoleOutput, wHnd, szFmtName, DWORD PTR bufferSize,
  DWORD PTR startPoint, addr rc                ; offset windowSize crashes the app
  ret
DisplayFmt ENDP
Title: Re: The smallest executable
Post by: sinsi on January 18, 2013, 09:15:50 PM
Quote from: sinsi on January 17, 2013, 05:52:27 PM
If they don't change then put them in .code
Of course, some APIs will expect to write to it...

Quote from: jj2007 on January 18, 2013, 08:03:05 PMoffset windowSize crashes the app

Quote from: MSDNlpWriteRegion [in, out]
A pointer to a SMALL_RECT structure. On input, the structure members specify the upper-left and lower-right coordinates of the console screen buffer rectangle to write to. On output, the structure members specify the actual rectangle that was used.

Title: Re: The smallest executable
Post by: jj2007 on January 18, 2013, 10:22:41 PM
Quote from: sinsi on January 18, 2013, 09:15:50 PMOn output,

Indeed, see movlps above. Strange that it apparently did not crash on Frank's machine.
Title: Re: The smallest executable
Post by: frktons on January 19, 2013, 12:59:34 AM
Does the attached 2K version crashes as well? On my pc is works.
If it does, I'll follow Jochen's advice and create a LOCAL variable.

I don't think it will affect the 2.048 bytes result.

To get there I had to leave only the essential and get rid of some
redundancy here and there.

And, well I restored the .data section as well, the link parameters I'm
using already merge data section so there is no need to make
strange things with preinitialized data.
Title: Re: The smallest executable
Post by: jj2007 on January 19, 2013, 01:50:18 AM
2k, no crash :t
Title: Re: The smallest executable
Post by: dedndave on January 19, 2013, 01:50:56 AM
        push    18004Fh       ;79 x 24
        push    0
        INVOKE  SetConsoleWindowInfo, wHnd, TRUE, esp
        pop     ecx
        pop     edx


:P
Title: Re: The smallest executable
Post by: jj2007 on January 19, 2013, 01:53:09 AM
Initialised local variables? You are cheating, Dave ;-)
Title: Re: The smallest executable
Post by: frktons on January 19, 2013, 02:05:51 AM
Quote from: jj2007 on January 19, 2013, 01:50:18 AM
2k, no crash :t

I think it is enough, getting rid of 512 bytes more would be a bit complex
and too long way.   ;)

Quote from: dedndave on January 19, 2013, 01:50:56 AM
        push    18004Fh       ;79 x 24
        push    0
        INVOKE  SetConsoleWindowInfo, wHnd, TRUE, esp
        pop     ecx
        pop     edx


:P

Is this the equivalent of:



    windowSize  SMALL_RECT <N0,N0,N79,N24>

    INVOKE SetConsoleWindowInfo, wHnd, TRUE, ADDR windowSize


?
You have pushed 8 bytes on the stack,
The SMALL_RECT is 8 bytes long.

Nice little trick to get around things.

Is it smaller or just smarter than usual code?
Title: Re: The smallest executable
Post by: dedndave on January 19, 2013, 02:27:24 AM
when you push a constant, the assembler assumes it's a dword in a use32 segment
so, you have created the structure, temporarily, on the stack
when you are done using it, pop, pop, it's gone

one thing that is convenient, in this case, is that a pointer to the structure is in ESP
because the structure pointer is the last parameter of the function, you can use it directly
if the function had other parms afterwards, you'd have to move the current stack pointer into a register
ReadFile and WriteFile are examples of this if you want to create a temporary nNumberOfBytes dword
        push    0
        mov     edx,esp
        INVOKE  ReadFile,hFile,lpFileBuf,uFileSize,edx,NULL
        pop     ecx

that's because parameters are pushed onto the stack in reverse order
so - when NULL is pushed, ESP changes
Title: Re: The smallest executable
Post by: frktons on January 19, 2013, 02:50:38 AM
Quote from: dedndave on January 19, 2013, 02:27:24 AM
when you push a constant, the assembler assumes it's a dword in a use32 segment
so, you have created the structure, temporarily, on the stack
when you are done using it, pop, pop, it's gone

one thing that is convenient, in this case, is that a pointer to the structure is in ESP
because the structure pointer is the last parameter of the function, you can use it directly
if the function had other parms afterwards, you'd have to move the current stack pointer into a register
ReadFile and WriteFile are examples of this if you want to create a temporary nNumberOfBytes dword
        push    0
        mov     edx,esp
        INVOKE  ReadFile,hFile,lpFileBuf,uFileSize,edx,NULL
        pop     ecx

that's because parameters are pushed onto the stack in reverse order
so - when NULL is pushed, ESP changes


Thanks Master Dave, and here it is a present for you,
the 1.5K version of the program  :P

Do you think I've to shrink it more or I can pass through and
move to something else?  :lol:
Title: Re: The smallest executable
Post by: dedndave on January 19, 2013, 02:59:36 AM
1.5 kb is about as small as a PE EXE gets
Alex can make a smaller EXE, but he plays a lot of tricks to do it   :P
Title: Re: The smallest executable
Post by: Magnum on January 19, 2013, 03:32:24 AM
That impressive and something I have needed.

Andy
Title: Re: The smallest executable
Post by: frktons on January 19, 2013, 03:36:06 AM
Quote from: Magnum on January 19, 2013, 03:32:24 AM
That impressive and something I have needed.

Andy

I'm happy to be of some help. :t
Title: Re: The smallest executable
Post by: hutch-- on January 19, 2013, 08:03:53 AM
 :biggrin:

> 1.5 kb is about as small as a PE EXE gets

masm1k.exe is 1024 bytes. exampl07 directory. Done years ago.
Title: Re: The smallest executable
Post by: frktons on January 19, 2013, 10:14:41 AM
Quote from: hutch-- on January 19, 2013, 08:03:53 AM
:biggrin:

> 1.5 kb is about as small as a PE EXE gets

masm1k.exe is 1024 bytes. exampl07 directory. Done years ago.
If the program only opens an empy window maybe it is possible
to do it in 700-800 bytes more or less, but it will appear as 1,024
anyway. I challenged everybody 2 years ago to shrink a 12K exe+
screen, but there was no real competition. I built it, step by
step, and here it is now. Somebody thought it was more or less
an impossible task. And I tend to love impossible tasks by my own
nature.  :lol:
Title: Re: The smallest executable
Post by: npnw on January 20, 2013, 09:41:10 PM
http://www.phreedom.org/research/tinype/ (http://www.phreedom.org/research/tinype/)

Used to be able to write com files in a few bytes way back in the day. I think 5 bytes for a reboot code.
If they haven't changed the spec, the link above is the tiniest I know about.


Title: Re: The smallest executable
Post by: Vortex on January 20, 2013, 09:53:08 PM
Quote from: npnw on January 20, 2013, 09:41:10 PM
http://www.phreedom.org/research/tinype/ (http://www.phreedom.org/research/tinype/)

Used to be able to write com files in a few bytes way back in the day. I think 5 bytes for a reboot code.
If they haven't changed the spec, the link above is the tiniest I know about.

Hi npnw,

I wonder how the author of that article managed to link the object module :

link /nologo /ENTRY:main /NODEFAULTLIB /SUBSYSTEM:WINDOWS /ALIGN:1 tiny.obj

The alignment value 1 is less than section alignment 16. Some version(s) of Windows will refuse to run very small portable executables.
Title: Re: The smallest executable
Post by: hutch-- on January 20, 2013, 11:16:36 PM
 :biggrin:

You can do a "REBOOT.COM" in 2 bytes, "int 19h".  :P

Erol is correct here, go below 512 byte alignment and it becomes unreliable, particularly on earlier versions of Win32. The linkers generate the warning for good reason, it does not comply with the PE specs for Win32.
Title: Re: The smallest executable
Post by: frktons on January 21, 2013, 04:26:56 AM
Quote from: hutch-- on January 20, 2013, 11:16:36 PM
:biggrin:

You can do a "REBOOT.COM" in 2 bytes, "int 19h".  :P


:lol: :lol: :lol:
Title: Re: The smallest executable
Post by: npnw on January 21, 2013, 09:58:41 AM
frktons,
yup, that was what I was thinking!


Vortex,

I read a PE format code for NT 3.1 in another article, and I think he referenced it in his article that there were windows versions that wouldn't run that small of program.  However, most will run it fine.

Title: Re: The smallest executable
Post by: Magnum on January 21, 2013, 04:06:26 PM
If Dave can cheat, well Ich ....


; com.asm Com file template
;
; Ahh....Back in time when things were simpler, No I-Phones, Gas Wars were common, and
folks said Please and Thank you.
;       
;
.model       tiny
.386
.code

org          100h

begin:

jmp          start

; data goes here

start:
   
int     20h ; proper exit

end begin

Title: Re: The smallest executable
Post by: dedndave on January 22, 2013, 03:19:14 AM
this is me, cheating   :P
        .MODEL  Tiny
        .386
        OPTION  CaseMap:None

;####################################################################################

        .CODE

;************************************************************************************

        ORG     100h

_main   PROC    NEAR

        ret

_main   ENDP

;####################################################################################

        END     _main
Title: Re: The smallest executable
Post by: frktons on January 22, 2013, 03:21:04 AM
Quote from: dedndave on January 22, 2013, 03:19:14 AM
        .MODEL  Tiny
        .386
        OPTION  CaseMap:None

;####################################################################################

        .CODE

;************************************************************************************

        ORG     100h

_main   PROC    NEAR

        ret

_main   ENDP

;####################################################################################

        END     _main


Dave won the prize with his "Do nothing" program  :greenclp: :eusa_dance: :greenclp:
Title: Re: The smallest executable
Post by: dedndave on January 22, 2013, 03:38:20 AM
.COM programs start out with a 0 word pushed onto the stack and CS = DS = ES = SS = PSP
at PSP:0000, you will find CD 20, which is INT 20h
so, a NEAR RET gets you a terminate   :P

MZ .EXE's start out a little differently
the code segment is not the same as the PSP segment, like .COM's
as i recall, DS and ES are pointing to the PSP, though
so, you can do this...
        xor     ax,ax
        push    ds
        push    ax
;
;
;
        retf

the 8086/8088 didn't support pushing constants, so you couldn't use PUSH 0
most of the general registers are set to 0, i think
you might get away with PUSH DX or something
AX may not be 0 if there is 1 or 2 valid parsed path(s) on the command line
        push    ds
        push    dx
;
;
;
        retf

i think that's the minimal MZ EXE - 3 bytes of code, 512 for the header
you're not supposed to use INT 20h from an EXE, unless you set cs to psp - something like that
Title: Re: The smallest executable
Post by: MichaelW on January 22, 2013, 04:40:10 AM
If just opening and closing meets the requirements, then I think you can get the same apparent result by renaming an arbitrary 1-byte file to whatever.exe.
Title: Re: The smallest executable
Post by: dedndave on January 22, 2013, 04:41:45 AM
that would be cheating   :lol:
Title: Re: The smallest executable
Post by: dedndave on January 22, 2013, 04:47:16 AM
i wonder how big an exe would be if we used one of these...

http://www.linurs.org/mc14500.html (http://www.linurs.org/mc14500.html)

:biggrin:
Title: Re: The smallest executable
Post by: FORTRANS on January 22, 2013, 05:24:43 AM
Hi,

   This also works.  And is small.  Doesn't do much though.
Has to be a *.COM program of course.


CODE    SEGMENT
        ASSUME  CS:CODE,DS:CODE,ES:NOTHING
        ORG     100H    ; COM file opening
START:

        RET     ; Ensure near return.

CODE    ENDS
        END     START


Cheers,

Steve N.
Title: Re: The smallest executable
Post by: Vortex on January 22, 2013, 05:32:23 AM
Hi npnw,

The article was interesting because MS link will simply refuse to link the object files because of the improper alignment value 1. At least, this is what I observed with the linker supplied with the Masm32 package. Windows 2000 will not run executables not importing API functions.
Title: Re: The smallest executable
Post by: Greenhorn on January 22, 2013, 07:18:16 AM
WTF are you guys smoking ... ?  :shock: :lol: :t
Title: Re: The smallest executable
Post by: npnw on January 22, 2013, 09:22:23 AM
Vortex,

He made reference to the API in win 2000 in the article. The linker probably won't work because of the 16 byte limit, or derivative of 16 for byte alignment and memory transfers at that time. Otherwise it would take two or more memory reads to transfer with the processor. I'm not sure if they have made this 32 bit now, or 64 byte alignment to optimize memory access.

Otherwise the 1 byte would work for 8088 virtual mode. If they have decoupled the linker from hardware, you can do this. If they are optimized for the hardware, this is why it wouldn't work.

http://msdn.microsoft.com/en-us/library/s0ksfwcf(v=vs.80).aspx (http://msdn.microsoft.com/en-us/library/s0ksfwcf(v=vs.80).aspx)

Align
http://msdn.microsoft.com/en-us/library/dwa9fwef(v=vs.80).aspx (http://msdn.microsoft.com/en-us/library/dwa9fwef(v=vs.80).aspx)

directive references
http://msdn.microsoft.com/en-US/library/8t163bt0(v=vs.80).aspx (http://msdn.microsoft.com/en-US/library/8t163bt0(v=vs.80).aspx)

These were from the visual studio 2005 there are links to other assembler versions.
Title: Re: The smallest executable
Post by: Vortex on January 23, 2013, 07:46:43 AM
Quote from: npnw on January 22, 2013, 09:22:23 AM
He made reference to the API in win 2000 in the article.

Here is the problem. Windows 2000 will simply refuse to run a PE not importing an API function. ( tiny.exe - 97 bytes )

Tried the 97 bytes example on a virtual Windows 2000 running on qemu. Ollydbg reported : Bad or unknown format of 32-bit executable file 'C:\tiny.exe'
Title: Re: The smallest executable
Post by: Antariy on January 23, 2013, 08:32:50 AM
http://www.masmforum.com/board/index.php?topic=10252.msg125601#msg125601 :biggrin:
Title: Re: The smallest executable
Post by: Gunther on January 24, 2013, 04:57:41 AM
Hi Alex,

Quote from: Antariy on January 23, 2013, 08:32:50 AM
http://www.masmforum.com/board/index.php?topic=10252.msg125601#msg125601 :biggrin:

not bad, Alex, not bad.

Gunther
Title: Re: The smallest executable
Post by: frktons on January 24, 2013, 08:21:27 AM
Quote from: Antariy on January 23, 2013, 08:32:50 AM
http://www.masmforum.com/board/index.php?topic=10252.msg125601#msg125601 :biggrin:

It doesn't seem to work on win7/64 bit system though.
Title: Re: The smallest executable
Post by: dedndave on January 24, 2013, 09:23:17 PM
it's a 16-bit program, which isn't supported in 64-bit windows OS's
i think it can be done using DosBox or something
Title: Re: The smallest executable
Post by: frktons on January 25, 2013, 12:36:47 PM
Quote from: dedndave on January 24, 2013, 09:23:17 PM
it's a 16-bit program, which isn't supported in 64-bit windows OS's
i think it can be done using DosBox or something


I think it's time to look forward. 16 bit world was funny, but only because we were young.
Thinking about all the limitations it had, it's much better to live in a 32/64 bit modern version.
:P
Title: Re: The smallest executable
Post by: Gunther on January 26, 2013, 06:34:06 AM
Frank,

Quote from: frktons on January 25, 2013, 12:36:47 PM
I think it's time to look forward. 16 bit world was funny, but only because we were young.
Thinking about all the limitations it had, it's much better to live in a 32/64 bit modern version.
:P

wise spoken, but we shouldn't forget some good tricks from the old 8 and 16 bit world.

Gunther
Title: Re: The smallest executable
Post by: frktons on January 26, 2013, 07:00:53 AM
Quote from: Gunther on January 26, 2013, 06:34:06 AM
Frank,

wise spoken, but we shouldn't forget some good tricks from the old 8 and 16 bit world.

Gunther

Agreed. :t
Title: Re: The smallest executable
Post by: Magnum on January 26, 2013, 07:02:01 AM
I agree with you.

We can just look at the code in some of our 32 bit programs.



; Fireworks - with MMX blur and light effects
; by ronybc from Kerala,INDIA
; website: http://www.ronybc.8k.com

.686p
.MMX
.model flat,stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\gdi32.inc
include \masm32\include\user32.inc

includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\gdi32.lib
includelib \masm32\lib\user32.lib

; struct spark {float x,xv,y,yv;};
; struct FireShell {DWORD life; float air; spark d[250];};
; sizeof FireShell = 250*4*4+8 = 4008 bytes

EXX   EQU 4
EXY   EQU 8
AIR   EQU 12
SPARC EQU 16

.data
ClassName db "apocalypse",0
AppName   db "Fireworks MMX ...by ronybc",0,0,0,0,0,0
info      db "Fireworks Version: 3.40229 - Freeware",13,10
          db  13,10
          db "WARNING: This is a Fireware, softwares that push CPU temperature",13,10
          db "to its maximum. It does No harm, but overclockers better stay away :)",13,10
          db "Entire source code of this program is free available at my website. ",13,10
          db  13,10
          db "If you like the work, help the author with donations.",13,10
          db "see http://www.ronybc.8k.com/support.htm",13,10
          db  13,10
          db "SPACE & ENTER keys toggles 'Gravity and Air' and",13,10
          db "'Light and Smoke' effects respectively.",13,10
          db "And clicks explode..! close clicks produce more light",13,10
          db  13,10
          db "Manufactured, bottled and distributed by",13,10
          db "Silicon Fumes Digital Distilleries, Kerala, INDIA",13,10
          db 13,10
          db "Copyright 1999-2004 © Rony B Chandran. All Rights Reserved",13,10
          db 13,10
          db "This isn't the Final Version",13,10
          db "check http://www.ronybc.8k.com for updates and more",0
seed      dd 2037280626
wwidth    dd 680               ; 1:1.618, The ratio of beauty ;)
wheight   dd 420               ; smaller the window faster the fires
maxx      dd 123               ; 123: values set on execution
maxy      dd 123               ; this thing is best for comparing
lightx    dd 123               ; cpu performance.
lighty    dd 123
flash     dd 123
flfactor  dd 0.92
adg       dd 0.00024           ; 0.00096 acceleration due to gravity
xcut      dd 0.00064
nb        dd 5                 ; number of shells
nd        dd 400               ; sparks per shell
sb        dd 0                 ; value set on execution
maxpower  dd 5
minlife   dd 500               ; altered @WndProc:WM_COMMAND:1300
motionQ   dd 16                ; 01-25, altered @WndProc:WM_COMMAND:1210
fcount    dd 0
GMode     dd 1                 ; atmosphere or outer-space
CMode     dd 0                 ; color shifter
EMode     dd 1                 ; special effects
click     dd 0
stop      dd 0
fadelvl   dd 1
chemtable dd 00e0a0ffh, 00f08030h, 00e6c080h, 0040b070h,  00aad580h

bminf     BITMAPINFO <<40,0,0,1,24,0,0,0,0,0,0>>

.data?
hInstance HINSTANCE ?
hwnd      LPVOID ?
hmnu      HWND ?
wnddc     HDC ?
hFThread  HANDLE ?
hHeap     HANDLE ?
idThread1 DWORD ?
idThread2 DWORD ?
bitmap1   LPVOID ?
bitmap2   LPVOID ?
hFShells  LPVOID ?
msg       MSG <>
wc        WNDCLASSEX <>

.code

random PROC base:DWORD         ; Park Miller random number algorithm
    mov eax, seed              ; from M32lib/nrand.asm
    xor edx, edx
    mov ecx, 127773
    div ecx
    mov ecx, eax
    mov eax, 16807
    mul edx
    mov edx, ecx
    mov ecx, eax
    mov eax, 2836
    mul edx
    sub ecx, eax
    xor edx, edx
    mov eax, ecx
    mov seed, ecx
    div base
    mov eax, edx
    ret
random ENDP
; -------------------------------------------------------------------------
Light_Flash3 PROC x1:DWORD, y1:DWORD, lum:DWORD, src:DWORD, des:DWORD
    LOCAL mx:DWORD, my:DWORD, x2:DWORD, y2:DWORD, tff:DWORD
    mov eax,lum
    shr eax,1                  ; Light_Flash: dynamic 2D lighting routine
    mov lum,eax                ; does not uses any pre-computed data
    mov tff,255                ; ie. pure light frum tha melting cpu core :)
    mov eax,maxx
    mov mx,eax
    mov eax,maxy
    dec eax
    mov my,eax
    mov esi,src
    mov edi,des
    xor eax,eax
    mov y2,eax
ylp3:                          ; 2x2 instead of per pixel lighting
    xor eax,eax                ; half the quality, but higher speed
    mov x2,eax
xlp3:
    mov eax,y2
    sub eax,y1
    imul eax
    mov ebx,x2
    sub ebx,x1
    imul ebx,ebx
    add eax,ebx
    mov edx,lum
    imul edx,edx
    xor ebx,ebx
    cmp eax,edx
    ja @F                      ; jump to end causes time waves
    push eax
    fild dword ptr[esp]
    fsqrt
    fidiv lum                  ; this code is -nonlinear-
    fld1
    fsubrp st(1),st(0)
    fmul st(0),st(0)           ; curve
    fmul st(0),st(0)           ; curve more
    fimul tff
    fistp dword ptr[esp]

    pop ebx
    imul ebx,01010101h
@@:
    mov eax,y2
    imul maxx
    add eax,x2
    lea eax,[eax+eax*2]
    mov edx,maxx
    lea edx,[edx+edx*2]
    add edx,eax
   
    movd MM2,ebx               ; simply add with saturation
    movq MM0,[esi+eax]         ; gamma correction is against this code
    psllq MM2,32
    movq MM1,[esi+edx]
    movd MM3,ebx
    por MM2,MM3
    paddusb MM0,MM2
    movd [edi+eax],MM0
    paddusb MM1,MM2
    psrlq MM0,32
    movd [edi+edx],MM1
    movd ebx,MM0
    psrlq MM1,32
    mov [edi+eax+4],bx
    movd ecx,MM1
    mov [edi+edx+4],cx
    emms
@@:
    mov eax,x2
    add eax,2
    mov x2,eax
    cmp eax,mx
    jbe xlp3
    mov eax,y2
    add eax,2
    mov y2,eax
    cmp eax,my
    jbe ylp3
    ret
Light_Flash3 ENDP
; -------------------------------------------------------------------------
Blur_MMX2 PROC                 ; 24bit color version
    mov edi,bitmap2            ; (Developed under an old SiS6326 graphic card
    mov esi,bitmap1            ;  which prefers 24bit for faster operation)
    mov bitmap1,edi            ;  Note: SiS315 is excellent, good rendering quality
    mov bitmap2,esi
    pxor MM7,MM7
    mov eax,fadelvl
    imul eax,00010001h
    mov [ebp-4],eax
    mov [ebp-8],eax
    movq MM6,[ebp-8]
    mov eax,maxx
    lea eax,[eax+eax*2]
    mov ebx,eax
    imul maxy
    push eax                   ; maxy*maxx*3
    lea edx,[ebx-3]
    lea ebx,[ebx+3]
    neg edx
    xor eax,eax
    lea esi,[esi-3]
@@:
    movd MM0,[esi]             ; code enlarged version
    punpcklbw MM0,MM7          ; optimized for speed, not size
    movd MM1,[esi+8]
    movd MM2,[esi+16]
    punpcklbw MM1,MM7
    punpcklbw MM2,MM7
   
    movd MM3,[esi+6]
    movd MM4,[esi+14]
    movd MM5,[esi+22]
    punpcklbw MM3,MM7
    paddw MM0,MM3
    punpcklbw MM4,MM7
    paddw MM1,MM4
    punpcklbw MM5,MM7
    paddw MM2,MM5

    movd MM3,[esi+ebx]
    punpcklbw MM3,MM7
    paddw MM0,MM3
    movd MM4,[esi+ebx+8]
    movd MM5,[esi+ebx+16]
    punpcklbw MM4,MM7
    paddw MM1,MM4
    punpcklbw MM5,MM7
    paddw MM2,MM5

    movd MM3,[esi+edx]
    punpcklbw MM3,MM7
    paddw MM0,MM3
    movd MM4,[esi+edx+8]
    movd MM5,[esi+edx+16]
    punpcklbw MM4,MM7
    paddw MM1,MM4
    punpcklbw MM5,MM7
    paddw MM2,MM5

    psrlw MM0,2                ; neibours only, ie. smoky blur
    psrlw MM1,2
    psrlw MM2,2
    psubusw MM0,MM6            ; fade
    psubusw MM1,MM6
    psubusw MM2,MM6
    packuswb MM0,MM7
    lea esi,[esi+12]
    packuswb MM1,MM7
    packuswb MM2,MM7
    movd [edi+eax],MM0
    movd [edi+eax+8],MM1
    movd [edi+eax+16],MM2
    lea eax,[eax+12]
    cmp eax,[esp]
    jbe @B
    pop eax
    emms                       ; free fpu registers for following
    ret                        ; floating-point functions
Blur_MMX2 ENDP
; -------------------------------------------------------------------------
FShell_explodeOS PROC hb:DWORD
    mov edi,hb
    add edi,SPARC
    mov eax,nd
    dec eax
    shl eax,4
@@:
    fld dword ptr[edi+eax]     ; x coordinate
    fadd dword ptr[edi+eax+4]  ; x velocity
    fstp dword ptr[edi+eax]
    fld dword ptr[edi+eax+8]   ; y coordinate
    fadd dword ptr[edi+eax+12] ; y velocity
    fstp dword ptr[edi+eax+8]
    sub eax,16
    jnc @B
    dec dword ptr[edi-SPARC]
    mov eax,[edi-SPARC]        ; return(--life)
    ret
FShell_explodeOS ENDP
; -------------------------------------------------------------------------
FShell_explodeAG PROC hb:DWORD
    mov edi,hb
    fld adg                    ; acceleration due to gravity
    fld dword ptr[edi+AIR]     ; air resistance
    add edi,SPARC
    mov eax,nd
    dec eax
    shl eax,4
@@:
    fld dword ptr[edi+eax+4]   ; x velocity
    fmul st(0),st(1)           ; deceleration by air
    fst dword ptr[edi+eax+4]
    fadd dword ptr[edi+eax]    ; x coordinate
    fstp dword ptr[edi+eax]
    fld dword ptr[edi+eax+12]  ; y velocity
    fmul st(0),st(1)           ; deceleration by air
    fadd st(0),st(2)           ; gravity
    fst dword ptr[edi+eax+12]
    fadd dword ptr[edi+eax+8]  ; y coordinate
    fstp dword ptr[edi+eax+8]
    sub eax,16
    jnc @B
    fcompp                     ; marks st(0) and st(1) empty
    dec dword ptr[edi-SPARC]
    mov eax,[edi-SPARC]        ; return(--life)
    ret
FShell_explodeAG ENDP
; -------------------------------------------------------------------------
FShell_render PROC hb:DWORD, color:DWORD
    LOCAL expx:DWORD, expy:DWORD
    mov edi,hb
    mov eax,[edi+EXX]
    mov expx,eax
    mov eax,[edi+EXY]
    mov expy,eax
    add edi,SPARC
    mov ebx,color
    dec ebx
    ;and ebx,3
    mov ecx,offset chemtable
    mov edx,hFShells           ; floats are beautiful, and cheap source of
    add edx,32                 ; the chemical used for multi colored fires
    mov eax,CMode
    or eax,eax
    cmovz edx,ecx
    mov edx,[edx+ebx*4]
    mov ecx,nd
    dec ecx
    shl ecx,4
    mov esi,bitmap1
    push maxy                  ; using stack adds speed
    push maxx                  ; (local variables)
    push edx
@@:
    fld dword ptr[edi+ecx+4]
    fabs
    fld xcut                   ; low cost code for independant burnouts
    fcomip st(0),st(1)
    fistp dword ptr[esp-4]
    jae forget

    fld dword ptr[edi+ecx]
    fistp dword ptr[esp-4]
    fld dword ptr[edi+ecx+8]
    fistp dword ptr[esp-8]
    mov eax,[esp-8]
    cmp eax,[esp+8]
    jae forget
    mov ebx,[esp-4]
    cmp ebx,[esp+4]
    jae forget
    imul dword ptr[esp+4]
    add eax,ebx
    lea eax,[eax+eax*2]
    mov edx,[esp]
    mov [esi+eax],dx
    shr edx,16
    mov [esi+eax+2],dl
forget:
    sub ecx,16
    jnc @B
    ;add esp,12  'leave'ing (ENDP)
    ret
FShell_render ENDP
; -------------------------------------------------------------------------
FShell_recycle PROC hb:DWORD, x:DWORD, y:DWORD
    mov edi,hb
    mov eax,x
    mov [edi+EXX],eax
    mov eax,y
    mov [edi+EXY],eax
    mov eax,x
    mov lightx,eax             ; Light last one
    mov eax,y
    mov lighty,eax
    mov eax,flash              ; having only one light source
    add eax,3200               ; 3200 million jouls...!
    mov flash,eax              ; add if previous lighting not extinguished
    invoke random,20
    inc eax
    imul minlife
    mov ebx,eax                ; sync explosions by mouse clicks with rest
    mov eax,[edi]              ; by maintaining minimum delay of 'minlife'
    xor edx,edx
    idiv minlife
    add edx,ebx
    mov [edi],edx
    invoke random,30           ; like its real world counterpart, creation process
    add eax,10                 ; is long and boring but the end product is explodin..
    mov [esp-4],eax            ; refer C++ source also. Most of the below area
    mov eax,10000              ; is blind translation of that original C code
    mov [esp-8],eax            ; i crawled on that code as a Human C compiler...!
    fld1
    fild dword ptr[esp-4]
    fidiv dword ptr[esp-8]
    fsubp st(1),st(0)
    fstp dword ptr[edi+AIR]
    add edi,SPARC
    fild y
    fild x
    mov eax,1000
    mov [esp-4],eax
    fild dword ptr[esp-4]      ; 1000 (constant)
    invoke random,maxpower
    inc eax
    mov [esp-4],eax
    fild dword ptr[esp-4]      ; power
    mov ecx,nd
    dec ecx
    shl ecx,4
@@:
    push ecx
    invoke random,2000
    mov [esp-4],eax
    fild dword ptr[esp-4]
    fsub st(0),st(2)
    fdiv st(0),st(2)
    fmul st(0),st(1)
    mov ecx,[esp]
    fstp dword ptr[edi+ecx+4]
    fld st(0)
    fmul st(0),st(0)
    fld dword ptr[edi+ecx+4]
    fmul st(0),st(0)
    fsubp st(1),st(0)
    fsqrt
    invoke random,2000
    mov [esp-4],eax
    fild dword ptr[esp-4]
    fsub st(0),st(3)
    fdiv st(0),st(3)
    fmulp st(1),st(0)
    mov ecx,[esp]
    fstp dword ptr[edi+ecx+12]
    fld st(2)
    fstp dword ptr[edi+ecx]
    fld st(3)
    fstp dword ptr[edi+ecx+8]
    pop ecx
    sub ecx,16
    jnc @B
    fcompp
    fcompp
    ret
FShell_recycle ENDP
; -------------------------------------------------------------------------

FireThread:
    invoke SetThreadPriority,idThread1,THREAD_PRIORITY_HIGHEST
    invoke GetDC,hwnd
    mov wnddc,eax
    invoke GetProcessHeap
    mov hHeap,eax
    invoke HeapAlloc,hHeap,HEAP_ZERO_MEMORY,4194304
    add eax,4096               ; blur: -1'th line problem
    mov bitmap1,eax
    invoke HeapAlloc,hHeap,HEAP_ZERO_MEMORY,4194304
    add eax,4096               ; blur: -1'th line problem
    mov bitmap2,eax
    mov eax,nd
    shl eax,4
    add eax,SPARC
    mov sb,eax                 ; size of FShell = nd*16+8
    imul nb                    ; array size   = nb*sb
    invoke HeapAlloc,hHeap,HEAP_ZERO_MEMORY,eax
    mov hFShells,eax

    finit                      ; initialise floating point unit
    mov ax,07fh                ; low precision floats
    mov word ptr[esp-4],ax     ; fireworks... not space rockets
    fldcw word ptr[esp-4]

    sub ebp,12                 ; as 3 local variables

    mov eax,nb
    mov [ebp],eax
    mov eax,hFShells
    mov [ebp+4],eax
initshells:
    ;mov eax,maxx              ; naah... not needed
    ;shr eax,1                 ; trusting auto-zero
    ;invoke FShell_recycle,[ebp+4],eax,maxy
    ;mov eax,sb
    ;add [ebp+4],eax
    ;dec dword ptr[ebp]
    ;jnz initFShells
    ;mov flash,6400
lp1:
    mov eax,motionQ
    mov dword ptr[ebp+8],eax
lp2:
    mov eax,nb
    mov [ebp],eax
    mov eax,hFShells
    mov [ebp+4],eax
lp3:
    invoke FShell_render,[ebp+4],[ebp]
    mov eax,GMode
    mov ecx,offset FShell_explodeAG
    mov ebx,offset FShell_explodeOS
    test eax,eax
    cmovz ecx,ebx
    push [ebp+4]
    call ecx
    test eax,eax
    jns @F
    invoke random,maxy
    push eax
    mov eax,maxx
    add eax,eax
    invoke random,eax
    mov edx,maxx
    shr edx,1
    sub eax,edx
    push eax
    push [ebp+4]
    call FShell_recycle
@@:
    mov eax,sb
    add [ebp+4],eax
    dec dword ptr[ebp]
    jnz lp3
    dec dword ptr[ebp+8]
    jnz lp2
    mov eax,EMode
    test eax,eax
    jz r1
    mov eax,CMode              ; switch pre/post blur according to -
    test eax,eax               ; current chemical in fire
    jz @F
    invoke Blur_MMX2
@@:
    invoke Light_Flash3,lightx,lighty,flash,bitmap1,bitmap2
    invoke SetDIBitsToDevice,wnddc,0,0,maxx,maxy,\
           0,0,0,maxy,bitmap2,ADDR bminf,DIB_RGB_COLORS
    mov eax,CMode
    test eax,eax
    jnz r2
    invoke Blur_MMX2
    jmp r2
r1:
    invoke SetDIBitsToDevice,wnddc,0,0,maxx,maxy,\
           0,0,0,maxy,bitmap1,ADDR bminf,DIB_RGB_COLORS
    mov eax,maxx
    imul maxy
    lea eax,[eax+eax*2]
    invoke RtlZeroMemory,bitmap1,eax
r2:
    inc fcount                 ; count the frames
    fild flash
    fmul flfactor
    fistp flash
    invoke Sleep,5             ; control, if frames rate goes too high
    mov eax,stop
    test eax,eax
    jz lp1
    invoke ReleaseDC,hwnd,wnddc
    invoke HeapFree,hHeap,0,bitmap1
    invoke HeapFree,hHeap,0,bitmap2
    invoke HeapFree,hHeap,0,hFShells
    mov idThread1,-1
    invoke ExitThread,2003
    hlt                        ; ...! i8085 memories
; -------------------------------------------------------------------------
.data
fps  db 64 dup (0)
fmat db "fps = %u   [www.ronybc.8k.com]",0
.code

MoniThread:
    invoke Sleep,1000
    invoke wsprintf,ADDR fps,ADDR fmat,fcount
    invoke SetWindowText,hwnd,ADDR fps
    xor eax,eax
    mov fcount,eax
    mov eax,stop