<- previous index next ->
Both integer and floating point arithmetic are demonstrated. In order to make the source code smaller, a macro is defined to print out results. The equivalent "C" program is given as comments. First, see how to call the "C" library function, printf, to make it easier to print values: Look at the file printf1.asm ; printf1.asm print an integer from storage and from a register ; Assemble: nasm -f elf -l printf1.lst printf1.asm ; Link: gcc -o printf1 printf1.o ; Run: printf1 ; Output: a=5, eax=7 ; Equivalent C code ; /* printf1.c print an int and an expression */ ; #include <stdio.h> ; int main() ; { ; int a=5; ; printf("a=%d, eax=%d\n", a, a+2); ; return 0; ; } ; Declare some external functions ; extern printf ; the C function, to be called section .data ; Data section, initialized variables a: dd 5 ; int a=5; fmt: db "a=%d, eax=%d", 10, 0 ; The printf format, "\n",'0' section .text ; Code section. global main ; the standard gcc entry point main: ; the program label for the entry point push ebp ; set up stack frame mov ebp,esp mov eax, [a] ; put "a" from store into register add eax, 2 ; a+2 push eax ; value of a+2 push dword [a] ; value of variable a push dword fmt ; address of format string call printf ; Call C function add esp, 12 ; pop stack 3 push times 4 bytes mov esp, ebp ; take down stack frame pop ebp ; same as "leave" op mov eax,0 ; normal, no error, return value ret ; return Now, for integer arithmetic, look at the file intarith.asm ; intarith.asm show some simple C code and corresponding nasm code ; the nasm code is one sample, not unique ; ; compile: nasm -f elf -l intarith.lst intarith.asm ; link: gcc -o intarith intarith.o ; run: intarith ; ; the output from running intarith.asm and intarith.c is: ; c=5 , a=3, b=4, c=5 ; c=a+b, a=3, b=4, c=7 ; c=a-b, a=3, b=4, c=-1 ; c=a*b, a=3, b=4, c=12 ; c=c/a, a=3, b=4, c=4 ; ;The file intarith.c is: ; /* intarith.c */ ; #include <stdio.h> ; int main() ; { ; int a=3, b=4, c; ; ; c=5; ; printf("%s, a=%d, b=%d, c=%d\n","c=5 ", a, b, c); ; c=a+b; ; printf("%s, a=%d, b=%d, c=%d\n","c=a+b", a, b, c); ; c=a-b; ; printf("%s, a=%d, b=%d, c=%d\n","c=a-b", a, b, c); ; c=a*b; ; printf("%s, a=%d, b=%d, c=%d\n","c=a*b", a, b, c); ; c=c/a; ; printf("%s, a=%d, b=%d, c=%d\n","c=c/a", a, b, c); ; return 0; ; } extern printf ; the C function to be called %macro pabc 1 ; a "simple" print macro section .data .str db %1,0 ; %1 is first actual in macro call section .text ; push onto stack backward push dword [c] ; int c push dword [b] ; int b push dword [a] ; int a push dword .str ; users string push dword fmt ; address of format string call printf ; Call C function add esp,20 ; pop stack 5*4 bytes %endmacro section .data ; preset constants, writeable a: dd 3 ; 32-bit variable a initialized to 3 b: dd 4 ; 32-bit variable b initializes to 4 fmt: db "%s, a=%d, b=%d, c=%d",10,0 ; format string for printf section .bss ; uninitialized space c: resd 1 ; reserve a 32-bit word section .text ; instructions, code segment global main ; for gcc standard linking main: ; label lit5: ; c=5; mov eax,5 ; 5 is a literal constant mov [c],eax ; store into c pabc "c=5 " ; invoke the print macro addb: ; c=a+b; mov eax,[a] ; load a add eax,[b] ; add b mov [c],eax ; store into c pabc "c=a+b" ; invoke the print macro subb: ; c=a-b; mov eax,[a] ; load a sub eax,[b] ; subtract b mov [c],eax ; store into c pabc "c=a-b" ; invoke the print macro mulb: ; c=a*b; mov eax,[a] ; load a (must be eax for multiply) imul dword [b] ; signed integer multiply by b mov [c],eax ; store bottom half of product into c pabc "c=a*b" ; invoke the print macro diva: ; c=c/a; mov eax,[c] ; load c mov edx,0 ; load upper half of dividend with zero idiv dword [a] ; divide double register edx eax by a mov [c],eax ; store quotient into c pabc "c=c/a" ; invoke the print macro mov eax,0 ; exit code, 0=normal ret ; main returned to operating system bbbb [mem] a product of 32-bits times 32-bits is 64-bits imul bbbb eax --------- edx bbbbbbbb eax the upper part of the product is in edx the lower part of the product is in eax edx bbbbbbbb eax before divide, the upper part of dividend is in edx the lower part of dividend is in eax idiv bbbb [mem] the divisor -------- after divide, the quotient is in eax the remainder is in edx Now, for floating point arithmetic, look at the file fltarith.asm Note the many similarities to integer arithmetic, yet some basic differences. ; fltarith.asm show some simple C code and corresponding nasm code ; the nasm code is one sample, not unique ; ; compile nasm -f elf -l fltarith.lst fltarith.asm ; link gcc -o fltarith fltarith.o ; run fltarith ; ; the output from running fltarith and fltarithc is: ; c=5.0, a=3.000000e+00, b=4.000000e+00, c=5.000000e+00 ; c=a+b, a=3.000000e+00, b=4.000000e+00, c=7.000000e+00 ; c=a-b, a=3.000000e+00, b=4.000000e+00, c=-1.000000e+00 ; c=a*b, a=3.000000e+00, b=4.000000e+00, c=1.200000e+01 ; c=c/a, a=3.000000e+00, b=4.000000e+00, c=4.000000e+00 ; a=i , a=8.000000e+00, b=1.600000e+01, c=1.600000e+01 ;The file fltarith.c is: ; #include <stdio.h> ; int main() ; { ; double a=3.0, b=4.0, c; ; int i=8; ; ; c=5.0; ; printf("%s, a=%e, b=%e, c=%e\n","c=5.0", a, b, c); ; c=a+b; ; printf("%s, a=%e, b=%e, c=%e\n","c=a+b", a, b, c); ; c=a-b; ; printf("%s, a=%e, b=%e, c=%e\n","c=a-b", a, b, c); ; c=a*b; ; printf("%s, a=%e, b=%e, c=%e\n","c=a*b", a, b, c); ; c=c/a; ; printf("%s, a=%e, b=%e, c=%e\n","c=c/a", a, b, c); ; a=i; ; b=a+i; ; i=b; ; c=i; ; printf("%s, a=%e, b=%e, c=%e\n","c=c/a", a, b, c); ; return 0; ; } extern printf ; the C function to be called %macro pabc 1 ; a "simple" print macro section .data .str db %1,0 ; %1 is macro call first actual parameter section .text ; push onto stack backwards push dword [c+4] ; double c (bottom) push dword [c] ; double c push dword [b+4] ; double b (bottom) push dword [b] ; double b push dword [a+4] ; double a (bottom) push dword [a] ; double a push dword .str ; users string push dword fmt ; address of format string call printf ; Call C function add esp,32 ; pop stack 8*4 bytes %endmacro section .data ; preset constants, writeable a: dq 3.0 ; 64-bit variable a initialized to 3.0 b: dq 4.0 ; 64-bit variable b initializes to 4.0 i: dw 8 ; a 32 bit integer five: dq 5.0 ; constant 5.0 fmt: db "%s, a=%e, b=%e, c=%e",10,0 ; format string for printf section .bss ; unitialized space c: resq 1 ; reserve a 64-bit word section .text ; instructions, code segment global main ; for gcc standard linking main: ; label lit5: ; c=5.0; fld qword [five] ; 5.0 constant fstp qword [c] ; store into c pabc "c=5.0" ; invoke the print macro addb: ; c=a+b; fld qword [a] ; load a (pushed on flt pt stack, st0) fadd qword [b] ; floating add b (to st0) fstp qword [c] ; store into c (pop flt pt stack) pabc "c=a+b" ; invoke the print macro subb: ; c=a-b; fld qword [a] ; load a (pushed on flt pt stack, st0) fsub qword [b] ; floating subtract b (to st0) fstp qword [c] ; store into c (pop flt pt stack) pabc "c=a-b" ; invoke the print macro mulb: ; c=a*b; fld qword [a] ; load a (pushed on flt pt stack, st0) fmul qword [b] ; floating multiply by b (to st0) fstp qword [c] ; store product into c (pop flt pt stack) pabc "c=a*b" ; invoke the print macro diva: ; c=c/a; fld qword [c] ; load c (pushed on flt pt stack, st0) fdiv qword [a] ; floating divide by a (to st0) fstp qword [c] ; store quotient into c (pop flt pt stack) pabc "c=c/a" ; invoke the print macro intflt: ; a=i; fild dword [i] ; load integer as floating point fst qword [a] ; store the floating point (no pop) fadd st0 ; b=a+i; 'a' as 'i' already on flt stack fst qword [b] ; store sum (no pop) 'b' still on stack fistp dword [i] ; i=b; store floating point as integer fild dword [i] ; c=i; load again from ram (redundant) fstp qword [c] pabc "a=i " ; invoke the print macro mov eax,0 ; exit code, 0=normal ret ; main returns to operating system Refer to nasmdoc.txt or textbook 10.4 for details. A brief summary is provided here. "reg" is an 8-bit, 16-bit or 32-bit register "count" is a number of bits to shift "right" moves contents of the register to the right, makes it smaller "left" moves contents of the register to the left, makes it bigger SAL reg,count shift arithmetic left SAR reg,count shift arithmetic right (sign extension) SHL reg,count shift left (logical, zero fill) SHR reg,count shift right (logical, zero fill) ROL reg,count rotate left ROR reg,count rotate right SHLD reg1,reg2,count shift left double-register SHRD reg1,reg2,count shift right double-register An example of using the various shifts is in: shift.asm
<- previous index next ->