0% found this document useful (0 votes)
9 views

Asm03 AsmIntro

Uploaded by

Can Ilica
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
9 views

Asm03 AsmIntro

Uploaded by

Can Ilica
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 24

What is Assembly Language?

NASM and MASM


• In a high level language (HLL), one line of code • We will use NASM (Netwide Assembler) in this course
usually translates to 2, 3 or more machine • NASM is operating system independent
instructions –One of the two widely used Linux assemblers
Some statements may translate to hundreds or thousands of –The other is GAS (GNU assembler)
machine instructions
• The syntax differs significantly in many ways from
• In Assembly Language (AL), one line of code MASM (Microsoft Assembler)
translates to one machine instruction –MASM syntax is a standard that is almost always understood
AL is a "human readable" form of machine language by other x86 assemblers (TASM, CHASM, A386, etc.)
• HLLs are designed to be "machine-independent" –MASM syntax has some significant defects that makes coding
But machine dependencies are almost impossible to eliminate prone to error. Many of these are rectified in NASM
• ALs are NOT machine-independent • We will not cover NASM syntax in full depth
Each different machine (processor) has a different machine –We are interested in a basic machine interface, NOT a
language production assembler language
Any particular machine can have more than one assembly –NASM has many syntactic constructs similar to C
language –NASM has an extensive preprocessor similar to C’s

Basic Elements of NASM Assembler Literals


• Character Set • Literals are values are known or calculated at
Letters a..z A..Z () assembly time
Digits 0..9 • Examples:
Special Chars ? _ @ $ . ~ 'This is a string constant'
• NASM (unlike most assemblers) is case-sensitive with "So is this“
respect to labels and variables `Backquoted strings can use escape chars\n`
• It is not case-sensitive with respect to keywords, 123
mnemonics, register names, directives, etc. 1.2
0FAAh
• Special Characters
$1A01
0x1A01

Basic Elements: Integers Basic Elements: Statements


• Integers: numeric digits (incl A-F) with no decimal point • Syntactic Form:
• may include radix specifier at end: [label[:]] [mnemonic] [operands] [;comment]
b or y binary
• (Note: [label] can also be [name])
d decimal
Variable names are used in data definitions
h hexadecimal
Labels are used to identify locations in code
q octal
• Examples • Note that ALL parts are optional => blank lines are
200 decimal (default) legal
200d decimal • Statements are free form; they need not be formed
200h hex into columns
200q octal • Statement must be on a single line, max 128 chars
10110111b binary
• Example:
Note: Hexadecimal literals start with A-F must have a leading 0.
L100: add eax, edx ; add subtotal to running total
• Consider the constant AH = 10d. This is the name of a register. Consider
the constant 255d = FFH. This could be the name of a variable. • Labels often appear on a separate line for code clarity:
• NASM also supports other syntactic forms, e.g., 0xc8 or $c8 L100:
add eax, edx ; add subtotal to running total

1
Basic Elements: Labels and Names Types of Assembler “Statements”
• Names identify labels, variables, symbols, or keywords • Assembler "statements" fall into three broad classes:
• May contain: 1. Directives
A..Z,a..z limit EQU 100 ; defines a symbol limit
0..9 %define limit 100 ; like C #define
? _ @ $ . ~ CPU P4 ; Use Pentium 4 instruction set
• NASM is case-sensitive (unlike most x86 assemblers) 2. Data Definitions
• First character must be a letter, _ or “.” (which has a msg db 'Welcome to Assembler!'
special meaning in NASM as a “local label” which can be db 0Dh, 0Ah
redefined) count dd 0
mydat dd 1,2,3,4,5
• Names cannot match a reserved word (and there are
resd 100 ; reserves 400 bytes of
many!)
; uninitialized data
3. Instructions
mov eax, ebx
add ecx, 10

Variables, Labels and Constants Names, Labels and Colons


count1 db 100 ; variable called count1 count1 db 100 ; variable called count1
count2 times 100 db (0); variable called count2 (100 bytes) label1:
mov eax,0 ; label1 is the address of instruction
count3 EQU 100 ; constant called count3 ....
count4 EQU $ ; const count4 = address of str1 jmp label1
str1 DB 'This is a string' ; variable str1 16 bytes • In the code above, count1 is a variable and label1 is
slen EQU $-str1 ; const slen = 16
an address in code
label1: mov eax,0 ; label1 is the address of instruction NASM doesn’t care if you use a colon after the label or not
count1: db 100 ; variable called count1
.... label1
jmp label1 mov eax,0 ; label1 is the address of instruction
....
• Notes: count1 is the address of a single byte, count2 is the jmp label1
address of the first byte of 100 bytes of storage • Some other assemblers treat names with colons and
• Count3 does not allocate storage; it is a textual EQUate names without colons differently
(symbolic substitution; similar to C #define) The convention in x86 assembler is to use colons with
• The $ has a special meaning: the location counter labels in code and to use names without colons in data

What is a Variable Anyway? The Location Counter


count1 db 100 ; variable called count1 count1 db 100 ; variable called count1
count2 times 100 db 0 ; variable called count2 (100 bytes) count2 times 100 db (0); variable called count2 (100 bytes)
count3 EQU 100 ; constant called count3
• Variable names such as count1 and count2 represent count4 EQU $ ; const count4 = address of str1
str1 DB 'This is a string' ; variable str1 16 bytes
addresses
slen EQU $-str1 ; const slen = 16
• The only information that the assembler associates with a • The symbol $ refers to the location counter
variable is the location counter (current address) of the • As the assembler processes source code, it emits either code or data
item you declared at that address into the object code.
• Arrays are a fiction imposed by HLLs. They do not exist at • The location counter is incremented for each byte emitted
the machine level. The assembler sees no difference • In the example above, count4 is numerically the same value as str1
between count1 and count2 except for the address (which is an address)
• With slen EQU $-str1 the assembler performs the arithmetic to
compute the length of str1
• Note the use str1 in this expression as a numeric value (the address of
the first byte)

2
Keywords Hello World (MASM MS-DOS)!
• Keywords can be register names , instruction dosseg
.model small
mnemonics, assembler pseudo-ops and directives .stack 100H
• Examples .data
eax mov proc db hello_message db 'Hello, World!',0dh,0ah,'$'
.code
ah add sub .IF
main proc
ASSUME END .WHILE SHLD mov ax, @data
mov ds,ax
• If you accidentally use a keyword as a variable name mov ah,09
mov dx,offset hello_message
you may get a misleading error message
int 21H
mov ax,4c00h
int 21h
main endp
end main

Hello World (NASM Linux)! Hello World (NASM Windows)


SECTION .data ; data section global _main
extern _GetStdHandle@4
msg: db "Hello World",10 ; the string to print, 10=cr extern _WriteFile@20
extern _ExitProcess@4
len: equ $-msg ; len is a value, not an address section .text
_main:
; DWORD bytes;
SECTION .text ; code section mov ebp, esp
global main ; make label available to linker sub esp, 4
; hStdOut = GetstdHandle( STD_OUTPUT_HANDLE)
main: ; standard gcc entry point push -11
mov edx,len ; arg3, length of string to print call _GetStdHandle@4
mov ebx, eax
mov ecx,msg ; arg2, pointer to string ; WriteFile( hstdOut, message, length(message), &bytes, 0);
mov ebx,1 ; arg1, where to write, screen push 0
lea eax, [ebp-4]
mov eax,4 ; write sysout command to int 80 hex push eax
push (message_end - message)
int 0x80 ; interrupt 80 hex, call kernel
push message
push ebx
call _WriteFile@20
mov ebx,0 ; exit code, 0=normal ; ExitProcess(0)
mov eax,1 ; exit command to kernel push 0
call _ExitProcess@4
int 0x80 ; interrupt 80 hex, call kernel message:
db 'Hello, World', 10
message_end:

Hello World (NASM Linked with C - Windows) Hello World (NASM Linked with C - Linux)
global _main global main
extern _printf extern printf

section .text section .text


_main: main:
push message push message
call _printf call printf
add esp, 4 add esp, 4
ret ret
message: message:
db 'Hello, World', 10, 0 db 'Hello, World', 10, 0

3
Object Code, Load Images, Linkage Overview and Grouping of x86 Instructions
• In a high-level language, the process of producing an executable • Assembler Instructions can be categorized by
program looks like this: function:
Source code object code executable program 1. Data Movement
Compile Link
2. Arithmetic and Comparison
• Object code modules are language-independent linker inputs
• An executable program may not contain "pure machine
3. Bit and Logical Operations
language" : it may have unresolved memory references, 4. Character Operations
function calls, etc. 5. Control Flow
6. Miscellaneous
Executable Program Load Image Run
7. Semaphore and Process Sync (486+)
OS program loader Load IP
8. System Programming Instructions
• In the list below, 16/32 bit instructions are in all
• The operating system supplies a "program loader" that resolves
these references and creates a "load image"
uppercase while 32-bit only instructions are
lowercase
• The load image is pure machine language
• Assembler mnemonics are NOT case-sensitive;
either can be used

Data Movement Instructions Arithmetic and Comparison Instructions


• Moving Data: • Addition:
MOV, PUSH, POP, XCHG, PUSHA, POPA ADC, ADD, INC
movsx, movzx, pushd, popd, pushad, popad • Subtraction and Comparison
CMP, DEC, NEG, SBB, SUB, setcc
• I/O: IN, OUT, ins, outs • Multiplication:
MUL, IMUL
• Address Loading: LDS, LEA, LES, lfs, lss, lgs • Division:
DIV, IDIV
• Flag Transfer: • Sign Extension:
LAHF, SAHF, PUSHF, POPF, pushf, popfd CBW, CWD, cwde, cdq
• BCD Arithmetic:
DAA, DAS, AAA, AAS, AAM, AAD

Bit and Logical Operations Character Operations


• Logical: • Table Lookup
AND, TEST, OR, XOR, NOT XLAT
bt, btr, bts, btc, bsf, bsr • Block (String) Moves:
MOVS, LODS, STOS
• Shifts: • Block (String) Comparison:
SAL, SHL, SAR, SHR CMPS, SCAS
shld, shrd
The block instructions can be suffixed with an operand size,
for example MOVSB, MOVSW, movsd
• Rotations:
RCL, RCR, ROL, ROR
• Repetition Prefixes:
REP, REPE, REPZ, REPNE, REPNZ

4
Control Flow Miscellaneous
• Unconditional Jump: • External Synchronization:
JMP ESC, HLT, LOCK, WAIT
• Subroutine Call: • Space Filling/Time Wasting:
CALL, RET NOP (No OPeration)
• Conditional Jumps:
• Stack frame:
JA, JAE, JB, JBE, JC, JCXZ, JE, JG, JGE, JL,
JLE, JNA, JNAE, JNB, JNBE, JNC, JNE, JNG, ENTER, LEAVE
JNGE, JNL, JNLE, JNO, JNP, JNS, JNZ, JO, JP, • Array bound testing:
JPE, JPO, JS, JZ BOUND
The above conditionals are not all distinct
• Endian reversal
• Loops:
bswap 486+
LOOP, LOOPE, LOOPNE, loopd, loopdne, loopde
• Interrupts:
• Misc Pentium:
INT, INTO, IRET rdmsr, wrmsr, rdtsc, cpuid, rsm
• Flag Control: • Semaphore and Process Sync (486+)
CLC, CLD, CLI, CMC, STC, STD, STI xadd, cmpxchg, cmpxchg8b

System Instructions Data Definition


• 80286+
• A variable is a symbolic name for a location
lgdt, lldt, lidt, sgdt, sldt, sidt, arpl, lar,
lsl, verr, verw, clts, smsw, lmsw in memory where some data are stored
• 80386+ Variables are identified by names
invd, invlpg, wbinvd, mov (cr, dr, tr)
The offset address associated with the name is the
• The miscellaneous and systems instructions will not be covered
in detail in this course distance from the beginning of the segment to the
• NOP is worth mentioning however-it does nothing at but occupy beginning of the variable
space and slow down programs (it does take time to execute) • A variable name does not indicate how much
• A NOP instruction is a one-byte instruction that takes a small
amount of time (1-3 clock ticks) to execute storage is allocated
• Used for: • Assemblers associate some minimal type
leaving room to patch machine code
aligning instructions on address boundaries information with names to help prevent
very short delays in loops errors
• Implemented as xchg eax, eax (exchange eax with
NASM allows you to shoot yourself in the foot a bit
itself)
more than other assemblers

Intialized Data Definitions Initialized Data


• Allocates storage for one or more values • NASM initialized data directives go into the data
• The name is optional segment
segment .data
• May be followed by a list of values
• Data definition directives cause the assembler to
• Only the first value is "named"
allocate storage and associate some type (size)
• A variable name is just a synonym for a numeric information with the name
address Description Size"Type"
db Define Byte 1 Byte
dw Define Word 2 Word
• Other values can be accessed via an offset from the
dd Define Doubleword 4 Doubleword
name:
df,dp Define FarWord 6 far pointer
foo dw 3,4,99,1202,-3
dq Define Quadword 8 quad word
... dt Define Tenbyte 10 tenbyte
mov ax, foo+2; load second element of array
• Programmers conventionally refer to “dword”,
; same as mov ax, [foo+2]
“qword” and even “fword” instead of the full names

5
Data Definition Syntax Uninitialized Data
• NASM has different syntax for initialized and • NASM uses different syntax for uninitialized
uninitialized values data, which goes into the “bss” segment
• INITIALIZED VALUES: segment .bss
• [name] Dx initialvalue [,initialvalue]
• Just like Dxx but use resXX with the number
where Dx is
db byte
of objects needed
buffer resb 64 ; reserve 64 bytes
dw word wordvar resw 1 ; reserve a word
dd double word realarray resd 10 ; array of ten dwords
df far pointer (6-byte) qval resq 1 ; 1 qword
dq quad word
dt ten-byte

• For this course, we will generally use db, dw, and


dd, dq only

Historical Relic Examples


• BSS came from “Block Started by Symbol” , an • This example also shows how little-endian memory
assembler for IBM 704 in the 1950s works
msg db "ASM is fun!",0dh,0ah
• Almost universally used by C and C++ compilers today db "(for masochists)"
byt db 12h, 34h, 56h, 78h
wrd dw 1234h, 5678h
dwd dd 12345678h
qwd dq 12345678h
one dd 1.0

• Displayed by debug:
0EB4:0100 41 53 4D 20 69 73 20 66 ASM is f
0EB4:0108 75 6E 21 0D 0A 28 66 6F un!..(fo
0EB4:0110 72 20 6D 61 73 6F 63 68 r masoch
0EB4:0118 69 73 74 73 29 12 34 56 ists).4V
0EB4:0120 78 34 12 78 56 78 56 34 x4.xVxV4
0EB4:0128 12 78 56 34 12 00 00 00 .xV4....
0EB4:0130 00 00 00 80 3F 72 6F 6D ....?rom

IEEE Floats Pointers in Data Definitions


• Note that assemblers will assemble IEEE format • The offset of a variable or instruction can be stored
numbers. in a pointer
list dw 1,2,3,4
lptr dd list
INT100 DD 100 ; 32 bit integer with value 100
sstr db 'This is a string',0dh,0Ah
FLT100 DD 100.0 ; IEEE float sptr dd sstr
DBL100 DQ 100.0 ; IEEE double (64-bit) p2 dd lptr
EXT100 DT 100.0 ; IEEE extended (80-bit) cls dd clear_screen

• The decimal point cues the assembler to construct clear_screen:


and emit a floating point number ; asm code to clear the screen
ret
• Numbers with a decimal point can only appear in
• Lptr is initialized to the address represented by list;
data definitions; they are never used as literals in likewise for sptr and p2
code
• p2 is a “pointer to a pointer”
• cls is a pointer to a function

6
The TIMES prefix Basic Instructions
• The TIMES prefix causes the data definition or • We will start taking a tour through the basic parts of
instruction to be assembled multiple times. Ex: the x86 instruction set
zerobuf TIMES 2048 db 0 • For each instruction, we need to look at the syntax,
Initializes a 2048 byte variables call zerobuf semantics (effects on operands and flags) and what
• The argument to TIMES is an expression legal operands may be used
buffer: db ’hello, world’ • Operand abbreviations:
times 64−$+buffer db ’ ’ reg 8,16, or 32-bit register except segment regs
• TIMES can also be applied to instructions to provide imm immediate operand
trivially unrolled loops mem 8,16, or 32-bit memory cell
TIMES 32 add eax, edx segreg segment register
• In .bss (uninitialized data) these are equivalent: reg16 16-bit register except segreg
TIMES 1000 resd 1 mem16 16-bit word in memory
resd 1000 reg8, mem8 8-bit register/memory
But the latter assembles 1000 times faster reg32, mem32 32-bit register/memory

MOV (Move) Operands


• Used to copy (not move) values from one place to • Instructions with register operands are the most efficient
another. 2-3 times faster than L1 cache access
• Some other architectures use two or more different Perhaps 1000 or more times faster than a cache
instructions: LOAD (mem->reg) and STORE (reg->mem) • Immediate operands are constants
Immediate operands are coded into the instruction itself
• Syntax:
MOV destination, source mov eax, 5 assembles the "5" into an 8 or 32-bit word within the
instruction
NOTE THE ORDER OF THE OPERANDS!
• Note that immediate operands can written in assembly language
• Semantics: as expressions that are evaluated at time of assembly
destination <- source; source unaltered
mov eax, 65536/4
Flags: ODITSZAPC unchanged
mov ecx, 0ffceh shl 4
• Operands: But not:
reg,reg mem,reg reg,mem mov eax, ebx / 16
reg,imm mem,imm
• Expression used for immediate operands must be resolvable by
reg16,segreg mem16,segreg
the assembler
segreg,reg16 segreg,mem16

Assembler vs. HLL Direct Operands


• The illegal instruction mov eax, ebx/16 looks a lot • A direct operand refers to the contents of memory at
like the assignment statement a = b / 16; the offset of a variable
• But in assembler we have to “operate” the machine. count db 0
mov eax, ebx ; copy eax to ebx ...
push edx ; save edx mov al,[count]
mov dx, 16 ; prep for 32-bit division
div dx ; eax = eax/16
• This is called a "direct" operand because it is a direct
pop edx ; restore register
memory access
• Note: there is an easier way • The address of the operand is encoded into the
mov eax, ebx ; copy ax to bx
instruction
sar eax, 4 ; sar = Shift Arithmetic Right • This instruction loads from memory at the address
given by count
• In debug, if count is at address 4010013Eh, the above
instruction would appear as
mov al,[4010013E]

7
Values and Addresses MOV examples
• In NASM a variable name is an address •Includes some indirect addressing
mov ebx, count ; load address of count mov eax,ebx eax <- contents of ebx
mov ebx, [count] ; load value of count mov eax,[ebx] eax <- contents of word at address ds:ebx
• Note that while value arithmetic in a statement is mov eax,[ebx+4] eax <- contents of word at address ds:ebx+4
NOT legal, address arithmetic often IS legal mov ax,[ebx] ax <- contents of word at address DS:EBX
mov eax,1234ffeeh eax <- 1234ffeeH
(remember the function of the bus interface unit)
mov ah,[ebx+esi] AH <- contents of byte at
mov ebx, count+2 ; OK, load addr of count+2
address ds:ebx+esi
mov ebx, [count]+2 ; ILLEGAL
mov ds,ax ds <- contents of ax
mov ebx, [count+2] ; OK, Load 32-bit located mov [edx],0100h Word at address ds:edx <- 100H
; at address of count + 2 mov ebx, 0100h BX <- 100h
mov [0122h],es Word at addr DS:0122H <- contents of es
mov es,ax ES <- Contents of ax
MOV [SavEAX],eax Stores contents of eax into SavEAX
MOV SaveEAX,eax Not legal in NASM

Square Brackets Displacements


• Square brackets around an operand indicate either • While you cannot use arithmetic expressions in operands
direct or indirect addressing, but always a memory you can perform address arithmetic with direct or
reference (except for LEA instruction) indirect operands:
• If the operand is a register, square brackets indicate mov eax,[ebx+4] ;eax <-contents of word at address ebx+4
indirect addressing ;mov eax, ebx+4 ! Not legal. Requires two instructions:
mov eax,[ebx] ;eax <-contents of dword at address ebx mov eax, ebx
mov eax, ebx ;eax <-contents of ebx add eax, 4
• If the operand is a number, square brackets indicate • The bus interface unit has adder circuitry used in
direct addressing calculating effective addresses
mov eax,[10A8h] ;eax <-contents of word at address DS:[10A8h]
mov eax, 10A8h ;eax <-10a8h • The literal value 4 in [ebx+4] is called a displacement
• If the operand is a variable name, square brackets • Displacements can also be used variable names are
indicate direct addressing involved:
mov eax,[count] ;eax <-contents of word at addr DS:count mov eax,[data+4] ; eax <-contents of dword at address data+4
• Remember that variable names are symbols representing
addresses.

Limitations of MOV Offsets and Addresses


• Note that an instruction such as MOV DS,0040H is illegal • A memory operand is really a numeric constant at
• Segment registers cannot be loaded from immediate operands run-time--the address of the variable
• To load the value 0040H in DS:
MOV AX,0040H
MOV DS,AX • Can use offset from an address to access additional
• Limitations of MOV memory
- cannot have CS or IP as destination
- cannot move immediate data to segment register • Example
- cannot move from segment register to segment register .data
- source and destination operand must be same size array dd 11,12,13,14,15,16 ; array of 6 words
- cannot have immediate value as destination .code
- cannot move memory-to-memory
mov eax,[array] ;load first element
• Get around limitations by using other instructions:
; MOV DS, ES is illegal
mov ebx,[array+4] ;2nd element of array
PUSH ES add ebx,eax ;add the two elements
POP DS mov [array+8],ebx ;store to 3rd element
• Note that the MOV mnemonic represents seven different
machine language instructions. More on this later

8
Assembler is not C or Java A First Program
• In C or Java indexes in an array are compiled to • This program prompts the user to enter two numbers
correct element size: and then displays the sum
%include "asm_io.inc"
• C/Java Asm equivalent
;
int x,y; x dd 0
; initialized data is put in the .data segment
int a [5]; y dd 0 ;
... a TIMES 5 dd 0 segment .data
x = 5; mov [x],5 ;
y = a[1]; mov ebx, a ; These labels refer to strings used for output
a[2] = x+y; mov edx,[ebx+4] ;
mov [y], edx prompt1 DB "Enter a number: ", 0 ; don't
forget nul terminator
add edx, [x]
prompt2 db "Enter another number: ", 0
mov [ebx+8], edx
outmsg1 db "You entered ", 0
• In assembler we have offsets not indices (in example outmsg2 db " and ", 0
above an int is 4 bytes) outmsg3 db ", the sum of these is ", 0

A First Program-2 A First Program-3


; segment .text
global _asm_main
; uninitialized data is put in the .bss segment
_asm_main:
; enter 0,0 ; setup routine
segment .bss PUSHA
; MOV EAX, prompt1 ; print out prompt
call print_string
; These labels refer to double words used to
store the inputs call read_int ; read integer
mov [input1], eax ; store into input1
; mov eax, prompt2 ; print out prompt
input1 resd 1 call print_string
input2 resd 1 call read_int ; read integer
; mov [input2], eax ; store into input2

; code is put in the .text segment mov eax, [input1] ; eax = dword at input1
; add eax, [input2] ; eax += dword at input2
mov ebx, eax ; ebx = eax
dump_regs 1 ; dump out register values
dump_mem 2, outmsg1, 1 ; dump out memory

A First Program-4 A Program Skeleton


; ; file: skel.asm
; next print out result message as series of steps ; This file is a skeleton that can be used to start asm programs.
; %include "asm_io.inc"
mov eax, outmsg1 segment .data
; initialized data is put in the data segment here
call print_string ; print out first message
;
mov eax, [input1]
segment .bss
call print_int ; print out input1 ;
mov eax, outmsg2 ; uninitialized data is put in the bss segment
call print_string ; print out second message ;
mov eax, [input2] segment .text
call print_int ; print out input2 global _asm_main
mov eax, outmsg3 _asm_main:
call print_string ; print out third message enter 0,0 ; setup routine
mov eax, ebx pusha
; code is put here in the text segment. Do not modify the code
call print_int ; print out sum (ebx)
; before or after this comment.
call print_nl ; print new-line ;
popa
popa mov eax, 0 ; return back to C
mov eax, 0 ; return back to C leave
leave ret
ret

9
PUSH and POP POP
• Used to store and retrieve data from the stack • POP Syntax:
• PUSH and POP work with words or dwords only (not bytes POP dest POPD Dest
• To PUSH a byte it has to be extended to a word • Semantics:
• PUSH Syntax: (1) dest <- [SS:SP] | dest <- [SS:ESP]
PUSH source PUSHD source (2) SP <- SP + 2 | ESP <- ESP+4
• Semantics: (16|32) Flags: ODITSZAPC unchanged
(1) SP <- SP-2 | ESP <- ESP-4 • Operands:
(2) [SS:SP] <- source | [SS:ESP] <- source reg16 mem16 segreg reg32 mem32
Flags: ODITSZAPC unchanged
• Operands: • Notes:
reg16 mem16 segreg reg32 mem32 imm esp is decremented as stack grows
• Notes: esp always points to last item on stack, not to the next available
word (except when stack is empty)
1. In 32-bit code, PUSHD is necessary for imm operands only; push
eax is unambiguous POPD syntax only necessary when dest is not a register

• Other instructions that affect the stack (CALL and RET) will be
discussed later

Variations on a Theme:PUSHA, PUSHF, POPA, POPF POPF (POP Flags)


• PUSHF (PUSH Flags) • Purpose: Word at top of stack copied to Flags register.
• Syntax: POPF | POPFD
• Purpose: Push a copy of the flags register onto the
• Semantics:
stack.
(1) Flags <- [SS:SP] | Eflags <- [SS:ESP]
• Syntax: PUSHF | PUSHFD
(2) SP <- SP + 2 | ESP <- ESP + 4
• Semantics: • Notes:
(1) SP <- SP-2 | ESP <- ESP-4 1. PUSHF and POPF can be used to save the state of the flags register before
(2) [SS:SP] <- Flags register calling a subroutine.
2. POPF is the only instruction that allows modification of the Trap Flag, except
[SS:ESP] <- EFLAGS that it is cleared when an INT is executed.
3. O = bit Bh; D = bit Ah; I = bit 9; T = bit 8; S = bit 7; Z = bit 6; A = bit 4; P = bit
2; C = bit 0
4. This instruction and SAHF are the only ways that the x86 can directly modify
the SZAP bits in the flags register. Note that the ODIT bits cannot be accessed
only with POPF, although there are instructions that work directly with D and I.
5. POPF/POPFD have more complex semantics in 386+ processors as OS may not
allow direct control of IF

PUSHA, PUSHAD, POPA, POPAD XCHG


• PUSHA and POPA became available on the 80186. • How do you swap the contents of two registers? You need a third
"place" to put the data
PUSHA pushes eax, ebx, ecx, edx,original esp, ebp, esi, edi in mov [temp],eax
that order mov eax,ebx
POPA pops them back in reverse order mov ebx,[temp]
• XCHG does this in one instruction
xchg eax,ebx
• PUSHAD and POPAD are used to distinguish 32 • Syntax:
variants where there might be some question about XCHG dest1, dest2
whether 32 or 16 bit registers are intended • Semantics:
dest1 <- dest2
dest2 <- dest1
• We’ll just keep it simple and use PUSHA and POPA Flags: ODITSZAPC unchanged
• Operands (order is irrelevant)
reg,reg mem,reg reg,mem
• Generally PUSHA it is more efficient than pushing 1. At least one operand must be in a general register.
individual registers if more than 4 registers must be 2. Cannot use XCHG with seg regs or mem/mem
3. Note that the assembler NOP (No Operation) instruction is actually
saved assembled as XCHG eax, eax

10
Operand Size Specification Operand Size Specifiers
• With many instructions size of operand can be inferred from • Register references can be resolved by size of register
instruction itself. Examples: • Some memory references can be resolved by known size of other
PUSH AX operand
pop ecx
mov ah, [edx]
• Memory-immediate references are usually ambiguous
• Operand size specifiers byte, word, dword etc are used to
• With other instructions size of one operand can be inferred from
resolve ambiguous references
size of the other operand.
add dword [esi],1
• Examples: (ebx = 007Ah)
add byte [esi],1
MOV ah,[ebx] refers to a byte at address [ebx]
MOV ax,[ebx] refers to a word at address [ebx] add word [esi],1
ADD [ebx],FFFFFFFFh adds to dword at [ebx] • Because NASM does not associate declared size with variables, you
ADD [ebx],1 ??
must specify operand size when adding imm to memory
AND [ebx],0DFh ??
myvar dd 0
• What if memory at [ebx] = FF 00 00 00?
ADD [ebx],1 results in 00 10 00 00 for a 16 or 32-bit add add dword [myvar],1
ADD [ebx],1 results in 00 10 for a 16-bit add
ADD [ebx],1 results in 00 00 for a 16-bit add
(remember little-endian ordering: FF 00 is 00 FF)

Add and Sub Clearing a Register


• For both signed and unsigned addition and subtraction • Often we need to clear a register (set it to 0)
• Remember when using them that addition is commutative but
subtraction is not • Preferred technique is to use SUB or XOR (discussed
• Syntax: later)
ADD dest, source sub eax, eax is a small, fast 2 byte instruction
SUB dest, source mov eax,0 is a slightly slower 3 (or 6) byte instruction
• Semantics: • Although sub eax, eax and mov eax, 0 have
dest <- dest + source
the same effect on EAX, the semantics are different.
dest <- dest - source
How?
Flags: O . . . SZAPC modified for sum/difference
. DIT . . . . unchanged • When would you prefer to use mov eax, 0 ?
• Note that addition and subtraction modify ALL status flags
• Operands:
• Note that to clear memory, a MOV is required
reg,reg mem,reg reg,mem
because you cannot do a mem-mem subtract
reg,immed mem,immed
• Note immediate add to memory: you can do arithmetic without using
registers at all.

Using the Flags ADC and SBB


• Because ADD and SUB affect the flags, you can test • Add with carry and subtract with borrow
for conditions without using a CMP (compare) • Used to implement arithmetic with words larger than
instruction: register size
• Use this: Not this: • Syntax:
add ebx, ecx add ebx, ecx ADC dest source
jz done cmp ebx, 0
SBB dest source
je done
• Semantics:
dest <- dest + source + CF
• More about this when we look at conditional jumps dest <- dest - source - CF
Flags: O...SZAPC modified
.DIT.... unchanged
• Operands:
reg,reg mem,reg reg,mem
reg,immed mem,immed

11
ADC Example Compare (CMP)
• Example: Unsigned 32-bit addition in 16-bit machine • Compare (CMP) is subtraction without storage of the
vars dd 2 dup (?) ; two 32-bit vars
. . . ; var[0] = 0000fffe (65,534) var[1]=00000003 = 3
result. Only the flags are affected
mov si, vars • Syntax:
mov ax, [si] ; low-order word
mov dx, [si+2]; high-order word CMP dest, source
add [si+4],ax ; add ax into low order word
adc [si+6],dx ; add dx into h.o. word with CF
• Semantics:
compute dest - source and modify flags
FE FF 00 00 03 00 00 00
Flags: O...SZAPC modified
SI
.DIT..... unchanged
mov ax, [si] ; AX = FFFE • Operands:
mov dx, [si+2]; DX = 0000 reg,reg mem,reg reg,mem
add [si+4],ax ; FFFE + 0003 = 0001 CF Set reg,immed mem,immed
adc [si+6],dx ; 0000 + 0000 + 1(cf) = 1
• Notes:
;result: 00010001h = 65536 + 1 = 65537
Operands same as SUB; can compare immed to mem
FE FF 00 00 01 00 01 00 We will discuss in more detail with conditional jumps

INC and DEC CF


• How many times have you written something like this: • The answer is that inc eax leaves CF unmodified
for (i = 0; i < 100; i++) {...
• We increment (add 1) or decrement (subtract 1) so often that
• If eax = 0FFFFFFFFh, then CF will be set by
special instructions are provided for these operations add eax, 1
• INC and DEC are one-operand instructions
• Syntax:
INC dest • This seems a rather strange and arbitrary warp in the
DEC dest semantics of the instruction
• Semantics: • There is however a good reason: INC and DEC are
dest <- dest + 1 often used for address arithmetic (incrementing and
dest <- dest - 1
decrementing index registers)
Flags: O...SZAP. Modified
Multi-word arithmetic is usually done in a loop with index
.DIT....C unchanged
registers pointing to operands
• Operands:
CF is especially significant in multi-word arithmetic
reg mem
We’ll see an example later
• CAUTION: inc eax is NOT ALWAYS a substitute for add eax, 1
• Why?

Register-Indirect Addressing Multiplication


• A register can be used to access memory • Multiplication is available in 8, 16 and 32 bits
compare 8-bit multiplication multiplies 2 8-bit operands and produces
MOV eax, ebx ; copy ebx into eax a 16 bit result. One operand is in AL, result is in AX
with
MOV eax,[ebx]; load eax with dword 16-bit multiplication multiplies 2 16-bit operands and
; whose address is in ebx produces a 32 bit result. One operand is in AX, result is in
DX:AX
• The use of a register to hold an address is called
indirect addressing 32-bit multiplication multiplies 2 32-bit operands and
• eax, ebx, ecx, edx, esi, edi, esp and ebp can all be produces a 64 bit result. One operand is in eax, result is in
used for indirect addressing eax:edx
• We will cover this in more detail later • Even if the product of 2 k-bit operands is only k bits
long, the upper k bits of the 2k-bit result are cleared
(MUL) or set to the top-order bit of the product
(IMUL)

12
Multiplication & Division MUL (unsigned MULtiply)
• x86 multiplication and division instructions are much • Syntax: MUL source
more restricted than addition or subtraction • Semantics:
AX <-- AL * source8
• Both require the use of the accumulator register (al, DX:AX <-- AX * source16
ax, or eax) edx:eax <-- eax * source32
Flags: O.......C modified
....SZAP. undefined
• Unlike addition and subtraction, multiplication and .DIT..... unchanged
division have separate instructions for unsigned and
signed operands • Operands:
regmem NOTE: No Immediate
• Overflow and Carry flags are identical after a
• Unsigned: MUL, DIV multiplication
• Signed: IMUL, IDIV 0 = entire product is available in low-order part (AL, AX or
eax)
1 = product occupies both parts (AX, DX:AX or eax:edx)

IMUL (Integer MULtiply) 3-Address IMUL


• Syntax: IMUL source • In the 32-but instruction set, IMUL is extended to a 3
• Semantics: -operand instruction and an (apparent) immediate 2-
AX <-- AL * source8 operand instruction
DX:AX <-- AX * source16 • imul dest, source1, source2
edx:eax <-- eax * source32 IMUL reg, imm IMUL cx, 100 cx<- cx*100
Flags: O.......C modified . IMUL reg, r/m,imm IMUL ecx,edx,3 ecx<- edx * 3
..SZAP.. undefined IMUL reg, reg IMUL cx, dx cx<- cx * dx
.DIT..... unchanged Note: 2 operand IMUL cx, 100 == IMUL cx, cx,
• Operands: 100
regmem NOTE: No Immediate! • Operands:
• Overflow and Carry flags are identical after a reg16, imm reg32, imm
multiplication reg16, reg/mem16, imm reg32, reg/mem32 imm
0 = entire product is available in low-order part (AL, AX or reg16, reg16 reg32, reg32
eax)
1 = product occupies both parts (AX, DX:AX or eax:edx)

Limitations of IMUL Immediate Overflow / Carry with MUL and IMUL


• Note that the MUL instruction was never extended in • Overflow and carry indicate if LOW-ORDER part of
this fashion product is valid alone
• When using IMUL in this form the upper half of the • Each sequence below starts with MOV AL,42D
product is discarded; result is same as unsigned. 1) MOV BL,3
IMUL BL O = 0 C = 0; AX = 126 (AL = 126)
• It can only be used for "small" products that do not
exceed n bits for n-bit source operands 2) MOV BL,5
IMUL BL O = 1 C = 1; AX = 210 (AL = -46)

3) MOV BL,5
MUL BL O = 0 C = 0; AX = 210 (AL = 210)

4) MOV BL,7
IMUL BL O = 1 C = 1; AX = 294 (AL = 38)

13
Division: DIV and IDIV DIV and IDIV
• DIV for (unsigned) numbers and IDIV (signed) • Syntax:
DIV source
• 8-bit division requires a 16-bit dividend in AX and an 8- IDIV source
bit divisor in an 8-bit location. • Semantics:
If the quotient requires more than 8 bits, then a divide overflow AL <-- quotient of AX / source8
error is generated. AH <-- remainder of AX / source8
OR:
This causes an INT 0 exception; the default INT 0 handler
AX <-- quotient of DX:AX / source16
terminates the program, displays a "Divide Overflow" message and
DX <-- remainder of DX:AX / source16
returns to the OS
OR:
• In 8-bit division the quotient goes into AL and the eax <-- quotient of edx:eax / source32
remainder into AH. edx <-- remainder of edx:eax / source32
Processor generates INT 0 exception if quotient too large or attempt to
• 16-bit division requires a 32-bit dividend in DX:AX and a divide by 0
16-bit divisor in a 16-bit location. Flags: O...SZAPC undefined
.DIT..... unchanged
• 32-bit division requires a 64-bit dividend in edx:eax and • Operands:
a 32-bit divisor in a 32-bit location. reg mem NOTE: No Immediate
• Note that all status flags are undefined after DIV or IDIV

Remainders and Modulus NOT


• Note that integer division satisfies the relation: • Used to logically negate or complement an operand
N = quotient * divisor + remainder • Same effect can be achieved with XOR but if the
• There is some disagreement about the meaning of entire operand has to be complemented then NOT is
the modulus function when the dividend is negative faster
MOV AX,-3 • Syntax:
MOV BL,-2 NOT dest
IDIV BL AH (rem) <- FF (-1); AL <- 01 • Semantics:
MOV AX,-3 dest <- NOT dest
Flags: ODITSZAPC unchanged
MOV BL,2
IDIV BL AH (rem) <- FF (-1); AL <- FF • Operands:
reg mem
• Notes:
1. NOT is a unary operation
2. NOT is logical negation (1's complement); every bit is
inverted; NEG is the two's complement negation
3. Unlike other boolean operations NOT has no effect on the
flags

NEG Arithmetic Example: math.asm


%include "asm_io.inc"
• NEG (NEGate) is 2's complement negation segment .data
• Like NOT it is a single operand instruction ;
; Output strings
• Subtracts operand from 0 and replaces it with result ;
• Syntax: prompt db "Enter a number: ", 0
square_msg db "Square of input is ", 0
NEG dest cube_msg db "Cube of input is ", 0
• Semantics: cube25_msg db "Cube of input times 25 is ", 0
quot_msg db "Quotient of cube/100 is ", 0
dest <- 0 - dest
rem_msg db "Remainder of cube/100 is ", 0
Flags: O...SZAP. modified for result neg_msg db "The negation of the remainder is ", 0
.......C set if dest != 0 segment .bss
input resd 1
.DIT..... Unchanged
segment .text
• Operands: global _asm_main
reg mem _asm_main:
enter 0,0 ; setup routine
• Notes: pusha
CF is the complement of ZF

14
math.asm:2 math.asm:3
mov eax, prompt mov ebx, eax
call print_string imul ebx, [input] ; ebx *= [input]
mov eax, cube_msg
call read_int call print_string
mov [input], eax mov eax, ebx
call print_int
imul eax ; edx:eax = eax * eax call print_nl
mov ebx, eax ; save answer in ebx
mov eax, square_msg imul ecx, ebx, 25 ; ecx = ebx*25
call print_string mov eax, cube25_msg
mov eax, ebx call print_string
call print_int mov eax, ecx
call print_nl call print_int
call print_nl

math.asm:4 math.asm:5
neg edx ; negate the remainder
mov eax, ebx mov eax, neg_msg
; initialize edx by sign extension call print_string
cdq mov eax, edx
mov ecx, 100 ; can't divide by immediate value call print_int
idiv ecx ; edx:eax / ecx call print_nl
mov ecx, eax ; save quotient into ecx
mov eax, quot_msg popa
call print_string mov eax, 0 ; return back to C
mov eax, ecx leave
call print_int ret
call print_nl
mov eax, rem_msg
call print_string
mov eax, edx
call print_int
call print_nl

math.asm:2 Transfer of Control Instructions


mov eax, prompt • The basic transfer of control instructions are:
call print_string Unconditional Jumps (JMP)
Conditional Jumps (many)
call read_int Call and Return (CALL and RET)
mov [input], eax Interrupt and Interrupt Return (INT and IRET)
• Jumps are like GOTO statements in a high level language
imul eax ; edx:eax = eax * eax
• High level selection and iteration structures (if, while, for, etc.)
mov ebx, eax ; save answer in ebx are implemented at the machine level with jumps or branches –
mov eax, square_msg the term varies by processor
call print_string • Conditional jumps operate by inspecting one or more of the
mov eax, ebx flags
call print_int • Intel processors are CISC machines and provide other control
call print_nl structures also - mainly LOOP instructions and repeated string
instructions
• These are complex instructions and we will study them later

15
Short, Near, Far The JMP Instruction
• Before we examine jumps we need to look at "distances" in • Syntax:
memory
JMP dest
• The segmented architecture of 8086 allows two types of addresses:
JMP NEAR dest
NEAR specified by 16 bit offset relative to CS
FAR specified by 32 bit segment:offset; anywhere within 1MB physical JMP FAR destJMP SHORT dest
memory
• Semantics
• For 32 machines we still have NEAR or FAR
EIP <- dest
NEAR specified by 32 bit offset relative to CS
FAR specified by 48 bit segment:offset; anywhere within 4GB physical Flags: ODITSZAPC unchanged
memory
• Operands:
• Machine encoding of jumps adds another type of address:
index reg mem label
SHORT specified by 8-bit signed address; range is -128 to +127 bytes
• On 386+ processors, conditional jumps (Jxx) can be: • Note: under operands we have added two new types:
SHORT +127 to -128 bytes index register and label
NEAR +32,767 to -32,768 (if not flat model) A "label" is a symbolic name for an address
NEAR +2G to -2G (flat model)
• Note that SHORT jumps are require only one byte for the jump
offset

JMP Targets Conditional Jumps and Sequences


• The target of a JMP instruction can be an address • Conditional jumps (abbreviated Jxx or Jcc) inspect the flags
stored in memory or an index register • If designated condition is met, jump is taken otherwise control
falls through to next instruction
This allows run-time computation of addresses
• A typical conditional sequence looks like:
This and the similar operation of the CALL instruction provie a CMP OP1, OP2
hardware foundation for late-bound function calls in JE Label
dynamically-typed and/or object-oriented languages
• For this course we will only use the simplest form: • JE jumps if ZF = 1 (result is zero) and JNE jumps if ZF = 0 (result
JMP dest non-zero)
• Recall that the compare (CMP) instruction is exactly like SUB
• In assembly we can write SHORT JMP, NEAR JMP or but modifies flags only
FAR JMP, but most assemblers accept just JMP and • Don't use unnecessary instructions:
figure out from context which type of jump is sub eax, ebx
appropriate cmp eax, 0 ; not necessary- SUB already
jle negative ; set the flags
SHORT JMP is used as an optimization: reduces the length of
the instruction to 2 bytes • All you need is:
sub eax, ebx
jle negative

Grouping of x86 Conditionals Synonyms


• The x86 conditionals are a large and at first • Many conditionals have two mnemonics (and some have three) that
correspond to a single machine language instruction
confusing set of mnemonics
• You can use whichever fits the sense of the program to make it
• The key to understanding them is to regard them in more readable
three groups: • Examples: JZ (Jump if Zero) and JE (Jump if Equal)
1. Unsigned conditionals. These correspond to standard • JNZ (Jump if Non-Zero) and JNE (Jump if not Equal)
relational operators for arithmetic
2. Signed conditionals. These also correspond to standard • Compare:
relational operators for arithmetic SUB AX,BX
JZ label ; jump if zero to label
3. Single-flag tests (including the test for equality)
• With
4. And the oddball JCXZ (Jump if CX = 0) CMP AX,BX
• Remember that the processor neither knows nor JE label ; jump if equal to label
cares if you intend the operands of an ADD • “Jump if equal” would sound odd following a subtraction. The
instruction to be signed or unsigned natural question is “equal to what?”
• Likewise, “jump if zero” would sound odd after a compare
• The distinction is made when testing the results instruction
with conditional jumps

16
Overview of Conditional Mnemonics CMP Revisited
• Remember that CMP performs a subtraction and sets the flags
• Unsigned arithmetic: JB, JNAE, JBE, JNA, JA, • Consider what happens with CMP AL,2
Signed Unsigned
JNBE, JAE, JNB AL Meaning Meaning O S Z C Flags
• Signed Arithmetic: JL, JNGE, JLE, JNG, JG, 1 00-01 0 - 1 0 - 1 0 1 0 1
2 02 2 2 0 0 1 0
JNLE, JGE, JNL 3 03-7F 3 - 127 3 - 127 0 0 0 0
• Single Flag: 4 80-81 < -126 128 – 129 1 0 0 0
5 82-FF -126 - -1 130 - 255 0 1 0 0
Zero: JE, JZ, JNE, JNZ
Overflow: JO, JNO • If AL < 2 in a signed interpretation look at rows 1, 4, and 5.
Carry: JC, JNC Here SF <> OF, otherwise if AL >= 2 SF=OF
Sign: JS, JNS • If AL < 2 in an unsigned interpretation look at row 1. Here CF is
Parity JP, JPE, JNP, JPO set, otherwise it is clear
• Test for CX = 0: JCXZ jecxz • Semantics can be precisely expressed in terms of flags but we
will see that English mnemonics make a lot more sense

Syntax & Semantics of Conditional Jumps Signed and Unsigned Conditionals


• All of the conditionals are the same • Unsigned:JB, JNAE, JBE, JNA, JA, JNBE, JAE, JNB
• Syntax: • Signed: JL, JNGE, JLE, JNG, JG, JNLE, JGE, JNL
Jcc dest
• Semantics: • The key to distinguishing (and remembering) signed
EIP <- dest if condition is true and unsigned conditional jumps is
Flags: ODITSZAPC unchanged UNSIGNED: B (below) and A (above)
• operands: SIGNED: L (less than) and G (greater than)
short or near label • Unsigned conditionals are used with unsigned data; for
• The fact that the flags are unaffected means that example when comparing addresses or characters
the flags can be tested repeatedly if necessary. Ex: • Signed conditionals are only used with 2’s complement
cmp ax, amt ; data.
jbe isless ; jump if ax < amt (unsigned)
• Unsigned are by far the most common
jae ismore ; jump if ax > amt (unsigned)
jmp equal

The Unsigned Conditionals The Signed Conditionals


• JB, JNAE, JBE, JNA, JA, JNBE, JAE, JNB JL, JNGE, JLE, JNG, JG, JNLE, JGE, JNL
JB (Jump if Below)
JL (Jump if Less)
JNAE (Jump if not Above or Equal)
JC (Jump if Carry set) JNGE(Jump if not Greater or Equal)
Semantics: IP <- dest if CF = 1 Semantics: IP <- dest if SF <> OF
JBE (Jump if Below or Equal)
JNA (Jump if not Above) JLE (Jump if Less or Equal)
Semantics: IP <- dest if CF = 1 or ZF = 1
JNG (Jump if not Greater)
JA (Jump if Above)
Semantics: IP <- dest if ZF = 1 or SF <> OF
JNBE (Jump if not Below or Equal)
Semantics: IP <- dest if CF = 0 and ZF = 0 JG (Jump if Greater)
JAE (Jump if Above or Equal) JNLE (Jump if not Less or Equal)
JNB (Jump if not Below) Semantics: IP <- dest if ZF = 0 or SF = OF
JNC (Jump if No Carry)
Semantics: IP <- dest if CF = 0 JGE (Jump if Greater or Equal)
• Note that semantics are precisely expressed in terms of flags JNL (Jump if not Less)
but English mnemonics make a lot more sense Semantics: IP <- dest if SF = OF

17
Zero Flag / Equality CF and OF
• These are the most common conditionals used Carry: JC (Jump if Carry)
JNC (Jump if no Carry)
JE (Jump if Equal) Semantics:
JC: IP <- dest if CF = 1
JZ (Jump if Zero)
JNC: IP <- dest if CF = 0
Semantics: IP <- dest if ZF = 1

JNE (Jump if Not Equal) Overflow: JO (Jump if Overflow)


JNZ (Jump if not Zero) JNO (Jump if no Overflow)
Semantics:
Semantics: IP <- dest if ZF = 0
JO: IP <- dest if OF = 1
JNO: IP <- dest if OF = 0

SF and PF And the Oddball Jump: JECXZ


Sign: JS (Jump if Sign) • This jump instruction inspects the CX register, not
JNS (Jump if no Sign) the flags
Semantics:
JS: IP <- dest if SF = 1 • JCXZ (Jump if CX = 0)
JNS: IP <- dest if SF = 0
• JECXZ (Jump if ecx = 0)
Remember that SF = 1 if result is negative
• Parity JP (Jump if Parity)
Semantics:
JPE (Jump if Parity Even) eip <- dest if ECX = 0
Semantics: IP <- dest if PF = 1
Flags: ODITSZAPC unchanged
JNP (Jump if Parity)
JPO (Jump if Parity Odd) • This is mostly of interest as a test before LOOP
Semantics: IP <- dest if PF = 0 instructions but can be used to inspect CX (or ECX)
Remember that PF = 1 on even parity without setting flags.
• Note that no "inverse" instruction (JECXNZ) exists

Conditional Jump Examples isalpha


• Finally some complete functions to look at! isAlpha:
; accepts a char in AL and returns ZF set if A..Z or a..z
Check for alphabetic characters
; returns ZF clear otherwise
Find min-max in array of integers
push eax ; save char in al
and al, 11011111b ; convert al to uppercase
cmp al, 'A'
jb L1 ; if below, ZF clear
cmp al, 'Z'
ja L1 ; if above, ZF clear
sub eax, eax ; sets zf
L1:
pop eax ; no effect on flags
ret
• Example call
mov al, char
call isAlpha
jnz notalpha

18
Notes on isalpha function Min-Max Values in Array
ARRAYCOUNT EQU 500
• This function returns a boolean in the zero flag array resd ARRAYCOUNT
ZF = 1 function => True, ZF = 0 => false largest resd 1
smallest resd 1
• Note the AND Mask so that we have to check upper-
MinMax:
case range only mov edi, array ; base address of array
mov eax, [edi] ; get first element
• eax is pushed so that we can restore AL mov [largest], eax ; initialize largest
• Note use of unsigned conditional jumps mov [smallest], eax
mov ecx, ARRAYCOUNT
;
;
initialize smallest
number of elements in array
• If either cmp is true, we know that zf is clear L1:
mov eax, [edi] ; get an element
• If neither is true, sub ax, ax will set zf cmp eax, [smallest] ; is eax < smallest?
jge L2 ; no, skip
mov [smallest], eax ; yes, save it
L2:
cmp eax, [largest] ; is eax > largest?
jle L3 ; no, skip
mov [largest], eax ; yes, save it
L3:
add edi, 4 ; advance pointer
loop L1

Notes on Min-Max The LOOP Instructions


• Algorithm: first element in array is both largest so • LOOP is a hardware looping instruction
far, and smallest so far. Use this to initialize mov ecx,5
variables largest and smallest SHORT_LABEL:
...
• Note that we cannot use this code: loop SHORT_LABEL
mov [largest], [edi] ; initialize largest
• LOOP decrements ecx and jumps to SHORT_LABEL if
because that is a memory-to-memory MOV ecx is non-zero
• Note use of signed comparison instructions. Code has • Syntax:
to be modified for unsigned integers LOOP dest
• Because array was defined with dd, elements are 32 • Semantics:
bits so we have to add 4 to edi to advance pointer (1) ecx <-- ecx - 1 (flags unchanged)
(2) if ecx != 0 then eip <-- dest
Flags: ODITSZAPC unchanged
• Operands:
Short label only (-128 to +127 bytes)

LOOP Which explains the oddball…


• Note that ecx is decremented before being tested • Testing before the loop: the jecxz instruction tests
• How many times will the loop be performed above, for ecx = 0 before the loop is executed
assuming that ecx is not altered by the code? • Commonly, when the loop variable initial value is
unknown, you would see the above sequence as
• What happens if mov ecx,5 is replaced by mov ecx, 0?
How many times is the loop performed? Initialize ecx
...
jecxz
0 - 1 = FFFFFFFF = 4,294,967,295
short_label:
ecx is interpreted as an unsigned value by the loop instruction
...
LOOP short_label
quit:

19
Sum an Array of Integers Alternate code with displacement addressing
asize EQU 100 • Different addressing mode, same effect:
array TIMES asize dd 0 asize EQU 100
... array TIMES asize dd 0
sub eax, eax ; initialize sum ...
mov ebx, array ; pointer to array sub eax, eax ; initialize sum
mov ecx, asize ; number of elements sub ebx, ebx ; initial offset = 0
L1: mov ecx, asize ; number of elements
add eax,[ebx] L1:
add ebx, 4 add eax,[ebx+array]
loop L1 add ebx,4
loop L1

Checking for overflow 64-bit sum of 32-bit array


• Code varies with signed/unsigned ints: • Note that ADC DX, 0 seems to add 0 to DX (a bit silly)
asize EQU 100 but it is Add with Carry so CF is added as well
array TIMES asize dd 0 • This only works for unsigned integers
... asize EQU 100
sub eax, eax ; initialize sum array TIMES asize dd 0
sub ebx, ebx ; initial offset = 0
...
mov ecx, asize ; number of elements
sub eax, eax ; initialize l.o. sum
L1:
sub edx, edx ; initialize h.o. sum
add eax,[ebx+array] sub ebx, ebx ; initial offset = 0
jo overflow ;signed OR mov ecx, asize ; number of elements
jc overflow ;unsigned L1:
add ebx,4 add eax,[ebx+array]
loop L1 adc edx, 0
• Note that conditional jump has to be immediately after lea ebx,[ebx+4]
loop L1
the add into eax, because add bx, 2 affects flags

Signed 64-bit sum of 32-bit array Conditional LOOPs


• In order to add an array of signed 32-bit integers in • Loops come in several flavors
an 32-bit array, we need to use the following Conditional loops are LOOPE (LOOPZ) and LOOPNE (LOOPNZ)
algorithm: • These loops have two tests:
Initialize sum to 0 test for ecx = 0 AND for Z = 1 or Z = 0
Initialize pointer to array
• LOOPE (LOOP if Equal) and LOOPZ (LOOP if Zero)
L1:
• Syntax:
load from [ebx]
LOOPE dest
sign-extend value to 64 bits
LOOPZ dest
add into 64-bit sum
check OF • Semantics:
Loop L1 (1) ecx <-- ecx - 1 (flags unchanged)
(2) if ecx != 0 AND ZF = 1 then eip <-- dest
• We’ll get back to this later
Flags: ODITSZAPC unchanged
• Operands:
Short label only (-128 to +127 bytes)

20
LOOPE/LOOPZ Example: Find First Non-Zero Element
• Notes: hits TIMES 256 dd 0
1. Because the test for loop continuation is an AND, loop will ....
terminate when either ZF = 0 OR ecx = 0 mov ecx, 256 ; number of values
2. This loop is typically used when “searching for a mov ebx, hits-4 ; one element before first val
mismatch” L1:
3. Just as JZ/JE are synonyms, LOOPE and LOOPZ are the add ebx,4
same machine instruction cmp dword [ebx], 0 ; compare immediate to mem
4. It may be more convenient to read the mnemonics as loope L1
“loop while equal” and “loop while zero” because they are
L2:
more similar to a WHILE loop than a count-controlled FOR
loop • How do we know at L2 why the loop terminated?
• We may have found a non-zero value, or we may
have failed to find one after inspecting all 256
elements

After Conditional Loop Termination Be careful about order of instructions


hits TIMES 256 dd 0
• This doesn’t work
....
hits TIMES 256 dd 0
mov ecx, 256 ; number of values
....
mov ebx, hits-4 ; one element before first val
mov ecx, 256 ; number of values
L1:
mov ebx, hits ; FIRST ELEMENT
add ebx,4
L1:
cmp dword [ebx], 0 ; compare immediate to mem
cmp word ptr [ebx], 0 ; compare immediate to mem
loope L1
add ebx,4
L2:
loope L1
• The obvious answer is to examine the word that ebx L2:
points to with cmp dword [ebx], 0.
• The add instruction after the cmp trashes the
• But an easier solution lies in the semantics of loope:
Flags: ODITSZAPC unchanged
flags
• So the flags remain set by the cmp instruction, and at L2
we can have:
L2: jz not_found

LOOPNE and LOOPNZ LOOPNE Example: Find First Space


• LOOPNE (LOOP if/while Not Equal) and LOOPNZ • Find the first space in a string. Handy for parsing strings such as
(LOOP if/while Not Zero) command-line arguments:
aString resb strsize
• Syntax:
.....
LOOPNE dest
FindBlank:
LOOPNZ dest
mov esi, aString - 1
• Semantics: mov ecx, strsize
(1) ecx <-- ecx - 1 (flags unchanged) mov al, 20h ; 20h = ASCII space
(2) if ecx != 0 AND ZF = 0 then eip <-- dest
L1:
Flags: ODITSZAPC unchanged inc esi
• Operands: cmp [esi], al
Short label only (-128 to +127 bytes) loopne L1
• Notes: ; loop terminates because we either found a space
1. Since test is an AND, loop will terminate when either ZF = 1 ; OR searched the entire string. Inspect the flags:
OR ecx= 0 jz FoundBlank
2. This loop is typically used when "searching for a match" jmp NoBlanks

21
Example: First Negative Integer The TEST Instruction
• This example finds the first negative int in an array, • TEST is AND without storing results (affects flags
using a TEST instruction (AND operands and modify only) For now consider:
flags) to inspect top bit B0FF = 1011 0000 1111 1111
nums resd vectorsize AND 8000 = 1000 0000 0000 0000
..... Result: 8000 = 1000 0000 0000 0000
FindNeg:
mov esi, nums - 4
mov cx, vectorsize 70FF = 0111 0000 1111 1111
L1: AND 8000 = 1000 0000 0000 0000
add esi, 4 Result: 0000 = 0000 0000 0000 0000
test byte [esi+3], 80h; check top bit
loopz L1
; Find reason why loop terminated
jnz FoundNeg
jmp NoNeg

LOOP on the Pentium Replacing LOOP


• LOOP and its variations are expensive instructions on a Pentium • LOOP can be replaced with conditional jumps
- typically 6 clocks. FindBlank2:
mov esi, aString - 1
• Optimization of asm code can involve replacement of LOOPs:
mov ecx, strsize
mov al, 20h ; 20h = ASCII space
aString resb strsize
..... L1:
FindBlank: inc esi ; 1 clock
mov esi, aString - 1 cmp [esi], al ; 1 clock
mov ecx, strsize jne testCX ; not a space, check cx(1 clock)
mov al, 20h ; 20h = ASCII space jmp FoundBlank ; was a space, process it
L1: TestCX: ; any string left?
inc esi ; 1 clock dec ecx ; adjust counter (1 clock)
cmp [esi], al ; 1 clock jnz L1 ; 1 clock
loopne L1 ; 6 clocks
jmp NoBlanks
jz FoundBlank
• We had an 8-clock loop before; now it is 5 clocks
jmp NoBlankss

Arithmetic Example: Prime Numbers prime.asm:1


#include <stdio.h> %include "asm_io.inc"
int main(){
unsigned guess; /* current guess for prime */
unsigned factor; /* possible factor of guess */
segment .data
unsigned limit; /* find primes up to this value */ Message db "Find primes up to: ", 0
printf("Find primes up to: ");
scanf("%u", &limit);

printf("2\n"); /* treat first two primes as special case */ segment .bss


printf("3\n"); Limit resd 1 ; find primes up to this limit
guess = 5; /* initial guess */ Guess resd 1 ; the current guess for prime
while ( guess <= limit ) {
/* look for a factor of guess */
factor = 3;
while ( factor*factor < guess && guess % factor != 0 )
segment .text
factor += 2;
if ( guess % factor != 0 ) global _asm_main
printf("%d\n", guess);
guess += 2; /* only look at odd numbers */ _asm_main:
} enter 0,0 ; setup routine
return 0;
} pusha

22
prime.asm:2 prime.asm:3
mov eax, Message while_limit: ; while ( Guess <= Limit )
mov eax,[Guess]
call print_string cmp eax, [Limit]
call read_int ; scanf("%u", & limit ); jnbe end_while_limit ; use jnbe b/c data are unsigned
mov [Limit], eax
mov ebx, 3 ; ebx is factor = 3;
while_factor:
mov eax, 2 ; printf("2\n"); mov eax,ebx
call print_int mul eax ; edx:eax = eax*eax
jo end_while_factor ; if answer won't fit in eax
call print_nl alone
mov eax, 3 ; printf("3\n"); cmp eax, [Guess]
jnb end_while_factor ; if !(factor*factor < guess)
call print_int mov eax,[Guess]
call print_nl mov edx,0
div ebx ; edx = edx:eax % ebx
cmp edx, 0
mov dword [Guess], 5 ; Guess = 5; je end_while_factor ; if !(guess % factor != 0)

add ebx,2 ; factor += 2;


jmp while_factor
end_while_factor:

prime.asm:4 Translating Standard Control Structures


add ebx,2 ; factor += 2;
jmp while_factor
• IF Statement
end_while_factor: if ( condition )
je end_if ; if !(guess % factor != 0) then block ;
mov eax,[Guess] ; printf("%u\n")
else
call print_int
call print_nl else block ;
end_if:
mov eax,[Guess]
• Assembler
add eax, 2 ; code to set FLAGS
mov [Guess], eax ; guess += 2 ; select Jxx to jump if condition false
jmp while_limit
end_while_limit:
jxx else_block
; code for then block
popa jmp endif
mov eax, 0 ; return back to C
leave else_block:
ret ; code for else block
endif:

Translating Standard Control Structures While and Do Loops


• IF Statement without ELSE • WHILE loop (test at top)
; code to set FLAGS while( condition ) {
; select Jxx to jump if condition false body of loop;
jxx endif }
; code for then block
endif: • Assembler
while:
; code to set FLAGS based on condition
; select Jxx to jump if condition is false
jxx endwhile
; body of loop
jmp while
endwhile:

23
While and Do Loops Quiz Mar 22
• DO loop (test at bottom) • Which of the following instructions do not affect the
do { flags. (Circle your answers)?
body of loop; MUL JMP MOV DEC PUSH JNAE
} while( condition )

• Which instruction is the same as JNAE?


• Assembler JNLE JLE JB JBE
do:
; body of loop
• In a NASM program, what goes into:
; code to set FLAGS based on condition
segment .text
; select Jxx to jump if condition is TRUE
jxx do
segment .data

segment .bss

24

You might also like