2
\$\begingroup\$

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 push/pop common? Or is the convention always to do push rbp 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...pop method is used so much?
  • Finally, does my exp seem ok? It feels a bit odd having three labels in what amounts to one function. How could that be improved?
asked Sep 11, 2020 at 5:23
\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

I'm no expert, but what the heck, here's a review comment:

# needs to be 16-byte aligned before the next function call so do two pushes
pushq 0ドル
pushq %rax

This comment is good, but I would rephrase it. Two eight-byte pushes makes 16 bytes and doesn't change the stack alignment. Therefore I infer that one of these pushes is significant and the other one is insignificant — but your comment doesn't tell me which is which! So you might say instead

# one extra push to preserve 16-byte stack alignment
pushq 0ドル
# push the result of `exp`
pushq %rax

You could make the generated code smaller by eliminating the insignificant constant 0ドル:

# push the result of `exp`, plus one extra push to preserve 16-byte stack alignment
pushq %rax
pushq %rax

Now the reader doesn't even need to figure out which push is the significant one, because both pushes do the same thing!


But why is preserving 16-byte alignment on calls important? That's not a requirement of the machine. You seem to be trying to follow some specific ABI, like maybe for interoperability with C or C++. Your external documentation should be clearer about what ABI you're trying to follow.

And then, if you are trying to interoperate with C code, you could improve your code by indicating which of its labels are meant as external entrypoints and which ones are just internal local labels. It seems like you intend exp to be called from other code — it's an entrypoint — but e.g. exp_op is not callable, and exp_ret is technically callable but just acts as a no-op. You might mark them somehow as "local implementation details, not for external consumption."

Yeah, you technically already do this by exporting .globl _start and not .globl exp — but there's still a big difference between the callable function exp and the local label exp_op which is not reflected in your naming scheme. If I were doing this, I'd add .globl exp and I'd rename exp_op, exp_ret to something like Lexp1, Lexp2 or L1_looptop, L2_loopend.

answered Sep 11, 2020 at 13:45
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.