系统调用是操作系统提供的服务,用户程序通过各种系统调用,来引用内核提供的各种服务,系统调用的执行让
用户程序陷入内核,该陷入动作由swi软中断完成。当用户态的进程调用一个系统调用时,CPU通过软中断切换到
SVC模式并开始执行一个内核函数,完成用户态进程需要完成的工作。
fork():
path: glibc-2.3.6/nptl/sysdeps/unix/sysv/linux/pt-fork.c
#include // include __libc_fork()函数声明
pid_t __fork (void)
{
return __libc_fork ();
}
strong_alias (__fork, fork) // ./include/libc-symbols.h
// 实际上这里告诉编译器fork这个名字就代表着__fork这个名字,如果这里没有
// __fork()的定义,编译器就会报错。
// 类似地,存在weak_alias(XXX, xxx),也是取别名,但是编译器在XXX没有定义
// 的时候,不会报错。
// 可以参考强符号、弱符号,强引用和弱引用来理解它
vfork():
path: glibc-2.3.6/sysdeps/generic/vfork.c
#include
#include
__pid_t __vfork (void)
{
return __fork ();
}
libc_hidden_def (__vfork)
weak_alias (__vfork, vfork)
可以看出调用vfork是__vfork的别名,并且实际上是调用了__fork函数来实现__vfork函数的
clone():
path: glibc-2.3.6/sysdeps/unix/sysv/linux/arm/clone.S
该文件中是用汇编代码实现了__clone函数,存在:
weak_alias (__clone, clone)
__clone()函数声明如下:
extern int __clone (int (*__fn) (void *__arg), void *__child_stack,
int __flags, void *__arg, ...);
path: glibc-2.3.6/include/sched.h
pthread_create():
该函数的源码位置比较特殊,位于目录linuxthread目录下。
path:linuxthread/pthread.c
...
__pthread_create_2_1()
__pthread_create_2_0(),最终还是调用__pthread_create_2_1()来实现的。
*********************
__libc_fork():
path: glibc-2.3.6/nptl/sysdeps/unix/sysv/linux/fork.c
...
#ifdef ARCH_FORK
pid = ARCH_FORK ();
#else
# error "ARCH_FORK must be defined so that the CLONE_SETTID flag is
used"
pid = INLINE_SYSCALL (fork, 0);
#endif
...
这里pid = INLINE_SYSCALL (fork, 0);语句会得到执行,下面是3个重要的头文件:
sysdeps/unix/sysv/linux/arm/sysdep.h
sysdeps/unix/arm/sysdep.h
sysdeps/unix/sysdep.h
sysdeps/arm/sysdep.h
INLINE_SYSCALL这个宏定义于文件sysdeps/unix/sysv/linux/arm/sysdep.h中,该处的宏定义很复杂:
...
#define SYS_ify(syscall_name) (__NR_##syscall_name) // 获取中断号
//
中断号定义在:arm平台文件系统(制作文件系统时,需要拷贝交叉工具链中的头文件和库)中include/asm/unistd.h
#define __NR_restart_syscall (__NR_SYSCALL_BASE+ 0)
#define __NR_exit (__NR_SYSCALL_BASE+ 1)
#define __NR_fork (__NR_SYSCALL_BASE+ 2)
#define __NR_read (__NR_SYSCALL_BASE+ 3)
#define __NR_write (__NR_SYSCALL_BASE+ 4)
#define __NR_open (__NR_SYSCALL_BASE+ 5)
...
...
#define __NR_vfork (__NR_SYSCALL_BASE+ 190)
...
#define __NR_clone (__NR_SYSCALL_BASE+ 120)
...
...
***/
...
#undef INLINE_SYSCALL
#define INLINE_SYSCALL(name, nr, args...) \
({ unsigned int _sys_result = INTERNAL_SYSCALL (name, , nr, args);
\ // note1
if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (_sys_result, ), 0))
\ // 软中断异常返回处理
{ \
__set_errno (INTERNAL_SYSCALL_ERRNO (_sys_result, )); \
_sys_result = (unsigned int) -1; \
} \
(int) _sys_result; })
#undef INTERNAL_SYSCALL_DECL
#define INTERNAL_SYSCALL_DECL(err) do { } while (0)
#undef INTERNAL_SYSCALL // note1
#define INTERNAL_SYSCALL(name, err, nr, args...) \
({ unsigned int _sys_result; \
{ \
register int _a1 asm ("a1"); \ // 定义一个寄存器变量,存放在a1 <==>
r0
LOAD_ARGS_##nr (args) \
asm volatile ("swi %1 @ syscall " #name \ // swi
产生一个软中断异常,%1代表第一个输入参数
: "=r" (_a1) \ // _a1 = rx
: "i" (SYS_ify(name)) ASM_ARGS_##nr \ // 输入参数:软中断号(立即数),参数列表
: "memory"); \ // 告诉编译器内存可能被改变
_sys_result = _a1; \
} \
(int) _sys_result; })
#undef INTERNAL_SYSCALL_ERROR_P
#define INTERNAL_SYSCALL_ERROR_P(val, err) \
((unsigned int) (val) >= 0xfffff001u)
#undef INTERNAL_SYSCALL_ERRNO
#define INTERNAL_SYSCALL_ERRNO(val, err) (-(val))
#define LOAD_ARGS_0()
#define ASM_ARGS_0
#define LOAD_ARGS_1(a1) \
_a1 = (int) (a1); \
LOAD_ARGS_0 ()
#define ASM_ARGS_1 ASM_ARGS_0, "r" (_a1)
#define LOAD_ARGS_2(a1, a2) \
register int _a2 asm ("a2") = (int) (a2); \
LOAD_ARGS_1 (a1)
#define ASM_ARGS_2 ASM_ARGS_1, "r" (_a2)
#define LOAD_ARGS_3(a1, a2, a3) \
register int _a3 asm ("a3") = (int) (a3); \
LOAD_ARGS_2 (a1, a2)
#define ASM_ARGS_3 ASM_ARGS_2, "r" (_a3)
#define LOAD_ARGS_4(a1, a2, a3, a4) \
register int _a4 asm ("a4") = (int) (a4); \
LOAD_ARGS_3 (a1, a2, a3)
#define ASM_ARGS_4 ASM_ARGS_3, "r" (_a4)
#define LOAD_ARGS_5(a1, a2, a3, a4, a5) \
register int _v1 asm ("v1") = (int) (a5); \
LOAD_ARGS_4 (a1, a2, a3, a4)
#define ASM_ARGS_5 ASM_ARGS_4, "r" (_v1)
#define LOAD_ARGS_6(a1, a2, a3, a4, a5, a6) \
register int _v2 asm ("v2") = (int) (a6); \
LOAD_ARGS_5 (a1, a2, a3, a4, a5)
#define ASM_ARGS_6 ASM_ARGS_5, "r" (_v2)
#define LOAD_ARGS_7(a1, a2, a3, a4, a5, a6, a7) \
register int _v3 asm ("v3") = (int) (a7); \
LOAD_ARGS_6 (a1, a2, a3, a4, a5, a6)
#define ASM_ARGS_7 ASM_ARGS_6, "r" (_v3)
APCS 是arm过程调用标准(ARM Procedure Call Standard)。
APCS 对我们通常称为 R0 到 R14 的寄存器起了不同的名字,如下:
Reg# APCS 意义
R0 a1 工作寄存器
R1 a2 "
R2 a3 "
R3 a4 "
R4 v1 必须保护
R5 v2 "
R6 v3 "
R7 v4 "
R8 v5 "
R9 v6 "
R10 sl 栈限制
R11 fp 桢指针
R12 ip
R13 sp 栈指针
R14 lr 连接寄存器
R15 pc 程序计数器
*********************
*********************
__clone()
.text
ENTRY(__clone)
@ sanity check args
cmp r0, #0
cmpne r1, #0
moveq r0, #-EINVAL
beq PLTJMP(syscall_error)
@ insert the args onto the new stack
str r3, [r1, #-4]! // 线程函数参数入栈,(child_stack)
str r0, [r1, #-4]! // 线程函数指针入栈
@ do the system call
@ get flags
mov r0, r2 // flags 存入r0
@ new sp is already in r1
swi SYS_ify(clone) // swi __NR_clone, 产生软中断异常
movs a1, a1
blt PLTJMP(C_SYMBOL_NAME(__syscall_error))
RETINSTR(ne, lr)
@ pick the function arg and call address off the stack and
execute
ldr r0, [sp, #4]
mov lr, pc
ldr pc, [sp]
@ and we are done, passing the return value through r0
b PLTJMP(_exit)