Unsupported code


The previous snipset


The next snipset

Assembler & Win64

This small article is about how to write in assembler for Windows 64-bit, it isn't ment for the IA64 but the new 64-bit version of x86 environment (also called x86-64 or x64 or AMD64/EM64T (EM64T is sometimes misreferred to as EMT64) or AA-64).  I'm also assuming you know about Win32 assembler programming, if not : check out Iczelion's Win32 Asembly Homepage (even though the site isn't updated anymore, Iczelion still has my respect for his work).

When I starting writing this (july 2004),  the SDK for developing programs for the x64 wasn't made public yet, it was only available in the DDK for Windows Server 2003 (which can be ordered online).  You can now (may 2005) freely download the required files with the Windows Server 2003 SP1 Platform SDK.  You don't have to install the whole Platform SDK to assemble and link the examples listed below.  You only need to install the follow options :

  • Microsoft Windows Core SDK
  • Tools

  • Tools (AMD 64-bit)

  • Build Environment

  • Build Environment (AMD 64-bit, prerelease)

To debug your Win64 assembler programs you can use Microsoft's freely downloadable debugger (the 64-bit version can be found here).

This page has quite some success so I decided to write some more about Win64-programming.  If you want, check out this article about RIP relative addressing.

Short introduction

In order to create a simple Win64 assembler program you will need to following files from the DDK :

  • ml64.exe - the Macro Assembler

    link.exe - the linker
    mspdb70.dll - required DLL for the linker (verified for version 8.00.2207)
    msvcr70.dll - required DLL for the linker (verified for version 8.00.2207)
    mspdb80.dll - required DLL for the linker (verified for version 8.00.40310.39)
    msvcr80.dll - required DLL for the linker (verified for version 8.00.40310.39)

    kernel32.lib - not really needed unless you actually want to make a program
    user32.lib - not really needed unless you actually want to make a program

Make sure you are using kernel32.lib and user32.lib from the amd64 subdirectory!

The x86-64 expands some existing registers : rax, rcx, rdx, ebx, rsp, rbp, rsi, rdi, rip (these are 64-bit versions of eax, ecx, edx, ebx, esp, ebp, esi, edi, eip respectively).  And it defines 8 new registers : r8, r9, r10, r11, r12, r13, r14, r15, the 32-versions of these registers are : r8d, r9d, r10d, ....  And the be complete, r8w, r9w, ... are the 16-bit variants (the low word) for the new registers and r8b, r9b, ... are the 8-bit variants (the low byte).

If you have existing Win32 assembler programs, you may have been thinking it will be easy to convert them, but my first experience with Win64 assembler has told me otherwise :-(.  In Win32, all the parameters are passed via the stack, however in Win64 they are passed via the registers.

Note that the used registers (for parameter passing) are based on the size of the parameter.  For 32-bit parameters these are: ecx, edx, r8d, r9d, r10d, ... and for 64-bit parameters there ase : rcx, rdx, r8, r9, r10, ...

Win64 ASM example source code

The following code will display a small message box :

This is an old version that no longer assembles correctly with the newer ml64's (!) :

NOTE: for you to see the difference, I've added the 32-bit version :


How to invoke ml64?

In order the compile the 64-version (see above), you need to invoke ml64 like this :

ml64 XXX.asm /link /subsystem:windows /defaultlib:kernel32.lib /defaultlib:user32.lib /entry:main

(assuming kernel32.lib and user32.lib reside in the same directory as ml64.exe)


(where XXX is the name of your assembly file)

NOTE: I've added the option /entry:main because newer versions of link.exe require this!

Note that the Macro Assembler (x64) doesn't accept the .386 and the .model keywords.  They are probably some others too but I've got no clue which ones :), I'm too bored to test them.

Also "mov rax, offset X" isn't accepted, use "lea rax, X" instead!

About YASM

You can also use YASM to create a Win64 executables starting with version 0.5.0.  Older versions won't work.

In order to assemble try this : yasm-0.5.0-win.exe -f win64 XXX.asm

You can now use the resulting XXX.obj file with the linker (link.exe in the AMD64-subdirectory of your SDK) : link XXX.obj /subsystem:windows /defaultlib:kernel32.lib /defaultlib:user32.lib /entry:main

Notice the "global main" in the source code, and know that the entry-point is case-sensitive!

Also, the code for ML64 and YASM are incompatible!  ML64 doesn't accept the BITS 64 keyword and YASM doesn't accept the .CODE, .STACK and .DATA keywords!

About flat assembler

Starting with version 1.61.3 you could also use flat assembler to build 64-bit object files, but you still need Microsoft's Linker from the Platform SDK to create the exe file.  And starting with version 1.64 you can use flat assembler to directly build 64-bit executable files!

This shows how to use FASM to build a PE64 executable directly :

And if you want to use a linker to build the executable, use this :

In order to assemble try this : fasm XXX.asm
And to link type this : link XXX.obj /subsystem:windows /defaultlib:kernel32.lib /defaultlib:user32.lib /entry:main

Code writting for ML64 and flat assembler are incompatible with each other!  Also note that you need to write lea reg, [variable] whereas ML64 accepts lea reg, variable.

Now you know the basics of how to write for Win64 (x64), go out and write some code!  Let's forget about the 32-bit world...


The previous snipset


The next snipset