我正在学习在Linux(gcc(上使用x86-64汇编(AT&T(进行编码,但在这段琐碎的代码中找不到解决分段错误的方法。我看到了一些关于堆栈对齐的问题;然而,即使我尝试8美元或16美元,这也会失败:
.global main
main:
#prologue
movq %rsp, %rbp #initialise base pointer
#reserve memory for subroutine
subq $8, %rsp #the line causing the segfault
exit:
movq $0, %rdi
call exit
在调用printf之后,我编写的其他程序似乎运行良好。上面的代码出了什么问题?无论是否调用退出,代码都会失败。此操作和下面的代码正在失败。我使用编译
gcc -o test test.s
整个代码:
.text
formatStr: .asciz "%ld"
resultStr: .asciz "The result is: %dn"
q1: .asciz "Enter the base: "
q2: .asciz "Enter the exponent: "
#qTable2: #look up table for correct string during scanf
# .asciz q1
# .asciz q2
qTable: #alternative look up table
.quad base
.quad exponent
base:
movq $q1, %rdi
ret
exponent:
movq $q2, %rdi
ret
###################
# Subroutine: pow
# Function: Power an integer base to an exponent
# Inputs: uint base, int exponent(natural)
# Outputs: int result
##################
pow:
#prologue
pushq %rbp #store caller base pointer
movq %rsp, %rbp
movq $1, %rax #reset result
movq $0, %rbx #initialise loop
loop1:
imulq %rdi
incq %rbx
cmp %rsi, %rbx #compare loop interator to exponent
jle loop1
#epilogue
movq %rbp, %rsp #clear local variables from stack
pop %rbp #restore caller base pointer
ret
.global main
###################
# Subroutine: Main
# Function: Application entry point
###################
main:
#prologue
pushq %rbp
movq %rsp, %rbp #initialise base pointer
#reserve memory for subroutine
subq $8, %rsp
#Gather the inputs from the user
movq $0, %rbx #loop counter
#inputAcq:
#Call printf using correct question
movq %rax, %rsi #move result into argument 2
movq qTable(,%rbx,8), %rdi #format string as argument 1
call *%rdi
movq $0, %rax #no vector registers
call printf
leaq -16(%rbp,%rbx,8), %rsi #Argument 2
movq formatStr, %rdi #Argument 1
movq $0, %rax #no vector registers
call scanf
incq %rbx #increment loop counter
cmp $1, %rbx #check if more inputs are necessary else continue
jl inputAcq
#Call pow
movq -8(%rbp), %rsi #the exponent
movq -16(%rbp), %rdi #the base
call pow
#Call printf
movq %rax, %rsi #move result into argument 2
movq $resultStr, %rdi #format string as argument 1
movq $0, %rax #no vector registers
call printf
#exit program without errors
exit:
movq $0 , %rdi
call exit
使用(gdb(x/i$pc:时主代码的错误
0x4004e5 <exit+7>: callq 0x4004de <exit>
exit: # target of the CALL instruction
movq $0 , %rdi
call exit
您已经编写了一个包含推送返回地址的无限循环。当您用完堆栈时,它最终会分段故障。
在您自己的代码中为exit
标签使用不同的名称。.Lexit
可以工作,并且在调试时不会显示为标签。
有关GNU中的本地标签语法的更多信息,请参阅此答案。
subq $8, %rsp #the line causing the segfault
由于上面的指令没有引用内存,不可能在该指令上发生分段故障。
你可能误解了你实际看到的东西。你应该
- 显示一个最小的示例,包括构建命令,以及
- 展示你是如何得出"导致segfault的那条线"的结论的,这样你的错误就可以被指出
p.S.要找到发生segfault的实际指令,请在gdb
下运行程序,并在实际发生segfort后执行(gdb) x/i $pc
命令。