Search code examples
assemblyy86

Trying to understand what I'm doing wrong - Iterative sum of linked list Y86


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:


Solution

  • 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.