【发布时间】:2021-09-22 14:56:03
【问题描述】:
我正在编写一个调用子例程阶乘的程序,然后计算 5 的阶乘。返回后将打印答案。但是,在我尝试运行我的程序后,我得到了一个分段错误。调试器显示错误来自第 41 行,该行仅包含要从子例程返回的 Ret 语句。是什么导致了这种分段错误?
代码如下:
1
2 .data
3 .text
4
5 .global main
6 main:
7 pushq %rbp #prologue
8 mov %rsp, %rbp
9
10 push $5 #push value on stack for it to be operated
11 call factorial
12 mov -4(%rbp), %rdi #move answer into %rdi
13 mov $0, %rax #no vectors
14 call printf
15
16 mov %rbp, %rsp #epilogue
17 popq %rbp
18
19 mov $0, %rdi #exit of the program
20 call exit
21
22 factorial:
23 pushq %rbp #epilogue
24 mov %rsp, %rbp
25
26 mov 8(%rbp), %rdi #move value from line 10 into %rdi
27 mov $1, %rax # move 1 into %rax, here the result will come
28
29 factorial_loop_start:
30 cmpb $1, (%rdi) #compare %rdi to 1 to see if loop ends
31 je factorial_end
32 imul %rdi, %rax #multiply %rdi with %rax and put the answer in %rax
33 dec %rdi #decrement %rdi and return to start of loop
34 jmp factorial_loop_start
35
36 factorial_end:
37 mov %rax, 8(%rbp) #move the result in %rax to the original stack position of
38 #the value that needs to be processed
39 mov %rbp, %rsp #epilogue
40 popq %rbp
41 ret
【问题讨论】:
-
在调试器中单步验证每条指令是否达到预期效果;跟踪堆栈,以及压入堆栈的内容。
call会压入一个返回地址,所以在调用指令之后,栈顶应该有一个指向第 12 行的指针;还要注意rsp值。当ret执行时,同样的rsp值应该在那里,同样的第12 行代码指针作为堆栈的顶部项目。首先从一个小测试开始,例如factorial(1)并确保它有效,然后使用factorial(2)进入循环。 -
您正在使用
cmpb来测试终端值1,但您可能需要cmpl或cmpq。此外,由于 5 已按值传递,因此您希望将其直接用作值,而不是用作指针。
标签: assembly segmentation-fault x86-64 att