Author Topic: Factorial, help to understand  (Read 5387 times)

Offline Eght

  • Jr. Member
  • *
  • Posts: 3
Factorial, help to understand
« on: January 03, 2017, 07:23:53 PM »
Hi guys.
I have to understand how this program works. All comments are mine. Could someone make me sure my thoughts are valid? Thisprogram count 128 bit factorial. Why there are not any mul instructions? All additional comments are welcome : )



Code: [Select]
;128 bits is too big for mul instruction,
;which saves only 64-bits result (EDX (32bits) + EAX (32bits)).

;So first of all you need 4 DWORDS of memory to store 128bits result.
;Then you should replace your mul ebx; on some procedure call,
;that can handle 128bits multiplication.

SECTION .data

    formatd:    db "%d", 0 ; integer??
    formatx:    db "%08x", 0 :??

    name:   resb    20 ;reserve 20 bytes, they declare uninitialized storage space.
    number: resb   4

    array resd 4
    backup resd 4


SECTION .text

extern printf
extern scanf

global main

main:
            push EBP
            mov EBP, ESP    ;base pointer, stack pointer

            push number
            push formatd
            call scanf
            add ESP, 8 ; all: read number

            mov ebx, dword [number]   

            mov dword [array+0], 0x0    ;initialize with zeros
    mov dword [array+4], 0x0
            mov dword [array+8], 0x0
            mov dword [array+16], 0x0

            mov dword [backup+0], 0x0
            mov dword [backup+4], 0x0
            mov dword [backup+8], 0x0
            mov dword [backup+16], 0x0

            mov [array+0], eax



outer_loop:


cmp ebx, 0x1
je end


    mov eax, [array+0] ;assignment a numbers to the array
    mov [backup+0], eax

    mov eax, [array+4]
    mov [backup+4], eax

    mov eax, [array+8]
    mov [backup+8], eax

    mov eax, [array+12]
    mov [backup+12], eax


    mov ecx, ebx
    dec ecx

  inner_loop:

clc

; adding 128 bit number
  mov eax, [backup+0]
adc [array+0], eax ;add carried part from previous multiplication

  mov eax, [backup+4]
adc [array+4], eax

mov eax, [backup+8]
adc [array+8], eax

mov eax, [backup+12]
adc [array+12], eax

clc ;Clear carry flag


  loop inner_loop ; uses ecx (or cx in 16-bit code)

  dec ebx

  jmp outer_loop

  end:



            push dword [array+12]   ; printing number
            push formatx
            call printf
            add ESP, 8


            push dword [array+8]
            push formatx
            call printf
            add ESP, 8


            push dword [array+4]
            push formatx
            call printf
            add ESP, 8


            push dword [array+0]
            push formatx
            call printf
            add ESP, 8


           mov ESP, EBP
           pop EBP

           ret

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Factorial, help to understand
« Reply #1 on: January 03, 2017, 09:03:42 PM »
Hi Eght,

Oh goody! Two programs at once! :)

The first thing that jumps out at me:
Code: [Select]
            mov dword [array+0], 0x0    ;initialize with zeros
    mov dword [array+4], 0x0
            mov dword [array+8], 0x0
            mov dword [array+16], 0x0

            mov dword [backup+0], 0x0
            mov dword [backup+4], 0x0
            mov dword [backup+8], 0x0
            mov dword [backup+16], 0x0

The "16"s need to be "12"s. You get this right later on.

My guess as to why there are no "mul" instructions is that the 128-bit "mul" is done by repeated "add"s. I think I'm going to have to assemble this and try it out to see how it works.

You'll have to forgive me. I'm old and tired and a bit depressed. I used to be better at this, honest. I'd leave this for someone younger to answer, but sometimes when I don't answer a question it doesn't get answered at all (which makes me even more depressed). I'll try to get back to this...

In order to get 128 bits out of "printf", you concatenate hex numbers. In order to compare what we print to the "known" good answer to factorial, we're going to have to convert back and forth to decimal (this is a reminder to myself as well as you).

Later,
Frank


Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Factorial, help to understand
« Reply #2 on: January 03, 2017, 10:19:14 PM »
Code: [Select]
;128 bits is too big for mul instruction,
;which saves only 64-bits result (EDX (32bits) + EAX (32bits)).

;So first of all you need 4 DWORDS of memory to store 128bits result.
;Then you should replace your mul ebx; on some procedure call,
;that can handle 128bits multiplication.

SECTION .data

    formatd:    db "%d", 0 ; integer??
    formatx:    db "%08x", 0 :?? <- semicolon, not colon - it calls for 8 bytes of hex

; Nasm warns about this. No harm. but to shut it up:
section .bss
    name:   resb    20 ;reserve 20 bytes, they declare uninitialized storage space.
    number: resb   4
; "resd 1" does the same thing - might be clearer?

    array resd 4
    backup resd 4


SECTION .text

extern printf
extern scanf

global main

main:
            push EBP
            mov EBP, ESP    ;base pointer, stack pointer

            push number
            push formatd
            call scanf
            add ESP, 8 ; all: read number

            mov ebx, dword [number]   

            mov dword [array+0], 0x0    ;initialize with zeros
    mov dword [array+4], 0x0
            mov dword [array+8], 0x0
            mov dword [array+12], 0x0

            mov dword [backup+0], 0x0
            mov dword [backup+4], 0x0
            mov dword [backup+8], 0x0
            mov dword [backup+12], 0x0

            mov [array+0], eax
; at this point, eax is the return from scanf. Not sure you want that here.

... more later?

Best,
Frank