Search code examples
assemblystackx86-64nasmcpu-registers

Assembly- push'd register RAX is not the same when I pop it off the stack?


I'm currently writing an assembly NASM on a 64 bit machine to print the factorial of a given input, and then return the input. The program works correctly for printing out the factorial values, but the return value is not returning the input. Yes, the code is horrible, and I don't want you to simply rewrite the whole thing. (This is my homework.) I just want someone to explain why my return register (rax) is NOT preserving the value it had from the start.

extern read_input
extern print_int
call read_input

push rax   ;save n
mov rcx, 1 ;counter
push rcx   ;save counter
push rdi   ;save print int

jmp test

print:
pop rdi
imul rdi, rcx ;multiply by current counter
push rdi      ;save our multiplication factor
call print_int

pop rdi
pop rcx 
pop rax    ;restore trashed variables
add rcx, 1 ;increment counter by 1
push rax   ;push stuff back on stack
push rcx
push rdi

jmp test

test:
cmp rcx, rax
jle print

pop rax 
pop rcx 
pop rdi ;clear stack
ret

Output:

Please enter an input value:
read_input> Returning 4 (0x4)
Printing integer 1 (0x1)
Printing integer 2 (0x2)
Printing integer 6 (0x6)
Printing integer 24 (0x18)
Program complete.  Return 24 (0x18)

I want it to return my input, which in this case would be 4.

Any insight would be appreciated.


Solution

  • The order of the pushes and pops is wrong.

    The pushes:

    push rax   ;save n
    mov rcx, 1 ;counter
    push rcx   ;save counter
    push rdi   ;save print int
    ...
    push rax   ;push stuff back on stack
    push rcx
    push rdi
    

    The pops:

    pop rdi
    pop rcx 
    pop rax    ;restore trashed variables
    ...
    pop rax 
    pop rcx 
    pop rdi ;clear stack
    ret
    

    At the end rax and rdi are swapped, oops.