Afgedankte code

EN NL TR

Het vorige fragment

De fragmentenindex

Het volgende fragment

Assembler & Win64

Dit korte artikel gaat over hoe men een programma moet schrijven voor Windows 64-bit, het is niet bedoeld voor de IA64 maar voor de nieuwe 64-bit-versie van de x86 (deze wordt ook x86-64, x64 of AMD64/EM64T/AA-64 genoemd (EM64T wordt soms verkeerd geschreven als EMT64)).  Ik ga er vanuit dat je overweg kan met Win32-assembler, indien niet : ga dan even kijken op Iczelion's Win32 Assembly Homepage (ook al wordt de site niet meer aangepast tegenwoordig, Iczelion krijgt toch mijn respect voor zijn werk).

Toen ik dit schreef (juli 2004), was de SDK voor het schrijven van x64-programma's nog niet publiek gemaakt, hij was enkel verkrijgbaar via de DDK voor Windows Server 2003 (welke online gekocht kan worden).  De benodigde bestanden kunnen nu (mei 2005) vrijlijk gedownload worden met de Windows Server 2003 SP1 Platform SDK.  U hoeft niet de ganse Platform SDK te installeren om de onderstaande voorbeelden te kunnen assembleren.  Enkel de volgende opties zijn vereist :

  • Microsoft Windows Core SDK
  • Tools

  • Tools (AMD 64-bit)

  • Build Environment

  • Build Environment (AMD 64-bit, prerelease)

Om Win64-programma's te debuggen kan je Microsoft's gratis downloadbare debugger gebruiken (de 64-bit-versie kan je hier vinden).

Deze pagina bleek vrij populair te zijn dus heb ik besloten nog wat meer te schrijven over x64-programmen.  Als het u interesseert, lees dan dit artikel over RIP-relatieve adressering.
 



Korte introductie

Om een simpel Win64-assembler-programma te maken heb je de volgende bestanden uit de DDK nodig :

  • ml64.exe - de Macro Assembler

    link.exe - de linker
    mspdb70.dll - vereiste DLL voor de linker
    msvcr70.dll - vereiste DLL voor de linker (geverifieerd voor versie 8.00.2207)
    mspdb80.dll - vereiste DLL voor de linker (geverifieerd voor versie 8.00.2207)
    msvcr80.dll - vereiste DLL voor de linker (geverifieerd voor versie 8.00.40310.39)

    kernel32.lib - niet echt vereist tenzij je een echt programma wenst te maken
    user32.lib - niet echt vereist tenzij je een echt programma wenst te maken

Let er op dat u kernel32.lib en user32.lib gebruikt uit de amd64-subfolder!

De x86-64 heeft bestaande registers uitgebreid : rax, rcx, rdx, ebx, rsp, rbp, rsi, rdi, rip (dit zijn 64-bit-versies van respectievelijk eax, ecx, edx, ebx, esp, ebp, esi, edi, eip).  En komt 8 met nieuwe registers : r8, r9, r10, r11, r12, r13, r14, r15, de 32-versies van zijn deze registers zijn : r8d, r9d, r10d, ....  En om compleet  te zijn, r8w, r9w, ... zijn de 16-bit-varianten (de lage word/low word) van deze nieuwe registers en r8b, r9b, ... zijn de 8-bit-varianten (de lage byte/low byte).

Indien je bestaande Win32-assembler-programma's hebt, dan heb je misschien zitten denken dat het makkelijk ging zijn om ze om te zetten naar Win64, maar niets is minder waar.  Mijn eerste ervaringen met Win64-assembler leerden me de waarheid :-(.  In Win32 worden alle parameters via de stack doorgegeven, maar in Win64 worden ze doorgegeven via de registers.

Noteer dat de gebruikte registers (voor de parameter-doorgave) afhankelijk zijn van de grootte van de door-te-geven parameter.  Voor de 32-bit-parameters zijn dit: ecx, edx, r8d, r9d, r10d, ... en voor de 64-bit-parameters zijn dit : rcx, rdx, r8, r9, r10, ...
 


Win64-ASM-voorbeeldbroncode

De onderstaande code toont een "message box" :

Dit is een oudere versie welke niet meer geassembleerd kan worden met de nieuwe versies van ml64 :

NOTA: zodat je het verschil kunt zien, heb ik hier de 32-bit versie geplaatst :


 


Hoe gebruikt men ml64?

Om de 64 bit-versie (zie bovenaan) te assembleren, start je ml64 zo :

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

(er van uitgaande dat kernel32.lib en user32.lib zich in dezelfde folder bevinden als ml64.exe)

en

(waar XXX de naam is van het assemblerbestand)

NOTA: Ik heb de optie /entry:main toegevoegd omdat de nieuwere versies van link.exe dit vereisen!
 


Noteer dat de Macro Assembler (x64) het .386 en het .model sleutelwoord niet accepteerd.  Er zijn er waarschijnlijk nog maar ik zou niet weten de welke :), en ik heb er geen zin om dit te onderzoeken.

Ook: "mov rax, offset X" is niet ondersteund, gebruik in plaats hiervan: "lea rax, X"!
 


In verband met YASM

Vanaf versie 0.5.0 kan je ook YASM gebruiken om een Win64-programma te maken.  Met de oudere versies werkt het niet!

Om te assembleren doe je dit : yasm-0.5.0-win.exe -f win64 XXX.asm

Om te linken gebruik je de linker (link.exe) uit de SDK (uit de AMD64-subdirectory) : link XXX.obj /subsystem:windows /defaultlib:kernel32.lib /defaultlib:user32.lib /entry:main

Noteer "global main" en weet dat het ingangspunt (entry-point) hoofdlettergevoelig is!

Noteer ook dit: de code voor ML64 en YASM is niet direct uitwisselbaar!  ML64 accepteerd het BITS 64-sleutelwoord niet en YASM accepteerd de .CODE, .STACK en .DATA-sleutelwoorden niet!
 


In verband met flat assembler

Beginnend met versie 1.61.3 kan flat assembler ook gebruikt worden om 64-bit-objectbestanden te maken, de Microsoft Linker uit de Platform SDK is echter nog steeds vereist om het uiteindelijke exe-bestand maken.  Vanaf versie 1.64 heb je geen Microsoft Linker meer nodig!

Onderstaand voorbeeld toont aan hoe je een PE64-exe-bestand rechtstreeks moet aanmaken :

En als je een linker wenst te gebruiken dan doe je het zo :

Om te assembleren doe je dit : fasm XXX.asm
En om te linken doe je dit : link XXX.obj /subsystem:windows /defaultlib:kernel32.lib /defaultlib:user32.lib /entry:main

Code geschreven voor ML64 en flat assembler zijn niet compatibel met elkaar!  En noteer ook nog dat je lea reg, [variable] moet schrijven terwijl je voor ML64 lea reg, variable moet schrijven.
 


En nu dat je weet hoe je aan Win64 (x64) moet beginnen, ga en programmeer!  Laten we de 32-bit wereld vergeten...

 

Het vorige fragment

De fragmentenindex

Het volgende fragment