我正在使用 armv7 进行 openwrt 开发并面临由 vfork 引起的段错误。
我编写了一个包含以下部分的小型测试程序:
...
pid_t child_t;
if((child_t = vfork()) < 0)
{
printf("error!\n");
return -1;
}
else if(child_t == 0)
{
printf("in child:pid =%d\n",getpid());
sleep(2);
_exit(0);
}
else
{
printf("in parent:child_t id = %d,pid = %d\n",child_t,getpid());
}
...
vfork() 函数总是导致段错误,这是 gdb 调试跟踪:
...
(gdb) c
Breakpoint 1, main (argc=1, argv=0xbefffed4) at handler.c:33
33 if((child_t = vfork()) < 0)
(gdb) stepi
0x00008474 in vfork () at libpthread/nptl/sysdeps/unix/sysv/linux/arm/../../../../../../../libc/sysdeps/linux/arm/vfo rk.S:71
71 SAVE_PID
(gdb) l
66
67 #else
68 __vfork:
69
70 #ifdef __NR_vfork
71 SAVE_PID
72 DO_CALL (vfork)
73 RESTORE_PID
74 cmn r0, #4096
75 IT(t, cc)
(gdb) b libpthread/nptl/sysdeps/unix/sysv/linux/arm/../../../../../../../libc/sysdeps/linux/arm/vfo rk.S:72
Breakpoint 2 at 0xb6fcf930: file libpthread/nptl/sysdeps/unix/sysv/linux/arm/../../../../../../../libc/sysdeps/linux/arm/vfo rk.S, line 72.
(gdb) disassemble
0x00008584 <+40>: bl 0x8444 <puts>
=> 0x00008588 <+44>: bl 0x8474 <vfork>
0x0000858c <+48>: str r0, [r11, #-12]
(gdb)stepi
...
(gdb) stepi
0x00008474 in vfork () at libpthread/nptl/sysdeps/unix/sysv/linux/arm/../../../../../../../libc/sysdeps/linux/arm/vfo rk.S:71
71 SAVE_PID
(gdb) disassemble
Dump of assembler code for function vfork:
=> 0x00008474 <+0>: add r12, pc, #0, 12
0x00008478 <+4>: add r12, r12, #8, 20 ; 0x8000
0x0000847c <+8>: ldr pc, [r12, #796]! ; 0x31c
(gdb) stepi
…
(gdb) disassemble
Dump of assembler code for function vfork:
0x00008474 <+0>: add r12, pc, #0, 12
0x00008478 <+4>: add r12, r12, #8, 20 ; 0x8000
=> 0x0000847c <+8>: ldr pc, [r12, #796]! ; 0x31c
(gdb)c
Continuing.
Program received signal SIGSEGV, Segmentation fault.
0xffff0fe0 in ?? ()
(gdb)
我还在 vfork.S 找到了 vfork 代码:__vfork:
#ifdef __NR_vfork
SAVE_PID
DO_CALL (vfork)
RESTORE_PID
cmn r0, #4096
IT(t, cc)
#if defined(__USE_BX__)
bxcc lr
#else
movcc pc, lr
#endif
/* Check if vfork even exists. */
ldr r1, =-ENOSYS
teq r0, r1
bne __error
#endif
/* If we don't have vfork, use fork. */
DO_CALL (fork)
cmn r0, #4096
/* Syscall worked. Return to child/parent */
IT(t, cc)
#if defined(__USE_BX__)
bxcc lr
#else
movcc pc, lr
#endif
__error:
b __syscall_error
#endif
更多信息 - 当像这样绕过 vfork 时 -
VFORK_LOCK;
- if ((pid = vfork()) == 0) { /* Child of vfork... */
+ // if ((pid = vfork()) == 0) { /* Child of vfork... */
+ pid = syscall(__NR_fork, NULL);
+ if (pid == 0) { /* Child of vfork... */
一切似乎都很好。
谢谢大家的帮助!