Index to Assembly Language Programming

This is a page of notes to help you learn to write simple programs in Intel Assembler and debug your programs using DOS DEBUG.

This page contains the following sections:

Understanding PUSH, POP, CALL, and INT

The Stack is an essential part of assembly language programming. This section starts with the simple Intel PUSH/POP instructions and then shows how other assembly language instructions such as CALL and INT also use The Stack.

The PUSH, POP, CALL, and INT instructions all use the stack (the memory area pointed at by SS:SP). In .COM format executables, the stack is at the very top (high memory) of the single segment, typically starting at FFFEh, and it grows downward in memory (toward zero) with each PUSH. You cannot PUSH single bytes - the stack pointer always moves by a multiple of two bytes.

When a segment:offset register pair need to be pushed on the stack, the segment is pushed first, followed by the offset, e.g. CS is pushed before IP, and thus IP is stored at a lower memory address than CS. You can either remember that the push happens in natural CS, IP order, or you can remember that, in little-endian fashion, the Little register (the offset register) ends up in lower memory and the Big register (the segment register) ends up in higher memory. (If the Flags need to be pushed as well, as with interrupts, the flags are pushed before CS:IP.)

The following DEBUG scripts and their annotated output files show how the Intel CPU handles each type of instruction. Each of the input text files was run through DEBUG to produce the corresponding output file, to which explanatory comments were added by hand:

C:\> debug <push_pop.txt  >push_pop_out.txt
C:\> debug <call_push.txt >call_push_out.txt
C:\> debug <int_push.txt  >int_push_out.txt

Read these annotated output files for examples and explanations of the workings of PUSH/POP, CALL, and INT:

DEBUG Input Annotated DEBUG Output
push_pop.txt push_pop_out.txt
call_push.txt call_push_out.txt
int_push.txt int_push_out.txt

Homework, test, and exam questions typically show one of these types of instructions and ask you to describe, in execution order, which registers and what memory is affected as the instruction executes (see the Homework questions!). For example:

Exam Question: Given the following register contents, if the listed "CALL FABC:DEF0" instruction were executed, list, in execution order, the changes to registers and memory that would occur. Give both the old value and new value of each register that changes. You must address all of these items:
a) What registers would change, and what would be their old and new values?
b) What memory values would change? Give the memory addresses in both segment:offset and 20-bit real form.
c) What would be the values put in those changed memory locations?
d) What value would appear in the byte addressed by the final value of the stack pointer?

  AX=A1DF  BX=F04C  CX=F02C  DX=791A  SP=E010  BP=123F  SI=23F3  DI=A0A0
  DS=24FC  ES=5AF9  SS=000F  CS=1E5A  IP=0AB3   NV UP EI PL NZ NA PO NC

(Remember: A "far CALL" into a different segment saves the full CS:IP return address before jumping to the subroutine.)

ANSWER (a-c):  Note that order is important here!
IP: 0AB3 -> 0AB8    ; add 5 for length of instruction "9AF0DEBCFA"
SP: E010 -> E00E    ; decrement to PUSH two bytes of CS
[SP] <- 1E5A (CS) so [SS:SP] <- 1E5A so [000F:E00E] <- 1E5A so [0E0FE] <- 1E5A
SP: E00E -> E00C    ; decrement to PUSH two bytes of IP
[SP] <- 0AB8 (IP) so [SS:SP] <- 0AB8 so [000F:E00C] <- 0AB8 so [0E0FC] <- 0AB8
IP: 0AB8 -> DEF0    ; load new IP
CS: 1E5A -> FABC    ; load new CS
ANSWER (d): B8 (the low byte of the last value pushed: 0AB8)

Program Control Flow

Assembly language has no high-level control flow statements. To achieve the same effect, you must use conditional branching. See the Control Structure page and this Power Point presentation for details on how to turn structured programming statements such as IF, WHILE, FOR, etc., into assembly language.

Sample Programs and Program Style

Copying and modifying well-written existing programs is a good way to learn the style of assembly language programs. We have a small selection of sample programs for you to examine in this course. (Not all are well-written!)

Note that the comment style used in these programs is that of an instructor teaching a student how to use assembly language. It is not the style that you would use when writing programs in the real world, and it it not the style you should use when submitting your projects. Comment your algorithm, not how the language works.

Program Debugging and Tracing

If you can't figure out what your program is doing, you can debug it one-line-at-a-time using the DOS DEBUG command. The DOS DEBUG command lets you single-step through your programs to debug them.

Using DEBUG to examine registers and trace execution is covered in this web page.

You can see an example of tracing a very small assembler program here.

For more information on using DEBUG, see the Using DOS DEBUG page.