0

I am tasked with writing my first assembly code which takes a number between 1-12 entered by the user and outputs the factorial. I need to write 3 procedures one for the input, one to calculate factorial and one to print the result. I believe I have written it correctly (I didn't) but after getting the input from the user, the program terminates. I never see the result of my "Print" procedure. When trying to debug my code I get the error:

Program received signal SIGSEGV, Segmentation fault.

This error comes right after the first step of "invoke input"

Here is my complete code :

include c:\asmio\asm32.inc
includelib c:\asmio\asm32.lib
includelib c:\asmio\User32.lib ; SASM files for I/O
includelib c:\asmio\Kernel32.lib ; SASM files for I/O

input proto ; 0 parameters
Factorial proto nvx: dword ; 1 parameter
Print proto nax: dword, nf: dword ; 2 parameters  

; -------------------------------------------------------
.const ; Section to declare and initialize constants
NULL = 0
; -------------------------------------------------------
.data ; Section to declare and initialize variables
       nvx dword ?  
       nfx dword ?  
       nf dword ?  
       ask byte "Enter a number between 1-12: ", NULL
       fin byte "! is ", NULL
; -------------------------------------------------------
.code ; The actual code begins here: Main program

main proc ; Just like C++ this is the main program
start: 

       invoke input 
       mov nvx, eax
       invoke Factorial, nvx 
       mov nfx, eax
       invoke Print, nvx, nfx

 ret 0 ; need this line to return to caller
 main endp ; End of the procedure main
 ; -------------------------------------------------------
  input proc 
        mov   edx, OFFSET ask  
        call  WriteString        
        call  ReadInt    
ret
input endp
 ; -------------------------------------------------------

   Factorial proc USES ECX EBX nv: dword 
        mov ecx, nv ;start loop counter at value given by user because we need to multiply this many times to find the factorial.

        mov ebx, nv ; hold value of nv as divisor

        inc nv ; This is to account for 0! We increment by one and after the loop divide by nv

        mov eax, nv ; stores the largest number for multiplication


    L1:     
        dec nv ; becomes next largest number
        mul nv ; multiplication 
        mov eax, edx ; stores product into eax for next multiplication
        loop L1

        inc ebx
        cdq
        idiv ebx ; divide final product by original number + 1 for the correct factorial


        ret
        Factorial endp


    Print proc nax: dword, na: dword
        mov eax, nvx 
        call WriteString
        mov eax, OFFSET fin
        call WriteString
        mov eax, na
        call WriteString

        ret
        Print endp

end main ; End of the entire program
; -------------------------------------------------------
Google Z
  • 5
  • 3
  • Which instruction exactly faults? – Peter Cordes Oct 28 '19 at 02:43
  • @PeterCordes The debugger arrow is pointing at "Invoke input", I click continue and reach the error: "Program received signal SIGSEGV, Segmentation fault" I'm especially confused because when running the program normally I do reach the section that asks the user for their input (Which is an instruction within the procedure where the debugger seems to fail.) – Google Z Oct 28 '19 at 02:52
  • `invoke` isn't an actual x86 instruction; it's a MASM pseudo-instruction / macro. What actual instruction faulted? Look at the disassembly window and register values. Could it be some kind of linker problem where it assembled to an indirect call with a bad pointer? – Peter Cordes Oct 28 '19 at 02:54
  • @PeterCordes hmm, I'm using invoke because my professor asked me to do so. When debugging, the only instuction reached is the "Invoke input" and once I click continue I reach an error. – Google Z Oct 28 '19 at 03:00
  • I didn't say you shouldn't use `invoke` in your source, I'm saying you should look at the disassembly view to see what *actual* instruction(s) it assembled to so you can tell why the fault happened. e.g. is ESP invalid so `call` faults when pushing a return address? Or is the call target incorrect? Or did it assemble to an indirect `call [mem]` or something? Or is your debugger tricking you, and the fault happened somewhere *inside* that instruction. – Peter Cordes Oct 28 '19 at 03:03
  • Oh wait, you said you had to click "continue" before seeing a fault? `invoke input` is the very *first* instruction so it always starts there. But then "continue" runs until a fault. Look at EIP and registers *after* hitting the fault to see where it was. (I had previously been assuming you were talking about the debugger "here" arrow pointing at the `invoke input` line *after* hitting the fault.) – Peter Cordes Oct 28 '19 at 03:05
  • 1
    @PeterCordes when I go through my program using the "step into" command, it seems to run fine until reaching my third procedure which is labeled as "print". The error seems to come when calling WriteString within that procedure – Google Z Oct 28 '19 at 03:24
  • 2
    `nvx` is not a string, it's a number. Don't try to use `WriteString` on it because that will try to dereference it as a pointer and hence fault. Use `WriteInt`. Same for `na`. PS: you should use `nax` in your `Print` because that's the argument. – Jester Oct 28 '19 at 10:22

0 Answers0