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