Turinys

Procedures and macros

Some instructions that you need to know

This is just a list of some basic assembly instructions that are very important and are used often.

ADD

ADD: Add the contents of one number to another

Syntax: ADD operand1,operand2

This adds operand2 to operand1. The answer is stored in operand1. Immediate data cannot be used as operand1 but can be used as operand2.

SUB

SUB: Subtract one number from another

Syntax: SUB operand1,operand2

This subtracts operand2 from operand1. Immediate data cannot be used as operand1 but can be used as operand2.

MUL and IMUL

MUL: Multiplies two unsigned integers (always positive)

IMUL: Multiplies two signed integers (either positive or negitive)

Syntax: MUL register or variable

IMUL register or variable

This multiples AL or AX by the register or variable given. AL is multiplied if a byte sized operand is given and the result is stored in AX. If the operand is word sized AX is multiplied and the result is placed in DX:AX.

On a 386, 486 or Pentium the EAX register can be used and the answer is stored in EDX:EAX.

DIV and IDIV

DIV: Divides two unsigned integers (always positive)

IDIV: Divides two signed integers (either positive or negitive)

Syntax: DIV register or variable

IDIV register or variable

This works in the same way as MUL and IMUL by dividing the number in AX by the register or variable given. The answer is stored in two places. AL stores the answer and the remainder is in AH. If the operand is a 16 bit register than the number in DX:AX is divided by the operand and the answer is stored in AX and remainder in DX.

Introduction to Procedures

In assembly a procedure is the equivalent to a function in C or Pascal. A procedure provides a easy way to encapsulate some calculation which can then be used without worrying how it works. With procedures that are properly designed you can ignore how a job is done.

This is how a procedure is defined:

AProcedure PROC
.
. 		; some code to do something 
.
ret		; if this is not here then your computer will crash 
AProcedure ENDP

It is equally easy to run a procedure all you need to do is this:

call AProcedure

This next program is an example of how to use a procedure. It is like the first example we looked at, all it does is print „Hello World!“ on the screen.

; This is a simple program to demonstrate procedures. It should
; print Hello World! on the screen when ran.
 
.model tiny 
.code 
org 100h
 
Start: 
 
call Display_Hi 	; Call the procedure
mov ax,4C00h 		; return to DOS
int 21h 		
 
Display_Hi PROC 
 
mov dx,OFFSET HI 
mov ah,9 
int 21h 
 
ret
Display_Hi ENDP 
 
HI DB "Hello World!" 	; define a message
 
end Start

Procedures that pass parameters

Procedures wouldn't be so useful unless you could pass parameters to modify or use inside the procedure. There are three ways of doing this and I will cover all three methods: in registers, in memory and in the stack.

There are three example programs which all accomplish the same task. They print a square block (ASCII value 254) in a specified place.

The sizes of the files when compiled are: 38 for register, 69 for memory and 52 for stack (in bytes).

In registers

The advantages of this is that it is easy to do and is fast. All you have to do is to is move the parameters into registers before calling the procedure.

; this a procedure to print a block on the screen using 
; registers to pass parameters (cursor position of where to 
; print it and colour).
 
.model tiny 
.code
org 100h
 
Start: 
 
mov dh,4 	; row to print character on
mov dl,5 	; column to print character on
mov al,254 	; ascii value of block to display
mov bl,4 	; colour to display character
 
call PrintChar 	; print our character
mov ax,4C00h 	; terminate program 
int 21h
 
PrintChar PROC NEAR
 
push bx 	; save registers to be destroyed
push cx
 
xor bh,bh 	; clear bh - video page 0
mov ah,2 	; function 2 - move cursor
int 10h 	; row and col are already in dx
 
pop bx 		; restore bx
 
xor bh,bh 	; display page - 0
mov ah,9 	; function 09h write char & attrib
mov cx,1 	; display it once
int 10h 	; call bios service
 
pop cx 		; restore registers
 
ret 		; return to where it was called
PrintChar ENDP
 
end Start

Passing through memory

The advantages of this method is that it is easy to do but it makes your program larger and can be slower.

To pass parameters through memory all you need to do is copy them to a variable which is stored in memory. You can use a variable in the same way that you can use a register but commands with registers are a lot faster.

; this a procedure to print a block on the screen using memory
; to pass parameters (cursor position of where to print it and
; colour).
 
.model tiny 
.code
org 100h
 
Start: 
 
mov Row,4 	; row to print character
mov Col,5 	; column to print character on
mov Char,254 	; ascii value of block to display
mov Colour,4 	; colour to display character
 
call PrintChar 	; print our character
mov ax,4C00h 	; terminate program 
int 21h
 
PrintChar PROC NEAR
 
push ax cx bx 	; save registers to be destroyed
 
xor bh,bh 	; clear bh - video page 0
mov ah,2 	; function 2 - move cursor
mov dh,Row
mov dl,Col
int 10h 	; call Bios service 
 
mov al,Char 
mov bl,Colour
xor bh,bh 	; display page - 0
mov ah,9 	; function 09h write char & attrib 
mov cx,1 	; display it once
int 10h 	; call bios service
 
pop bx cx ax 	; restore registers
 
ret 		; return to where it was called
PrintChar ENDP
 
; variables to store data
 
Row db 		? 
Col db 		?
Colour db 	?
Char db 	?
 
end Start

Passing through Stack

This is the most powerful and flexible method of passing parameters the problem is that it is more complicated.

; this a procedure to print a block on the screen using the 
; stack to pass parameters (cursor position of where to print it
; and colour).
 
.model tiny 
.code
org 100h
 
Start: 
 
mov dh,4 	; row to print string on
mov dl,5 	; column to print string on
mov al,254 	; ascii value of block to display
mov bl,4 	; colour to display character
push dx ax bx 	; put parameters onto the stack 
 
call PrintString ; print our string
 
pop bx ax dx 	;restore registers
mov ax,4C00h 	;terminate program 
int 21h
 
PrintString PROC NEAR
 
push bp 	; save bp
mov bp,sp 	; put sp into bp
push cx 	; save registers to be destroyed
 
xor bh,bh 	; clear bh - video page 0
mov ah,2 	; function 2 - move cursor
mov dx,[bp+8] 	; restore dx
int 10h 	; call bios service
 
mov ax,[bp+6] 	; character
mov bx,[bp+4] 	; attribute
xor bh,bh 	; display page - 0
mov ah,9 	; function 09h write char & attrib 
mov cx,1 	; display it once
int 10h 	; call bios service
 
pop cx 		; restore registers
pop bp 
 
ret 		; return to where it was called
PrintString ENDP
 
end Start

This shows the stack for a procedure with two parameters:

To get a parameter from the stack all you need to do is work out where it is. The last parameter is at BP+2 and then the next and BP+4.

What are "Memory Models"?

We have been using the .MODEL directive to specify what type of memory model we use, but what does this mean?

Syntax: .MODEL MemoryModel

Where MemoryModel can be SMALL, COMPACT, MEDIUM, LARGE, HUGE, TINY or FLAT.

Macros (in Turbo Assembler)

Note: All code examples given are for macros in Turbo Assembler.

Macros are very useful for doing something that is done often but for which a procedure can't be used. Macros are substituted when the program is compiled to the code which they contain.

This is the syntax for defining a macro:

Name_of_macro macro 
;
;	a sequence of instructions 
;
endm

These two examples are for macros that take away the boring job of pushing and popping certain registers:

SaveRegs macro
 
push ax
push bx
push cx
push dx
 
endm
RestoreRegs macro
 
pop dx
pop cx
pop bx
pop ax
 
endm

Notice that the registers are popped in the reverse order to they were pushed. To use a macro in you program you just use the name of the macro as an ordinary instruction:

SaveRegs
 
; some other instructions
 
RestoreRegs

This example shows how you can use a macro to save typing in. This macro simply prints out a message to the screen.

OutMsg macro SomeText
local PrintMe,SkipData
 
jmp SkipData
 
PrintMe db SomeText,'$'
 
SkipData:
 
push ax dx cs 
 
mov dx,OFFSET cs:PrintMe
mov ah,9
int 21h
 
pop cs dx ax
 
endm

The only problems with macros is that if you overuse them it leads to you program getting bigger and bigger and that you have problems with multiple definition of labels and variables. The correct way to solve this problem is to use the LOCAL directive for declaring names inside macros.

Syntax: LOCAL name

Where name is the name of a local variable or label.

Macros with parameters

Another useful property of macros is that they can have parameters. The number of parameters is only restricted by the length of the line.

Syntax:

Name_of_Macro macro par1,par2,par3
;
; commands go here
;
endm

This is an example that adds the first and second parameters and puts the result in the third:

AddMacro macro num1,num2,result
 
push ax 	; save ax from being destroyed
mov ax,num1 	; put num1 into ax
add ax,num2 	; add num2 to it
mov result,ax 	; move answer into result
pop ax 		; restore ax
 
endm