Skip to content

Instantly share code, notes, and snippets.

@MEhrn00
Created April 16, 2026 03:14
Show Gist options
  • Select an option

  • Save MEhrn00/d77bd64fd842edbf790b3dc7987ed71a to your computer and use it in GitHub Desktop.

Select an option

Save MEhrn00/d77bd64fd842edbf790b3dc7987ed71a to your computer and use it in GitHub Desktop.
Small PE file

Small "Hello World" PE file using Clang/LLVM tools (~620-676 bytes).

LLD on Windows does not seem to accept the DOS stub which causes it to be 56 bytes larger.

matt@laptop ~/D/d/smallpe> make
clang --target=x86_64-unknown-windows-none -DDOSSTUB -c -o dosstub.o smallpe.S
llvm-objcopy --dump-section=.stub=dosstub.bin dosstub.o
clang --target=x86_64-unknown-windows-none -fuse-ld=lld -nostdlib -Wl,-subsystem:console -Wl,-build-id:no -Wl,-filealign:2 -Wl,-align:2 -Wl,-merge:.rdata=.text -Wl,-stub:dosstub.bin -o smallpe.exe smallpe.S
lld-link: warning: /align specified without /driver; image may not run
matt@laptop ~/D/d/smallpe> ls -l smallpe.exe
-rwxr-xr-x. 1 matt matt 620 Apr 15 23:08 smallpe.exe*
matt@laptop ~/D/d/smallpe>
PS C:\Users\User\Documents\smallpe> nmake /nologo
        llvm-objcopy --dump-section=.stub=dosstub.bin dosstub.obj
        clang -fuse-ld=lld -nostdlib  -Wl,-subsystem:console  -Wl,-build-id:no  -Wl,-filealign:2  -Wl,-align:2  -Wl,-merge:.rdata=.text -Wl,-stub:dosstub.bin -o smallpe.exe smallpe.S
lld-link: warning: /align specified without /driver; image may not run
PS C:\Users\User\Documents\smallpe> ls .\smallpe.exe

    Directory: C:\Users\User\Documents\smallpe

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a---           4/15/2026 11:10 PM            676 smallpe.exe

PS C:\Users\User\Documents\smallpe> .\smallpe.exe
Hello, world!
PS C:\Users\User\Documents\smallpe>
CC = clang
OBJCOPY = llvm-objcopy
ASFLAGS = --target=x86_64-unknown-windows-none
LDFLAGS = -fuse-ld=lld -nostdlib \
-Wl,-subsystem:console \
-Wl,-build-id:no \
-Wl,-filealign:2 \
-Wl,-align:2 \
-Wl,-merge:.rdata=.text
all : smallpe.exe
smallpe.exe: smallpe.S dosstub.bin
$(CC) $(ASFLAGS) $(LDFLAGS) -Wl,-stub:dosstub.bin -o $@ smallpe.S
dosstub.bin : dosstub.o
$(OBJCOPY) --dump-section=.stub=$@ $<
@touch -m $@
dosstub.o: smallpe.S
$(CC) $(ASFLAGS) -DDOSSTUB -c -o $@ $<
clean:
$(RM) smallpe.exe dosstub.o dosstub.bin
.PHONY : all clean
CC = clang
OBJCOPY = llvm-objcopy
CFLAGS = --target=x86_64-unknown-windows-none
ASFLAGS = --target=x86_64-unknown-windows-none
LDFLAGS = -fuse-ld=lld -nostdlib \
-Wl,-subsystem:console \
-Wl,-build-id:no \
-Wl,-filealign:2 \
-Wl,-align:2 \
-Wl,-merge:.rdata=.text
.SUFFIXES : .c .obj .S .bin
all : smallpe.exe
smallpe.exe : smallpe.S dosstub.bin
$(CC) $(LDFLAGS) -Wl,-stub:dosstub.bin -o $@ smallpe.S
dosstub.bin : dosstub.obj
$(OBJCOPY) --dump-section=.stub=$@ $**
dosstub.obj : smallpe.S
$(CC) $(ASFLAGS) -DDOSSTUB -c -o $@ $**
clean:
del /f smallpe.exe dosstub.obj dosstub.bin 2>nul
#ifdef DOSSTUB
.section .stub,"x"
.ascii "MZ"
.align 64,0
#else
.globl mainCRTStartup
.text
mainCRTStartup:
movl $0x6c, %ecx
leaq hello(%rip), %rdx
movl $hello_len, %r8d
movl $0, %r9d
pushq $0
movq __imp_WriteConsoleA(%rip), %rax
callq *%rax
movl $0, %ecx
movq __imp_ExitProcess(%rip), %rax
callq *%rax
hello: .ascii "Hello, world!\r\n"
.set hello_len, . - hello
.section .idata$2,"d"
.rva kernel32_lookup
.long 0
.long 0
.rva kernel32_dll
.rva kernel32_address
.section .idata$4,"d"
kernel32_lookup:
.section .idata$5,"d"
kernel32_address:
__imp_WriteConsoleA:
.rva WriteConsoleA_name
.long 0
__imp_ExitProcess:
.rva ExitProcess_name
.long 0
.quad 0
.section .idata$6,"d"
WriteConsoleA_name:
.short 0
.asciz "WriteConsoleA"
ExitProcess_name:
.short 0
.asciz "ExitProcess"
.section .idata$7,"d"
kernel32_dll:
.asciz "KERNEL32.dll"
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment