<- 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 ->