QQ登录

只需一步,快速开始

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 3295|回复: 4

用skyeye分析linux的fork函数执行的问题

[复制链接]
发表于 2004-12-27 10:31:01 | 显示全部楼层 |阅读模式
大家好!最近我在用skyeye学习arm linux kernel。skyeye真是一个好东西,从
开机开始的Linux kernel代码的运行情况都可以近距离的观察。

不过,现在我遇到一个问题:所有fork出的子进程都会被kernel kill掉。

我用的toolchain是用crosstool编译的gcc-3.2.3 + glibc-2.3.2 +
    linux_kernel_header 2.4.24,目标为arm-softfloat
内核代码是linux-2.6.9或linux-2.4.24+vrs1patched
romfs image使用uclinux制作,把sash代码中的vfork改为fork,编译应用程序使
用的c库为uclibc,并打开了uclibc的mmu配置选项。

skyeye的配置为ep7312

使用这种方法制作的kernel和romfs image,在skyeye中可以正常启动内核,但
是在应用程序中一旦使用fork系统调用,子进程就会立刻被kill,而父进程还可以正常运行。通过在skyeye中在force_sig_info函数处设置断点发现,子进程一被
fork就立刻发生一次page fault,并被内核发送SIGSEGV信号kill。

如果sash中的fork改为vfork则一切正常。(skyeye test suite中的romfs及initrd
中只使用了vfork而没有使用fork)

察看uclibc的源码发现,在uclibc中fork和vfork的实现不同:
fork使用内联汇编实现:

#define INTERNAL_SYSCALL(name, err, nr, args...)                \
  ({ unsigned int _sys_result;                                  \
     {                                                          \
       register int _a1 asm ("a1");                             \
       LOAD_ARGS_##nr (args)                                    \
       asm volatile ("swi       %1      @ syscall " #name       \
                     : "=r" (_a1)                               \
                     : "i" (SYS_ify(name)) ASM_ARGS_##nr        \
                     : "memory");                               \
       _sys_result = _a1;                                       \
     }                                                          \
     (int) _sys_result; })
#define _syscall0(type,name) \
type name(void) \
{ \
return (type) (INLINE_SYSCALL(name, 0)); \
}
#define __NR___libc_fork __NR_fork
        _syscall0(pid_t, __libc_fork);

而vfork使用汇编实现:

vfork:

#ifdef __NR_vfork
        swi     __NR_vfork
        cmn     r0, #4096
        movcc   pc, lr

        /* Check if vfork even exists.  */
        ldr     r1, =-ENOSYS
        teq     r0, r1
        bne     __syscall_error
#endif

按照vfork的方法,使用汇编语言实现了fork后,发现fork系统调用不再出错。
但是不知道为什么,所以向大家求教。
(我到armlinux上搜索了相关的主题,但没有人提到,所以怀疑是否与skyeye
相关,不知道用开发板的朋友有没有类似的问题)

另:请问除了使用gdb之外,还有什么方法可以反汇编,谢谢。
 楼主| 发表于 2004-12-27 17:06:28 | 显示全部楼层

one step forwoard

我用gcc -S,把uclibc中fork的汇编码dump出来,如下。

        .file   "syscalls.c"
        .text
        .align  2
        .global __libc_fork
        .type   __libc_fork, %function
__libc_fork:
        @ args = 0, pretend = 0, frame = 0
        @ frame_needed = 0, uses_anonymous_args = 0
--->   stmfd   sp!, {r5, lr}
--->   swi     #9437186        @ syscall __libc_fork
        mov     r5, r0
        cmn     r0, #4096
        bls     .L2
        bl      __errno_location(PLT)
        rsb     r3, r5, #0
        str     r3, [r0, #0]
        mvn     r5, #0
.L2:
        mov     r0, r5
        ldmfd   sp!, {r5, pc}
        .size   __libc_fork, .-__libc_fork
        .weak   fork
fork = __libc_fork
        .ident  "GCC: (GNU) 3.3.2"

用这个文件代替系统的fork,出现和以前一样的错误。但是如果把上文汇编代
码中用---->标出的两句颠倒位置,则fork系统调用能够正常工作。
why?

颠倒后的代码为:        .file   "syscalls.c"
        .text
        .align  2
        .global __libc_fork
        .type   __libc_fork, %function
__libc_fork:
        @ args = 0, pretend = 0, frame = 0
        @ frame_needed = 0, uses_anonymous_args = 0
        swi     #9437186        @ syscall __libc_fork
        stmfd   sp!, {r5, lr}
        mov     r5, r0
        cmn     r0, #4096
        bls     .L2
        bl      __errno_location(PLT)
        rsb     r3, r5, #0
        str     r3, [r0, #0]
        mvn     r5, #0
.L2:
        mov     r0, r5
        ldmfd   sp!, {r5, pc}
        .size   __libc_fork, .-__libc_fork
        .weak   fork
fork = __libc_fork
        .ident  "GCC: (GNU) 3.3.2"
回复

使用道具 举报

发表于 2004-12-28 09:19:41 | 显示全部楼层
arm-elf-oujdump 可以反汇编。 gcc -S 也是一个好的选择!
欢迎用skyeye对内核进行探索。如果有了分析和结论,我会把你的文章定为精华,让更多的人进行学习。
回复

使用道具 举报

 楼主| 发表于 2004-12-29 10:11:13 | 显示全部楼层

解决了

谢谢版主,objdump很好用!

通过使用skyeye的log功能,并对skyeye进行了一点小小的hack(让skyeye在
fork系统调用时开始输出log)终于察出了问题。
为便于描述,列出编号代码如下:

1   .file "syscalls.c"
2   .text
3   .align 2
4   .global __libc_fork
5   .type __libc_fork, %function
6   __libc_fork:
7   @ args = 0, pretend = 0, frame = 0
8   @ frame_needed = 0, uses_anonymous_args = 0
9   stmfd sp!, {r5, lr}
10 swi #9437186 @ syscall __libc_fork
11 mov r5, r0
12 cmn r0, #4096
13 bls .L2
14 bl __errno_location(PLT)
15 rsb r3, r5, #0
16 str r3, [r0, #0]
17 mvn r5, #0
18 .L2:
19 mov r0, r5
20 ldmfd sp!, {r5, pc}
21 .size __libc_fork, .-__libc_fork
22 .weak fork
23 fork = __libc_fork
24 .ident "GCC: (GNU) 3.3.2"

Linux为了提高系统性能(减小物理内存使用量)对fork系统调用采用了写时复
制技术。即在fork系统调用后并不为子进程分配内存空间,只是在子进程的页
表中把相应的表项设置为无效。这样,当子进程退出fork系统调用执行第一条
访问内存指令(20行)时,会发生缺页异常,在由Linux系统给子进程分配相
应的存储空间后,重新执行访问内存指令。

问题在于:ARM CPU的不同版本对缺页异常的处理细节(Ldm, stm指令)
不同。

以下参考:ARM Architecture Reference Manual
2.6.5 Data Abort
There are three Abort Model in ARM arch.

Early Abort Model: used in some ARMv3 and earlier implementations.
In this model, base register wirteback occurred for LDC,LDM,STC,STM instructions, and the base register was unchanged for all other
instructions. (oldest)

Base Restored Abort Model: If a Data Abort occurs in an instruction
which specifies base register writeback, the value in the base register
is unchanged. (strongarm, xscale)

Base Updated Abort Model: If a Data Abort occurs in an instruction which
specifies base register writeback, the base register writeback still occurs.
(arm720T)

本文中使用的CPU配置为ep7312(arm720T),所以相应的模型为Base Update
Abort Model。Linux内核中也对此进行了处理,即如果是arm720T cpu,则对
于如上文所列20行处的指令,通过修改sp补偿对base address register的更新。

通过察看skyeye的log发现,skyeye的实现中并没有进行对ldm指令中base
address register的更新,而Linux内核仍然进行补偿,所以造成子进程堆栈
定位的错误而异常退出。

通过修改skyeye的LoadMult函数中更新base address register的部分,fork系
统调用现在已经可以正常工作。但这部分代码在原代码中是被注释掉的,并标
记为:
/* chy 2005-11-24, bug found by [email protected], etc */
不知这里的bug指的是什么?

还有一个问题:
Linux应该把子进程的页表项设为只读,而非不能读写。因此ldm指令不应产生
缺页异常。另,子进程退出fork系统调用的第一条指令(11行),会发生预取指异
常,这似乎也不应该发生,因为是读访问而非写访问。
回复

使用道具 举报

发表于 2004-12-29 12:04:28 | 显示全部楼层
欢迎更多的人讨论,用skyeye动态分析比较有效!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

GMT+8, 2024-5-23 14:35 , Processed in 0.054878 second(s), 16 queries .

© 2021 Powered by Discuz! X3.5.

快速回复 返回顶部 返回列表