Let’s Warmup

[org 0x100]                                 ; originate from 0x100

	mov ax, 6                           ; move the value 6 in ax register 
	mov bx, 9                           ; move the value 9 in bx register 
	add ax, bx                          ; add value of both ax and bx and
                                            ; store it in ax 
                                                    
mov ax, 0x4c00                              ; move value 0x4C00 in ax register
int 0x21                                    ; interrupt with code 0x21 

Again the above code is a simple warmup example that shows how an assembly program looks in terms of structure. At this stage, the goal is not to fully understand what every instruction means, but to get familiar with the overall layout of an assembly program.

Assembly programs usually start with a directive that tells the assembler where the program should be loaded in memory. In our case:

[org 0x100]

This means the program will begin execution at memory offset 0x100. This is common for small programs known as COM files in DOS.

After that, we see a few instructions that use registers. Registers (like ax and bx) are special storage areas inside the CPU. We don’t need to worry about how they work just yet, but notice how values are moved into them and how they are combined. For example:

mov ax, 6
mov bx, 9
add ax, bx

Here the value 6 is placed into ax, the value 9 into bx, and then they are added together, with the result stored back into ax.

Finally, every program must have some way to end. In DOS assembly, this is done with the following instructions:

mov ax, 0x4c00
int 0x21

This combination tells DOS to stop running the program and return control back to the operating system.

So, the structure of a very basic assembly program looks like this:

[org 0x100]           ; program starts here

; All the instructions of the program are written between
; the start (above) and the ending part (below)

mov ax, 0x4c00        ; program exit setup
int 0x21              ; program exit
  1. Start with an origin directive ([org 0x100]).

  2. Write some instructions that do work (like moving numbers, adding, etc.).

  3. End with exit instructions (mov ax, 0x4c00 and int 0x21).

At this point, don’t worry about the detailed meaning of registers or interrupts. We will go deeper into them later. For now, just understand that this is the basic shape of an assembly program: it has a starting point, some operations, and a clean ending.

By the way in Assembly language we write comments using semi-colon ; . You can notice that in above code snippets.

Practical: Running an Assembly Program

Here we learn how to run an assembly program. Before that, we have to know a little bit about assembly language.

Assembly language is a type of machine language that is a little bit easier for humans to understand, unlike pure Machine Language which only has binary characters 0 and 1. However, because it is closer to humans, the machine will not directly understand it. So, we need something in between, that translates the assembly code into pure machine code. That intermediate thing is called an Assembler, whose task is to translate the assembly code into pure machine code 0 and 1.

There are many Assemblers out there such as:

  • NASM (Netwide Assembler)

  • TASM (Turbo Assembler)

  • MASM (Microsoft Assembler) etc.

Some of them are paid and some of them are not widely used. So in these notes, we use the NASM assembler to demonstrate things.

To run assembly, we have to install a couple of software that are the following:

  • DOSBox

  • NASM

That’s all. Search the internet and learn how to set up these tools to run assembly code. I’m not sharing that here to keep these notes shorter.

Now we move on to the steps to run assembly code, assuming you have set up DOSBox with the NASM suite installed.

Assembly To COM

Save the warm-up code written above in a file with a .asm extension. Every assembly code file has this extension. Now run the following command to convert it into a .com file:

C:\\> nasm.exe program.asm -o binary.com

The above command uses the nasm assembler (i.e., nasm.exe) to translate the file program.asm and save it as a new file binary.com. The -o option means output file name.

Now we can run the binary.com file using:

C:\\> binary.com
Fig 1.0: Running The Assembly Program - Translate program.asm file into binary.com file.
Note
  • .com files are simple executable files for DOS. They contain raw machine code and are limited in size (up to 64 KB).

  • The .asm file is the source code written by us, while the .com file is the machine-readable executable generated by the assembler.

Now we can run the binary.com file, but it shows nothing. Do you know why?

Because our warm-up assembly code doesn’t contain anything that shows output on the screen. Everything we did in that code was just storing some values into registers and then adding them together. All of this happens internally in the CPU. So how can we confirm if our code is actually running or not?

We can see the inner working of the above code using an Assembly language debugger called AFD (Advanced Full Screen Debugger). It comes with the NASM suite, and you can see it in the Fig 1.0 as well.

Now we run binary.com with the AFD debugger using the following command:

C:\\> afd.exe binary.com

After running the above command, the screen looks like this:

Fig 1.2: AFD Debugger - Showing Highlighting Different parts of the debugger.

Before going anywhere, I first like to explain the different sections of the AFD debugger we are seeing above. I have marked a total of 8 sections, and their explanations are below in order:

  1. Showing the current values of General Purpose Registers (AX, BX, CX, and DX).

  2. Showing the current values of Index Registers (SI, DI, BP, SP).

  3. Showing the current values of Segment Registers (CS, DS, ES, SS).

  4. Showing the current value of the Instruction Pointer register (IP).

  5. Showing the current values of the Flag Registers (OF, DF, IF, SF, ZF, AF, PF, CF).

  6. Points 6 and 8 are showing Data Windows, which display different parts of memory.

  7. Showing the Code Window, where you can see our assembly code.

We will learn about each type of register and memory addressing format later. However for now, we run over program in step-in method meaning one instruction at a time. When we run each instruction one by one. Notice in the Code Window above, the first instruction is highlighted with a white background.

That means our execution is stopped at that instruction, and we have to either press F1 (depending upon the version of AFD) to execute the instructions one at a time.

Fig 1.3: AFD - Step by step execution

See the above Fig 1.3. After pressing F1 two times, the first two instructions have been executed. Third instruction is highlighted in white. If you notice at the General Purpose Registers (AX and BX) section, you will see they now contain the values 0006 and 0009 as per our code wants.

If we press F1 again, then the AX register value will becomes 000F because 9 + 6 = 15, and in hexadecimal it is F. This means our code is running perfectly.

Now If we keep pressing F1, the value of AX will eventually change to 4C00, and when the INT 21 instruction comes, the debugger shows the message:

“Program Terminated OK”

Fig 1.4: AFD - Program Termination

Above we have seen how an assembly program looks like and how to run and debug assembly code. For now onwards we go through the theory of different things about assembly language and I will give the reference of things what we have learn so far. Keep today’s warmup in mind — we’ll keep building on it step by step.

Last updated

Was this helpful?