Computing: DOS, OS/2 & Windows Programming

Windows 64bit assembly programming by example: Introduction.

Introduction. 1. Numbers and arrays.  2. Characters and strings. Sample programs list.

Some important notes that you should read before starting this tutorial:

General structure of a 64-bit FASM program.

This structure corresponds to what a 64-bit FASM program has to look like, in order to be correctly built in the SASM IDE. In fact, the samples are assembly functions, executed by a C program, that does nothing else than just calling this function. This way to proceed gives automatically access to the C libraries from within the assembly code, and this way we can use C functions like scanf and printf for input-output.

Here is the general structure of the tutorial samples:

    format ELF64
    section '.data' writeable

    ...
    section '.bss' writeable
    ...
    section '.text' writeable
    public main
    extrn
...
    main:
        prolog code
        ...
        epilog code

The reader is supposed to know what the three sections are about. It is obvious that the .bss section will only be occasionally used. The reserved word extrn is used to declare functions that are external to the assembly program; it's this way that we will declare printf and other C functions. The x64 prolog and epilog code will be introduced in the following paragraphs. They are so to say part of the x64 calling convention (for details, cf. the article x64 calling convention at learn.microsoft.com). All this is a rather complicate topic, and I would say that it's outside the scope of this beginner tutorial. I will just briefly describe the code of the prolog and the epilog; if you want to have details, please, have a look at the article x64 prolog and epilog at learn.microsoft.com. And finally, if you don't understand what this is about, don't worry: Just copy the corresponding instructions to the beginning resp. to the end of every program that you write...

The x64 prolog.

Here is the prolog code used in all tutorial examples:

    push    rbp
    mov     rbp, rsp
    sub     rsp, 32
    and     rsp, -16

First, we save the old base pointer, and we set the new base pointer. Then, we have the magic line in 64-bit assembly. Under the Microsoft x64 calling convention, there is a unique concept of what's known as a shadow space. This is a space that is reserved every time you enter a function and is equal to at least 32 bytes (which is enough space to hold 4 arguments). This space must be reserved whenever you're making use of the stack, since it's what is reserved for things leaving the register values on the stack for debuggers to inspect later on. While the calling convention does not explicitly require the callee to use the shadow space, you should allocate it. Finally, no matter how much space you allocate for the shadow space and your own function's variables, you still need to ensure that the stack pointer is aligned on a 16-byte boundary.

The x64 epilog.

Here is the epilog code used in all tutorial examples:

    mov     rsp, rbp
    pop     rbp
    xor     rax, rax
    ret

First, we restore the stack pointer from RBP (for the case we had allocated local stack space), then pop the old value of the base pointer (pushed with the first instruction of the prolog); note that these two instructions may be replaced by the single instruction leave. The xor of RAX with itself is not part of the standard epilog; normally we would now return control to the calling program. So, what is this instruction for? The RAX register is used to return the result of a function. Here we return the value 0, typically used to indicate that the function completed successfully.

Calling internal and external procedures.

According to the x64 calling convention, with Windows 64-bit assembly, we usually use the RCX, RDX, R8 and R9 registers, in this order to pass arguments to a function. This is mandatory, if we call a C function like, for example, printf. If there is a single variable to print, the output format (more exactly its address) has to be placed in RCX, and the variable value in RDX. If there are two variables to print, the first one has to be placed in RDX, the second one in R8.

The function return value is placed in the RAX register.

Several tutorial samples include internal subroutines, that use different registers for argument passing or the return value. As the usage of the registers is documented with the function comments, I think that this is all ok (?).

Tutorial content.

The tutorial is made of several more or less independent parts, so you do not necessarily have to read them all or read them in a specific order (even though this might be recommendable). On the other hand, the sample programs of each part partially build on the explanations given in the samples before. Thus, real assembly beginners should view them in the order that they appear in the tutorial.

Tutorial content:

  1. Numbers and arrays:
    • 14 sample programs dealing with the following: Integer and floating point arrays, arrays passed to and modified in a procedure, print-out of an array, sorting of an array, two-dimensional arrays, random numbers.
    • 3 "real world" programs: "Guess the number" game, linear equations in one variable, equation of a line passing through two points.
  2. Characters and strings.

Further parts will (probably) be added in the future...


If you find this text helpful, please, support me and this website by signing my guestbook.