<- previous index next ->
The basic integer compare instruction is "cmp"
Following this instruction is typically one of:
JL label ; jump on less than "<"
JLE label ; jump on less than or equal "<="
JG label ; jump on greater than ">"
JGE label ; jump on greater than or equal ">="
JE label ; jump on equal "=="
JNE label ; jump on not equal "!="
After many integer arithmetic instructions
JZ label ; jump on zero
JNZ label ; jump on non zero
JS label ; jump on sign plus
JNS labe; ; jump on sign not plus
Note: Use 'cmp' rather than 'sub' for comparison.
Overflow can occur on subtraction resulting in sign inversion.
Convert a "C" 'if' statement to nasm assembly ifint.asm
The significant features are:
1) use a compare instruction for the test
2) put a label on the start of the false branch (e.g. false1:)
3) put a label after the end of the 'if' statement (e.g. exit1:)
4) choose a conditional jump that goes to the false part
5) put an unconditional jump to (e.g. exit1:) at the end of the true part
; ifint.asm code ifint.c for nasm
; /* ifint.c an 'if' statement that will be coded for nasm */
; #include <stdio.h>
; int main()
; {
; int a=1;
; int b=2;
; int c=3;
; if(a<b)
; printf("true a < b \n");
; else
; printf("wrong on a < b \n");
; if(b>c)
; printf("wrong on b > c \n");
; else
; printf("false b > c \n");
; return 0;
;}
; result of executing both "C" and assembly is:
; true a < b
; false b > c
global main ; define for linker
extern printf ; tell linker we need this C function
section .data ; Data section, initialized variables
a: dd 1
b: dd 2
c: dd 3
fmt1: db "true a < b ",10,0
fmt2: db "wrong on a < b ",10,0
fmt3: db "wrong on b > c ",10,0
fmt4: db "false b > c ",10,0
section .text
main: mov eax,[a]
cmp eax,[b]
jge false1 ; choose jump to false part
; a < b sign is set
push dword fmt1 ; printf("true a < b \n");
call printf
add esp,4
jmp exit1 ; jump over false part
false1: ; a < b is false
push dword fmt2 ; printf("wrong on a < b \n");
call printf
add esp,4
exit1: ; finished 'if' statement
mov eax,[b]
cmp eax,[c]
jle false2 ; choose jump to false part
; b > c sign is not set
push dword fmt3 ; printf("wrong on b > c \n");
call printf
add esp,4
jmp exit2 ; jump over false part
false2: ; a > b is false
push dword fmt4 ; printf("false b :gt; c \n");
call printf
add esp,4
exit2: ; finished 'if' statement
mov eax,0 ; normal, no error, return value
ret ; return 0;
Convert a "C" loop to nasm assembly loopint.asm
The significant features are:
1) "C" int is 4-bytes, thus dd1[1] becomes dword [dd1+4]
dd1[99] becomes dword [dd1+4*99]
2) "C" int is 4-bytes, thus dd1[i]; i++; becomes add edi,4
since "i" is never stored, the register edi holds "i"
3) the 'cmp' instruction sets flags that control the jump instruction.
cmp edi,4*99 is like i<99
jnz loop1 jumps if register edi is not 4*99
; loopint.asm code loopint.c for nasm
; /* loopint.c a very simple loop that will be coded for nasm */
; #include <stdio.h>
; int main()
; {
; int dd1[100];
; int i;
; dd1[0]=5; /* be sure loop stays 1..98 */
; dd1[99]=9;
; for(i=1; i<99; i++) dd1[i]=7;
; printf("dd1[0]=%d, dd1[1]=%d, dd1[98]=%d, dd1[99]=%d\n",
; dd1[0], dd1[1], dd1[98],dd1[99]);
; return 0;
;}
section .bss
dd1: resd 100
i: resd 1 ; actually unused, kept in register
section .text
global main
main: mov dword [dd1],5 ; dd1[0]=5;
mov dword [dd1+99*4],9 ; dd1[99]=9;
mov edi,4 ; i=1; /* 4 bytes */
loop1: mov dword [dd1+edi],7 ; dd1[i]=7;
add edi,4 ; i++; /* 4 bytes */
cmp edi,4*99 ; i<99
jne loop1 ; loop until i=99
extern printf ; the C function, to be called
section .data ; Data section, initialized variables
fmt: db "dd1[0]=%d, dd1[1]=%d, dd1[98]=%d, dd1[99]=%d",10,0
section .text ; Code section, continued
push dword [dd1+99*4] ; dd1[99]
push dword [dd1+98*4] ; dd1[98]
push dword [dd1+4] ; dd1[1]
push dword [dd1] ; dd1[0]
push dword fmt ; address of format string
call printf ; Call C function
add esp, 20 ; pop stack 5 push times 4 bytes
mov eax,0 ; normal, no error, return value
ret ; return 0;
; no registers needed to be saved
Previously, integer arithmetic in "C" was converted to
NASM assembly language. The following is very similar
(cut and past) of intarith.asm to intlogic.asm that
shows the "C" operators "&" and, "|" or, "^" xor, "~" not.
intlogic.asm
One significant use of loops is to evaluate polynomials and
convert numbers from one base to another.
(Yes, this is related to project 1 for CMSC 313)
The following program has seven loops.
Loop1 (h1loop) uses Horners method to convert ASCII decimal digits
to binary, using a sentinal, '.', with 'cmp' and 'je'
to exit the loop
Loop2 (h2loop) uses Horners method to convert ASCII decimal digits
using 'edi' as an index, 'ecx' and 'loop' to do the loop.
Loop3 (h3loop) uses Horners method to evaluate a polynomial,
using 'edi' as an index, 'ecx' and 'loop' to do the loop.
Loop4 (h4loop) uses Horners method, with data order optimized,
using 'ecx' as both index and loop counter, to get a
three instruction loop.
Loop5 (h5loop) uses Horners method to evaluate a polynomial
using double precision floating point. Note 8 byte
increment and quad word to printf.
Loop6 (h6loop) uses Horners method to evaluate the fractional
part of a double precision floating point polynomial.
Note that divide is used in place of multiply and the
least significant coefficient is used first.
Loop7 (h7loop) uses Horners method to convert ASCII decimal
fraction to binary. Note that shifting is needed
because the binary point can not be at the right end
of the word.
Loop8 (h8loop) just prints 16 bits from the result of Loop7
as ASCII characters.
Study horner.asm to understand
the NASM coding of the loops.
; horner.asm Horners method of evaluating polynomials
;
; given a polynomial Y = a_n X^n + a_n-1 X^n-1 + ... a_1 X + a_0
; a_n is the coefficient 'a' with subscript n. X^n is X to nth power
; compute y_1 = a_n * X + a_n-1
; compute y_2 = y_1 * X + a_n-2
; compute y_i = y_i-1 * X + a_n-i i=3..n
; thus y_n = Y = value of polynomial
;
; in assembly language:
; load some register with a_n, multiply by X
; add a_n-1, multiply by X, add a_n-2, multiply by X, ...
; finishing with the add a_0
;
; for conversion of decimal to binary, X=10
;
extern printf
section .data
decdig: db '5','2','8','0','.' ; decimal integer 5280
fmt: db "%d",10,0
global main
section .text
main: push ebp ; save ebp
mov ebp,esp ; ebp is callers stack
push ebx
push edi ; save registers
; method 1, using a "sentinel" e.g. '.'
mov eax,0 ; accumulate value here
mov al,[decdig] ; get first ASCII digit
sub al,48 ; convert ASCII digit to binary
mov edi,1 ; subscript initialization
h1loop: mov ebx,0 ; clear register (upper part)
mov bl,[decdig+edi] ; get next ASCII digit
cmp bl,'.' ; compare to decimal point
je h1fin ; exit loop on decimal point
sub bl,48 ; convert ASCII digit to binary
imul eax,10 ; * X (ignore edx)
add eax,ebx ; + a_n-i
inc edi ; increment subscript
jmp h1loop
h1fin:
push dword eax ; print eax
push dword fmt ; format %d
call printf
add esp,8 ; restore stack
; method 2, using a count
mov eax,0 ; accumulate value here
mov al,[decdig] ; get first ASCII digit
sub al,48 ; convert ASCII digit to binary
mov edi,1 ; subscript initialization
mov ecx,3 ; loop iteration count initialization
h2loop: mov ebx,0 ; clear register (upper part)
mov bl,[decdig+edi] ; get next ASCII digit
sub bl,48 ; convert ASCII digit to binary
imul eax,10 ; * X (ignore edx)
add eax,ebx ; + a_n-i
inc edi ; increment subscript
loop h2loop ; decrement ecx, jump on non zero
push dword eax ; print eax
push dword fmt ; format %d
call printf
add esp,8 ; restore stack
; evaluate a polynomial, X=7, using a count
section .data
a: dd 2,5,-7,22,-9 ; coefficients of polynomial, a_n first
X: dd 7
section .text
mov eax,[a] ; accumulate value here, get coefficient a_n
mov edi,1 ; subscript initialization
mov ecx,4 ; loop iteration count initialization, n
h3loop: imul eax,[X] ; * X (ignore edx)
add eax,[a+4*edi] ; + a_n-i
inc edi ; increment subscript
loop h3loop ; decrement ecx, jump on non zero
push dword eax ; print eax
push dword fmt ; format %d
call printf
add esp,8 ; restore stack
; evaluate a polynomial, X=7, using a count as index
; optimal organization of data allows a three instruction loop
section .data
aa: dd -9,22,-7,5,2 ; coefficients of polynomial, a_0 first
section .text
mov eax,[aa+4*4] ; accumulate value here, get coefficient a_n
mov ecx,4 ; loop iteration count initialization, n
h4loop: imul eax,[X] ; * X (ignore edx)
add eax,[aa+4*ecx-4]; + aa_n-i
loop h4loop ; decrement ecx, jump on non zero
push dword eax ; print eax
push dword fmt ; format %d
call printf
add esp,8 ; restore stack
; evaluate a double floating polynomial, X=7.0, using a count as index
; optimal organization of data allows a three instruction loop
section .data
af: dq -9.0,22.0,-7.0,5.0,2.0 ; coefficients of polynomial, a_0 first
XF: dq 7.0
Y: dq 0.0
N: dd 4
fmtflt: db "%e",10,0
section .text
mov ecx,[N] ; loop iteration count initialization, n
fld qword [af+8*ecx]; accumulate value here, get coefficient a_n
h5loop: fmul qword [XF] ; * XF
fadd qword [af+8*ecx-8] ; + aa_n-i
loop h5loop ; decrement ecx, jump on non zero
fstp qword [Y] ; store Y in order to print Y
push dword [Y+4] ; print Y (must be two parts of quadword)
push dword [Y] ; print Y
push dword fmtflt ; format %e
call printf
add esp,12 ; restore stack
; Convert the fractional polynomial, Y = a_-1 X^-1 + a_-2 X^-2 + ...
; This must be performed using divide in reverse order.
; compute y_1 = a_-n / X + a_-n+1
; compute y_2 = y_1 / X + a_-n+2
; compute y_i = y_i-1 / X + a_-n+i i=3..n
; thus y_n = Y_n-1 / X = Y = value of polynomial
; Using the coefficients above a_-1 = -9.0 (first)
; a_-2 = 22.0, a_-3 = -7.0, a_-4 = 5.0, a_-5 = 2.0
; N=4 (not 5) because the the first term is outside the loop
mov ecx,[N] ; loop iteration count initialization, n
fld qword [af+8*ecx]; accumulate value here, get a_-n-1 = 2.0
h6loop: fdiv qword [XF] ; * XF
fadd qword [af+8*ecx-8] ; + aa_n-i
loop h6loop ; decrement ecx, jump on non zero
fdiv qword [XF] ; extra divide for fractional terms
fstp qword [Y] ; store Y in order to print Y
push dword [Y+4] ; print Y (must be two parts of quadword)
push dword [Y] ; print Y
push dword fmtflt ; format %e
call printf
add esp,12 ; restore stack
; Convert the fractional part, a_-1 X^-1 + a_-2 X^-2 + ...
; This must be performed using "fixed point" arithmetic.
; The implied binary point is 16-bits from LSB.
section .data
fracdig:db '.','1','2','3','4' ; decimal fraction .1234
fmth: db "%X",10,0
ten: dd 10
eaxsave:dd 0
global h7loop ; for debugging loop "break h7loop"
section .text
mov eax,0 ; accumulate value here
mov al,[fracdig+4] ; get last ASCII digit
sub al,48 ; convert ASCII digit to binary
shl eax,16 ; move binary point
mov ecx,3 ; loop iteration count initialization
h7loop: mov edx,0 ; must clear upper dividend
idiv dword [ten] ; quotient in eax
mov ebx,0 ; clear register (upper part)
mov bl,[fracdig+ecx]; get next previous ASCII digit
sub bl,48 ; convert ASCII digit to binary
shl ebx,16 ; move binary point 16-bits
add eax,ebx ; + a_n-i
loop h7loop ; decrement ecx, jump on non zero
mov edx,0 ; must clear upper dividend
idiv dword [ten] ; final divide
mov [eaxsave],eax ; save eax, printf destroys it
push dword eax ; print eax
push dword fmth ; format %X (look at low 16-bits)
call printf
add esp,8 ; restore stack
; print the bits in eaxsave:
section .bss
abits: resb 17 ; 16 characters plus zero terminator
section .data
fmts: db "%s",10,0
section .text
mov eax,[eaxsave] ; restore eax
ror eax,1 ; get bottom bit in top of eax
mov ecx,16 ; for printing 16 bits
h8loop: mov edx,0 ; clear edx ready for a bit
shld edx,eax,1 ; top bit of eax into edx
add edx,48 ; make it ASCII
mov [abits+ecx-1],dl ; store character
ror eax,1 ; next bit into top of eax
loop h8loop ; decrement ecx, jump non zero
mov byte [abits+16],0 ; end of "C" string
push dword abits ; string to print
push dword fmts ; "%s"
call printf
add esp,8
pop edi
pop ebx
mov esp,ebp ; restore callers stack frame
pop ebp
ret ; return
; output from execution:
; 5280
; 5280
; 6319
; 6319
; 6.319000e+03
; -8.549414e-01
; 1F97
; 0001111110010111
<- previous index next ->