I'm doing this for a class lab and I'm not getting where I'm going wrong. The program works if I suffix all my instructions with l instead of q ( eg - andl instead of andq , rrmovl instead of rrmovq ) but not with the q. I'd really appreciate some pointer on what I'm doing wrong.
.pos 0
init: irmovq Stack, %rsp # Set up stack pointer
rrmovq %rsp,%rbp # Set up base pointer
irmovq ele1,%rax
pushq %rax
call sum_list # Execute main program
halt # Terminate program
# Sample linked list
.align 8
ele1: .quad 0x00a
.quad ele2
ele2: .quad 0x0b0
.quad ele3
ele3: .quad 0xc00
.quad 0
# int sum_list(list_ptr ls)
sum_list: pushq %rbp
rrmovq %rsp,%rbp
xorq %rax,%rax # val = 0
mrmovq 8(%rbp),%rdx # edx = ls
andq %rdx,%rdx # Set condition codes
je End
Loop: mrmovq (%rdx),%rcx # ecx = ls->val
addq %rcx,%rax # val += ls->val
mrmovq 4(%rdx),%rdx # ls = ls->next ------ tried +8 insetead of 4 also
andq %rdx,%rdx # Set condition codes
jne Loop
End: rrmovq %rbp,%rsp
popq %rbp
nop # makes sure stop in 31 steps
ret
# The stack starts here and grows to lower addresses
.pos 0x100
Stack:
I think you're getting your function args incorrectly: mrmovq 8(%rbp),%rdx
puts your function's return address into %rdx
.
That happens to be a few bytes before ele1
, which explains the offset-load that's creating the "shifted" value you see without just crashing. IDK how you don't crash right after that, though.
Your pointer arg is placed on the stack by the caller with push %rax
. After that, call
pushes a return address (8 bytes).
Inside your function, push %rbp
decrements %rsp
by another 8 bytes before you copy it to %rbp
. Thus the pointer arg pushed by your caller is at 16(%rsp)
, which is also 16(%rbp)
.
mrmovq 16(%rbp),%rdx # rdx = ls
When debugging, always try to test your assumptions. The hard part is sometimes figuring out what you're assuming, because it's often the thing you didn't even consider as a possible problem that bites you. (e.g. in this case, getting the function args.)
It would be easier to pass function args in registers, like 64-bit x86 code does. e.g. first arg in %rdi
, second in %rsi
is what the x86-64 System V calling convention uses. But if you're "supposed to" pass args on the stack like 32-bit x86 calling conventions, remember that each push
is 8 bytes wide.
OTOH, it's important to know how to use the stack, and keep track of what call / push / pop are doing to it.