我正在为一个班级实验室做这件事而且我没有得到我出错的地方。如果我用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
堆栈:
答案 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,了解如何使用堆栈并跟踪调用/推送/弹出正在对其进行的操作非常重要。