How to reduce EXE size of x86 ASM compiled with FASM? As an exercise, I've created a simple solution for this challenge, in x86 Assembly Language. I'm running this with FASM on Windows. Here's my source code:

format PE console
entry start

include 'WIN32A.inc'

section '.text' code executable
start:
    push    char            ; Start at 'A'
    call    [printf]        ; Print the current letter 4 times
    call    [printf]
    call    [printf]
    call    [printf]
    inc     [char]          ; Increment the letter
    cmp     [char], 'Z'     ; Compare to 'Z'
    jle     start           ; char &lt;= 'Z' --&gt; goto start

section 'r.data' data readable writeable
    char    db  'A', 10, 0  ; Stores the current letter

section '.idata' data readable import
    library  msvcrt,   'msvcrt.dll'
    import   msvcrt, printf, 'printf'


When I compile this, I get an executable larger than I expected. Here's a hexdump:

https://pastebin.com/W5sUTvTe

I notice there's a lot of empty space between the code section and the data and library import sections, as well as a message saying "This program cannot be run in DOS mode" embedded in the code. How can I assemble my source code to a small file, suitable for Code Golf?

As a side note, suggestions for better ways to print to stdout without importing msvcrt and calling printf are welcome.
Quite a bit general tip, but

Use COM file format instead of PE EXE.

PE EXE has a few flaws making the format pretty much useless in code-golf. First one is the image aligning (Windows won't run the EXE file if it's not aligned properly), and the second one is the header size. There are a few factors that aren't this important (dividing the executable into sections).

Advantages of using COM file format (that is pretty much equivalent to flat binary) are:


Zero header code, file isn't divided into sections
No image aligning (so the image size might not be divisible by a strictly defined power of two, but it has to be smaller than 65K. It doesn't change much though, because if your submission is larger than 65K, you're doing something wrong).
You can't use external libraries - this is actually a plus, because you without doubt have other way to perform I/O. That's where BIOS interrupts come handy.
You have direct control over the memory and devices linked up to the system, therefore there is no paging, no access violations, no memory protection, no concurrency, so on and so forth. These features make it easier to golf really creative programs.


I've revised your code to work as flat binary. It's dead simple:

ORG 100H

MOV DX, P
MOV AH, 9

L:
    INT 21H
    INT 21H
    INT 21H
    INT 21H

    INC BYTE [P]
    CMP BYTE [P], 'Z'
    JLE L

MOV AX, 4C00h
INT 21h

P DB "A", 10, "$"


The output binary is just 32 bytes big. I believe, it's possible to reduce the size even further, but this is just a starting point.

Assemble with nasm -fbin file.asm -o file.com. Note, this example has been made for NASM, but you can translate it freely to FASM, and it will work flawlessly.