June 20, 2018
Hot Topics:

Moving Forward in Programming with Assembler

  • April 11, 2005
  • By David McClarnon (Darwen)
  • Send Email »
  • More Articles »


A function is declared in the following form:

TestProc proc dwValue1:DWORD, wValue2:WORD, bValue3:BYTE


TestProc endp

The preceding code is an example of a blank function, but it shows the basics. The name of the function is given first, followed by proc. The parameters to the function are defined in the subsequent list in the form <name>:<type>. Some of the basic types available are DWORD, WORD, and BYTE.

The end of the function is marked by a line containing the name of the function followed by endp.

The ret statement is the return statement; in other words, it marks the places where the function is to be exited. A ret statement MUST be included at the end of the function.

If the code is called from C++, the registers ebx, esi, and edi must be restored to their original values before returning from the function. The usual way of doing this is by using push and pop, which will be covered later.

The return value of the function is in the eax register. The function parameters can be accessed by name in most instructions; for example:

TestProc proc dwValue1:DWORD, dwValue2:DWORD

   mov eax, dwValue1
   add eax, dwValue2

TestProc endp

This function adds dwValue1 to dwValue2 and returns the result.

To access functions in C++, you must declare a function with the same name and parameters. The size of the parameters in C++ must equal the size of the parameter defined in the Assembler code. They must also be declared as extern "C" and using the stdcall calling convention. For example, the C++ definition for the above assembler function is:

extern "C" unsigned int __stdcall TestProc(unsigned int dwValue1,
                                           unsigned int dwValue2);

If a pointer is to be passed in, it is declared as a DWORD parameter in the assembler function as pointers (in 32-bit operating systems) are 32 bits in size. Similarly, a 'char' would be passed as a BYTE, a 'WCHAR' as a WORD, and so on.

If an assembler function is designed to be exported from a static DLL, you do not need to define it; just include its name in the .def file of the DLL and then it can be used like any other C++ function declared this way.

Push, Pop, and the Stack

The processor contains a stack onto which registers, constants, and the contents of memory can be pushed and popped by using the push and pop instructions.

The stack is intended to overcome the small number of registers available. It gives an effective, quick way of saving and restoring the contents of registers.

The stack is a first-in-last-out queue of values. The push instruction adds a value to the head of the queue and the pop instruction removes the value from the head of the queue and places it in a register or memory address. For example:

TestFunction proc

   mov eax, 100
   push eax    ; Stack now contains { 100 }

   mov eax, 200
   push eax    ; Stack now contains { 200, 100 }

   mov eax, 300
   push eax    ; Stack now contains ( 300, 200, 100 }

   pop eax     ; eax = 300, stack = { 200, 100 }
   pop eax     ; eax = 200, stack = { 100 }
   pop eax     ; eax = 100, stack = { }


TestFunction endp

A typical use of the stack is to restore the values of the registers ebx, esi, and edi before exiting from a function. For example:

TestFunction proc

   push ebx
   push esi
   push edi

   ; code goes in here

   pop edi
   pop esi
   pop ebx

TestFunction endp

Obviously, only the values of the registers that are being used need to be saved, but this does demonstrate the use of the push and pop instructions.

An important point to note is that, when exiting a function, the stack should always be in the same state that it was in when entering a function. Another way of saying this is that for every push statement there needs to be a corresponding pop statement before the function returns.

Flags and the Instructions that Affect and Use Them

A flag is a setting in the processor that can either be true or false. The processor contains a set of flags to indicate end states after operations. There are a number of flags, but the one that I'm going to be dealing with in this article is the 'Zero' flag. This flag is set by certain operations to indicate that a register has become zero. Other operations set this flag to indicate equality.

Consider the decrement dec instruction. This decrements the register or value specified. If the result is zero, the zero flag is set. For example:

TestFunction proc

   mov eax, 2
   dec eax    ; eax == 1
   dec eax    ; eax == 0, zero flag is set

TestFunction endp

There are other operations that behave differently depending on the states of a particular flag. One of these operations is the jump. Its raw form is jmp, which jumps the program execution to a location in memory (usually specified with a label, the same way as a goto statement in C++). It has various forms, two of which are jz (jump if zero) and jnz (jump if not zero).

By using these instructions and the knowledge of the zero flag, you now can write loops:

LoopFunction proc

   xor eax, eax    ; efficient way of saying eax = 0
   mov ecx, 5      ; ecx is the register generally used for counters

LoopStart:         ; this is a label, used for labelling code positions
   inc eax
   dec ecx
   jnz LoopStart

   ; eax now equals 5


LoopFunction endp


I have covered some of the basic instructions involved in Assember and demonstrated their use. I have also explained what a register is and the registers that exist in Assembler. I have also shown how to define functions with parameters in Assembler and write definitions in C++ for them.

In the next installment of this tutorial, I will cover arithmetic operations, and some of the macros that MASM provides to ease the development of Assembler code.

Page 2 of 2

Comment and Contribute


(Maximum characters: 1200). You have characters left.



Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

By submitting your information, you agree that developer.com may send you developer offers via email, phone and text message, as well as email offers about other products and services that developer believes may be of interest to you. developer will process your information in accordance with the Quinstreet Privacy Policy.


We have made updates to our Privacy Policy to reflect the implementation of the General Data Protection Regulation.
Thanks for your registration, follow us on our social networks to keep up-to-date