Multiplication & Division

In the `"Hello World!"` sample program we had used the instructions `REPNZ` and `SCASB` to calculate the length of the string being printed at runtime. In this program we use Nasm's `equ` directive to calculate the length during assembly time as opposed to at runtime. The variable `promptlen` gives an example.

In the below program, we print the prompt asking for the user to enter an integer which is then read into the variable input defined in the `.bss` section, which is the uninitialized memory section, using the function `read_int()` , defined earlier in the file `asm_io.asm` .

To multiply two signed integers, we use the `IMUL` instruction, which is what we have used here. To divide two signed integers, we use the `IDIV` instruction, which places the quotient of the division in the `RAX` register and the remainder in the `RDX` register. A very common error is to forget to initialize the `RDX` register, which we do here with instruction `CQO` which sign extends `RAX` to `RDX` . The negation of a number, i.e. multiplication by `-1` , is done using the `NEG` instruction which calculates the two's complement of the value in the register operand for the instruction.

```%include "asm_io.inc"
%macro prologue 0
push    rbp
mov     rbp,rsp
push    rbx
push    r12
push    r13
push    r14
push    r15
%endmacro
%macro epilogue 0
pop     r15
pop     r14
pop     r13
pop     r12
pop     rbx
leave
ret
%endmacro

section .bss
input   resd    1

section .rodata
prompt     db  "Enter a number: ",0
promptlen  equ \$-prompt
cube       db  "The cube of the number is: ",0
square     db  "The square of the number is: ",0
cube25     db  "The value of cube of the number times 25 is: ",0
quotient   db "The quotient of cube/100 is: ",0
remainder  db  "The remainder of cube/100 is: ",0
negation   db  "The negation of the remainder is: ",0

section .text
global main
main:
prologue
; print the prompt for the user
mov     rdx, promptlen
mov     rsi, dword prompt
push    0x1
pop     rdi
mov     rax,rdi
syscall

mov     rdi, dword input

; calculate its square and print the output
mov     rdi, dword square
call    print_string
mov     rdi, [input]
imul    rdi, rdi
mov     rbx, rdi
call    print_int
call    print_nl

; calculate its cube and print the output
mov     rdi,dword cube
call    print_string
mov     rdi, [input]
imul    rdi,rdi
imul    rdi,[input]
mov     rbx, rdi
call    print_int
call    print_nl

; calculate the cube times 25 and print the output
mov     rdi, dword cube25
call    print_string
mov     rdi, rbx
imul    rdi,0x19
call    print_int
call    print_nl

; calculate cube/100 and print the output
mov     rdi, dword quotient
call    print_string
; initialize rax and sign extend it to rdx
mov     rax,rbx
cqo
mov     rcx,0x64         ; this is the hex representation of 100
idiv    rcx
push    rdx
mov     rdi, rax
call    print_int
call    print_nl

; calculate the remainder of cube/100 and print the output
mov     rdi, dword remainder
call    print_string
pop     rdx
mov     rdi,rdx
push    rdx
call    print_int
call    print_nl

; calculate the negation of the remainder and print the output
mov     rdi, dword negation
call    print_string
pop     rdi
neg     rdi
call    print_int
call    print_nl
epilogue
```

To compile the above program which we shall call `math.asm` , we execute the following steps:

```\$ yasm -f elf64 asm_io.asm
\$ yasm -f elf64 math.asm
\$ gcc -o math.out math.o asm_io.o -lc
```

Since we are using C library functions like `printf()` , `scanf()` and `putchar()` , we need to link in the C library during link time, hence the `-lc` is used for that. This is a dynamic link, and we use `gcc` to do it. If we want to use just the linker `ld` we can link in the C library statically as given below:

```\$ ld -o math.out math.o asm_io.o -Bstatic -lc
```

This however will generate a very large executable because all the C library functions will become a part of the executable. We do not want this, so we link in dynamically using the C runtime object files provided by the operating system in `/usr/lib64/` directory as below:

```\$ ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 /usr/lib64/crt1.o  /usr/lib64/crti.o \
math.o asm_io.o  /usr/lib64/crtn.o -lc -o math.out
```

It is advisable that the files should be linked in the correct order as shown above.