试图了解我做错了什么 - 链表 Y86 的迭代求和
Trying to understand what I'm doing wrong - Iterative sum of linked list Y86
我正在为一个 class 实验室做这件事,但我没有弄错。如果我用 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
堆栈:
我认为您获取的函数参数不正确:mrmovq 8(%rbp),%rdx
将函数的 return 地址放入 %rdx
.
这恰好是 ele1
之前的几个字节,这解释了创建 "shifted" 值的偏移负载,而不会导致崩溃。不过,我不知道你怎么不在那之后立即崩溃。
您的指针 arg 由调用者使用 push %rax
放置在堆栈上。之后,call
推送一个 return 地址(8 字节)。
在您的函数中,push %rbp
在将其复制到 %rbp
之前将 %rsp
再减少 8 个字节。因此,调用者推送的指针 arg 位于 16(%rsp)
,这也是 16(%rbp)
.
mrmovq 16(%rbp),%rdx # rdx = ls
调试时,请始终尝试检验您的假设。困难的部分有时是弄清楚 什么 你在假设什么,因为它通常是你甚至没有考虑过的可能问题困扰你的事情。 (例如,在这种情况下,获取函数参数。)
在寄存器中传递函数参数会更容易,就像 64 位 x86 代码一样。例如%rdi
中的第一个参数,%rsi
中的第二个参数是 x86-64 System V 调用约定所使用的。但是,如果您 "supposed to" 像 32 位 x86 调用约定一样在堆栈上传递参数,请记住每个 push
是 8 个字节宽。
OTOH,了解如何使用堆栈并跟踪调用/推送/弹出对其所做的操作很重要。
我正在为一个 class 实验室做这件事,但我没有弄错。如果我用 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
堆栈:
我认为您获取的函数参数不正确:mrmovq 8(%rbp),%rdx
将函数的 return 地址放入 %rdx
.
这恰好是 ele1
之前的几个字节,这解释了创建 "shifted" 值的偏移负载,而不会导致崩溃。不过,我不知道你怎么不在那之后立即崩溃。
您的指针 arg 由调用者使用 push %rax
放置在堆栈上。之后,call
推送一个 return 地址(8 字节)。
在您的函数中,push %rbp
在将其复制到 %rbp
之前将 %rsp
再减少 8 个字节。因此,调用者推送的指针 arg 位于 16(%rsp)
,这也是 16(%rbp)
.
mrmovq 16(%rbp),%rdx # rdx = ls
调试时,请始终尝试检验您的假设。困难的部分有时是弄清楚 什么 你在假设什么,因为它通常是你甚至没有考虑过的可能问题困扰你的事情。 (例如,在这种情况下,获取函数参数。)
在寄存器中传递函数参数会更容易,就像 64 位 x86 代码一样。例如%rdi
中的第一个参数,%rsi
中的第二个参数是 x86-64 System V 调用约定所使用的。但是,如果您 "supposed to" 像 32 位 x86 调用约定一样在堆栈上传递参数,请记住每个 push
是 8 个字节宽。
OTOH,了解如何使用堆栈并跟踪调用/推送/弹出对其所做的操作很重要。