分段错误并挂在汇编代码中
segmentation fault and hang in assembly code
我正在重新实现分册 1 中 Knuth 的程序 P:生成前 500 个素数。该程序毫无问题地生成了前 25 个素数。该代码如下:
$ cat progp.S
/* print the first 500 primes */
#define n %bx
#define j %r12
#define k %r13
#define pk %r14d
.data
fmt: .asciz "%d\n"
x: .space 1000
.text
.globl main
.type main, @function
main:
pushq %rbp
movq %rsp, %rbp
xorq %rbx, %rbx
movw , x
movw , n
movq , j
Mtwo:
movw n, x(,j,2)
incq j
Mthree:
cmpq 0, j
je end
Mfour:
addw , n
Mfive:
movq , k
Msix:
movzwl x(,k,2), pk
movzwl n, %eax
xorq %rdx, %rdx
divl pk
cmpl [=10=], %edx
je Mfour
Mseven:
cmpl pk, %eax
jle Mtwo
Meight:
incq k
jmp Msix
end:
xorq j, j
loop:
leaq fmt, %rdi
movzwl x(,j,2), %esi
call printf
incq j
cmpq , j
je bye
jmp loop
bye:
movl [=10=], %edi
callq exit
leave
ret
.size main,.-main
.end
如果将 Mthree 中的比较减少到 25,那么程序就可以了。任何更高的值,程序都会在 printf 中出错或挂起。
我正在组装它:
cc -static progp.S
我还可以补充一点,在不调用 printf 的情况下,它成功生成了前 500 个素数,这可以从 gdb 中的 "end" 处放置断点看出。
$ gdb ./a.out
(gdb) b end
Breakpoint 1 at 0x400531
(gdb) run
Starting program: /home/ben/src/hg/asm/knuth/a.out
Breakpoint 1, 0x0000000000400531 in end ()
(gdb) p $rbx
= 3571
我一尝试调用 printf,它就出错了,所以我假设我对堆栈做了一些愚蠢的事情。
printf
在 x86-64 中期望 %rax
中的一个值告诉函数浮点参数的数量。在你的情况下没有这样的参数,所以清楚 %rax
(清除 %eax
也清除 %rax
)。您的程序似乎 运行 可以接受更改:
...
loop:
leaq fmt, %rdi
movzwl x(,j,2), %esi
xor %eax, %eax
call printf
...
我正在重新实现分册 1 中 Knuth 的程序 P:生成前 500 个素数。该程序毫无问题地生成了前 25 个素数。该代码如下:
$ cat progp.S
/* print the first 500 primes */
#define n %bx
#define j %r12
#define k %r13
#define pk %r14d
.data
fmt: .asciz "%d\n"
x: .space 1000
.text
.globl main
.type main, @function
main:
pushq %rbp
movq %rsp, %rbp
xorq %rbx, %rbx
movw , x
movw , n
movq , j
Mtwo:
movw n, x(,j,2)
incq j
Mthree:
cmpq 0, j
je end
Mfour:
addw , n
Mfive:
movq , k
Msix:
movzwl x(,k,2), pk
movzwl n, %eax
xorq %rdx, %rdx
divl pk
cmpl [=10=], %edx
je Mfour
Mseven:
cmpl pk, %eax
jle Mtwo
Meight:
incq k
jmp Msix
end:
xorq j, j
loop:
leaq fmt, %rdi
movzwl x(,j,2), %esi
call printf
incq j
cmpq , j
je bye
jmp loop
bye:
movl [=10=], %edi
callq exit
leave
ret
.size main,.-main
.end
如果将 Mthree 中的比较减少到 25,那么程序就可以了。任何更高的值,程序都会在 printf 中出错或挂起。
我正在组装它:
cc -static progp.S
我还可以补充一点,在不调用 printf 的情况下,它成功生成了前 500 个素数,这可以从 gdb 中的 "end" 处放置断点看出。
$ gdb ./a.out
(gdb) b end
Breakpoint 1 at 0x400531
(gdb) run
Starting program: /home/ben/src/hg/asm/knuth/a.out
Breakpoint 1, 0x0000000000400531 in end ()
(gdb) p $rbx
= 3571
我一尝试调用 printf,它就出错了,所以我假设我对堆栈做了一些愚蠢的事情。
printf
在 x86-64 中期望 %rax
中的一个值告诉函数浮点参数的数量。在你的情况下没有这样的参数,所以清楚 %rax
(清除 %eax
也清除 %rax
)。您的程序似乎 运行 可以接受更改:
...
loop:
leaq fmt, %rdi
movzwl x(,j,2), %esi
xor %eax, %eax
call printf
...