For continuity, my last question was with adding numbers together with a function call: Example x86-64 program. In this one I've tried to apply the lessons pointed out in the previous answer (stack alignment, using
edx instead of
rdx where the results will fit). I've tried to comment inline with the code:
# We are going to calculate 7^2 + 2^4 = 49 + 16 = 65 # The exponent function supports whole numbers (long) >= 0 .section .data base_1: .long 7 exp_1: .long 2 base_2: .long 2 exp_2: .long 4 .section .text .globl _start _start: # We will do the first function call, 7^2 mov base_1(%rip), %edi mov exp_1(%rip), %esi call exp # needs to be 16-byte aligned before the next function call so do two pushes pushq $0 pushq %rax # Now do the second function call mov base_2(%rip), %edi mov exp_2(%rip), %esi call exp # We have the return value in %eax so let's add this with our previous function's value popq %rdi add %eax, %edi mov $60, %eax syscall exp: # Initialize %eax to 1 mov $1, %eax exp_op: cmp $0, %esi je exp_ret imul %edi, %eax dec %esi jmp exp_op exp_ret: ret
I have a few specific questions about the code:
- Is doing a raw
popcommon? Or is the convention always to do
mov rsp rbp...
pop rbp. Why is one method preferred over the other?
- What if I wanted to store the result of the first calculation in a register: are there any registers that are guaranteed to be preserved between function calls? Or is this why the
push...popmethod is used so much?
- Finally, does my
expseem ok? It feels a bit odd having three labels in what amounts to one function. How could that be improved?