<- previous    index    next ->

Lecture 4 Arithmetic and shifting

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

Other links

Go to top