试图理解我做错了什么 - 链表Y86的迭代总和

时间:2017-11-24 23:08:11

标签: assembly y86

我正在为一个班级实验室做这件事而且我没有得到我出错的地方。如果我用l而不是q(例如--andl而不是andq,rrmovl而不是rrmovq)后缀我的所有指令,程序是有效的,但不是q。我非常感谢我指出我做错了什么。

   .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

堆栈:

1 个答案:

答案 0 :(得分:1)

我认为您的功能错误不正确:mrmovq 8(%rbp),%rdx会将您的函数的返回地址放入%rdx

恰好是ele1之前的几个字节,它解释了创建“看到移位”值的偏移量 - 而不仅仅是崩溃。 IDK虽然在此之后你不会崩溃。

调用者使用push %rax将指针arg放在堆栈上。之后,call推送一个返回地址(8个字节)。

在您的函数内部,push %rbp%rsp再减少8个字节,然后再将其复制到%rbp。因此,调用者推送的指针arg位于16(%rsp),也是16(%rbp)

mrmovq  16(%rbp),%rdx    # rdx = ls

调试时,请始终尝试测试您的假设。困难的部分有时会弄清楚你正在假设什么,因为它往往是你甚至不认为是咬你的可能问题。 (例如,在这种情况下,获取函数args。)

在寄存器中传递函数args会更容易,比如64位x86代码。例如%rdi中的第一个arg,%rsi中的第二个arg是x86-64 System V调用约定使用的内容。但是如果你“应该”像32位x86调用约定那样在堆栈上传递args,请记住每个push是8字节宽。

OTOH,了解如何使用堆栈并跟踪调用/推送/弹出正在对其进行的操作非常重要。