用户进程到系统调用
1.用户进程使用如open();的C库函数。2从库函数(open)中使用"int 0x80"或是syscall命令进入system_call。glibc 中的部分源码//sysdeps/unix/sysv/linux/x86_64/sysdeps.
1.用户进程使用如open();的C库函数。
2从库函数(open)中使用"int 0x80"或是syscall命令进入system_call。
glibc 中的部分源码 //sysdeps/unix/sysv/linux/x86_64/sysdeps.h INLINE_SYSCALL--->INTERNAL_SYSCALL--->INTERNAL_SYSCALL_NCS--->syscall. # define INLINE_SYSCALL(name, nr, args...) \ ({ \ unsigned long int resultvar = INTERNAL_SYSCALL (name, , nr, args); \ if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (resultvar, ), 0)) \ { \ __set_errno (INTERNAL_SYSCALL_ERRNO (resultvar, )); \ resultvar = (unsigned long int) -1; \ } \ (long int) resultvar; }) # define INTERNAL_SYSCALL(name, err, nr, args...) \ INTERNAL_SYSCALL_NCS (__NR_##name, err, nr, ##args) # define INTERNAL_SYSCALL_NCS(name, err, nr, args...) \ ({ \ unsigned long int resultvar; \ LOAD_ARGS_##nr (args) \ LOAD_REGS_##nr \ asm volatile ( \ "syscall\n\t" \//x86_64的关键指令syscall. : "=a" (resultvar) \ : "0" (name) ASM_ARGS_##nr : "memory", "cc", "r11", "cx"); \ (long int) resultvar; }) |
有一个问题:在i386的CPU上,我们知道linux在初始化时为中断号0x80准备了一个中断处理函数(trap_init-->set_system_trap_gate(SYSCALL_VECTOR, &system_call);)。当发生int 0x80时,CPU通过一系列的动作(这个硬件动作,其它网文介绍很多),到达中断处理函数。那么在x86_64的CPU上,syscall指令能跳到哪去呢?CPU是如何处理这个指令的呢?需要OS为这个指令准备哪些信息?还有它又是怎么回来的?
3 CPU完成一系列切换的动作。
4.进入中断处理函数,更准确的说法是进入内核。
在arch/x86/kernel/entry_64.S#455或是在arch/x86/kernel/entry_32.S#L498(在entry_32.s为例)
ENTRY(system_call)
499 RING0_INT_FRAME # can't unwind into user space anyway
500 pushl_cfi %eax # save orig_eax
501 SAVE_ALL
502 GET_THREAD_INFO(%ebp)
503 # system call tracing in operation / emulation
504 testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp)
505 jnz syscall_trace_entry
506 cmpl $(nr_syscalls), %eax
507 jae syscall_badsys
508syscall_call:
509 call *sys_call_table(,%eax,4)
510 movl %eax,PT_EAX(%esp) # store the return value
511syscall_exit:
512 LOCKDEP_SYS_EXIT
513 DISABLE_INTERRUPTS(CLBR_ANY) # make sure we don't miss an interrupt
514 # setting need_resched or sigpending
515 # between sampling and the iret
516 TRACE_IRQS_OFF
517 movl TI_flags(%ebp), %ecx
518 testl $_TIF_ALLWORK_MASK, %ecx # current->work
519 jne syscall_exit_work
当进入了system_call之后。
SAVE_ALL:???
。。。。
进入sys_call_table.xxx 中。
sys_call_table的定义在哪里,它的引用在哪里?为什么在内核和x86中的很多文件中都有它????
sys_call_table的定义:(在 linux/arch/x86/kernel/syscall_table_32.S)。
ENTRY(sys_call_table)2 .long sys_restart_syscall /* 0 - old "setup()" system call, used for restarting */
3 .long sys_exit
4 .long ptregs_fork
5 .long sys_read
6 .long sys_write
7 .long sys_open /* 5 */
8
这样就可以找到内核定义的sys_function函数了。
5.运行各种各样的系统调用的函数。
那么各种各样的sys_function都是定义在哪里呢? 例:
SYSCALL_DEFINE3(semop, int, semid, struct sembuf __user *, tsops, unsigned, nsops)
{
函数实体。
。。。。。
。。。。。
}
在一些文件中,我们可以找到以上这样的语句。
在syscalls.h中定义如下:
#define SYSCALL_DEFINE1(name, ...) SYSCALL_DEFINEx(1, _##name, __VA_ARGS__) #define SYSCALL_DEFINE2(name, ...) SYSCALL_DEFINEx(2, _##name, __VA_ARGS__) #define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__) #define SYSCALL_DEFINE4(name, ...) SYSCALL_DEFINEx(4, _##name, __VA_ARGS__) #define SYSCALL_DEFINE5(name, ...) SYSCALL_DEFINEx(5, _##name, __VA_ARGS__) #define SYSCALL_DEFINE6(name, ...) SYSCALL_DEFINEx(6, _##name, __VA_ARGS__)
它由一系列的宏,逐步定义的,如何做的??
这些宏的具体定义的内涵是什么?
SYSCALL_DEFINE3(semop,int,semid,......)这个宏,把"semop"的函数,定义成
sys_semop(int semid,struct sembuf __user* tsops,unsigned nsops);
这个sys_semop函数就是sys_call_table中的一部分了。
这样用户进程在使用系统调用时,read,write,或是semget,semop时,就可以调用到相应的sys_xxxx函数了。
附:cond_syscall解释 /* * "Conditional" syscalls * * What we want is __attribute__((weak,alias("sys_ni_syscall"))), * but it doesn't work on all toolchains, so we just do it by hand */ #ifndef cond_syscall #define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall") #endif
在sys_ni.c中:cond_syscall(sys_fanotify_mark);
cond_syscall定义如下:
/*
* "Conditional" syscalls
*
* What we want is __attribute__((weak,alias("sys_ni_syscall"))),
* but it doesn't work on all toolchains, so we just do it by hand */
#ifndef cond_syscall#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
#endif
asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")分析如下:以上嵌入式汇编翻译成汇编代码如下:
.weak #x .set #x,sys_ni_syscall
以上的含义是:在编译时,告诉编译器,当没有符号x时,就用sys_ni_syscall这个符号来代替符号x.
在http://www.acsu.buffalo.edu/~charngda/cc.html中说明如下:
#pragma weak symbol1=symbol2
Declare symbol1 as a weak alias of symbol2. Equivalently, one can use
#pragma weak symbol1=symbol2 定义 symbol1作为symbol2的弱别名,与如下代码等效。
__asm__(".weak symbol1"); //定义symbol1是弱符号。
__asm__(".set symbol1,symbol2"); //把symbol1与symbol2联系起来。
A better way to achieve this is through the "weak, alias" function attributes.
还有一种更好的实现“弱,别名”函数属性的方式。
更多推荐
所有评论(0)