1.系统调用
一般情况下,用户进程是不能访问内核的。它既不能访问内核中的数据,也不能调用内核中的函数。但系统调用是一个例外。还有一个是中断
Linux内核中设置了一组用于实现各
种系统功能的子程序,称为系统调
用。用户可以通过系统调用命令在自
己的应用程序中调用它们。
2.区别
系统调用和普通的函数调用非常相
似,区别仅仅在于,系统调用由操作
系统内核实现,运行于内核态;而普
通的函数调用由函数库或用户自己提
供,运行于用户态。
3.库函数
Linux系统还提供了一些C语言函数
库,这些库对系统调用进行了一些包
装和扩展,这些库函数与系统调用的
关系非常紧密
4.系统调用数
在2.6.29 版内核中,共有系统调用332个,可
在arch/arm/include/asm/unistd.h中找到它
们。
5.使用系统调用
#include<time.h>
main()
{
time_t the_time;
the_time=time((time_t *)0); /*调用time系统调用*/
printf("The time is %ld\n",the_time);
}
/* 从格林尼治时间1970年1月1日0:00开始到现在的秒数。 */
6.工作原理
一般情况下,用户进程是不能访问内核的。它既不能访
问内核所在的内存空间,也不能调用内核中的函数。系
统调用是一个例外。
其原理是进程先用适当的值填充寄
存器,然后调用一个特殊的指令,这个指令会让用户程
序跳转到一个事先定义好的内核中的一个位置,内核根据应用程序所填充的固定值来找到相应的函数执行。
1.适当的值
在文件include/asm/unistd.h中为每一个系统调用规定了唯一的编号,这个号码称为系统调用号
#define__NR_restart_syscall (__NR_SYSCALL_BASE+0)
2.特殊的指令
v 在Intel CPU中,这个指令由中断0x80实现。
v 在ARM中,这个指令是SWI
指令(已经重命名为SVC指令)
3.固定的位置(在arm中)
ENTRY(vector_swi) <entry-common.S>。
4.相应的函数
上面过程检查系统调用号,这个号码告诉内
核进程请求哪种服务。然后,它查看系统
调用表(sys_call_table)找到所调用的内核
函数入口地址。接着,就调用函数,等返
回后,做一些系统检查,最后返回到进
程。
/* arch/arm/kernel/calls.S */
/* 0 */
CALL(sys_restart_syscall)
CALL(sys_exit)
CALL(sys_fork_wrapper)
CALL(sys_read)
CALL(sys_write)
/* 5 */
CALL(sys_open)
...... ...... ...... ...... ...... ...... ...... ...... ...... ...... ......
CALL(sys_dup3)
CALL(sys_pipe2)
/* 360 */
CALL(sys_inotify_init1)
具体流程
1.
#define __syscall(name) "swi\t" __NR_##name "\n\t“
int open( const char * pathname, int flags)
{
。。。。。。
__syscall(open);
。。。。。。
}
转化为
int open( const char * pathname, int flags)
{
。。。。。。
swi\t __NR_open
。。。。。。
}
2.
/* arch/arm/kernel/entry-common.S */
ENTRY(vector_swi)
......
..
....
....
..
......
adr tbl, sys_call_table
......
..
....
....
..
......
ldrcc pc, [tbl, scno, lsl #2]
......
......
......
@ load syscall table pointer
@ call sys_* routine
......
ENTRY(sys_call_table)
#include "calls.S"
3.
/* arch/arm/kernel/calls.S */
/* 0 */
CALL(sys_restart_syscall)
CALL(sys_exit)
CALL(sys_fork_wrapper)
CALL(sys_read)
CALL(sys_write)
/* 5 */
CALL(sys_open)
...... ...... ...... ...... ...... ...... ...... ...... ...... ...... ......
CALL(sys_dup3)
CALL(sys_pipe2)
/* 360 */
CALL(sys_inotify_init1)
/*************************************************
**************************************************/
通过反汇编c库来查看具体的系统调用过程
arm-linux-objdump -D -S libc.so.6 >log
通过分析反汇编的文件来查看具体的系统调用
/*************************************************
**************************************************/
7.实现系统调用
向内核中添加新的系统调用,需要执行 3
个步骤:
1. 添加新的内核函数
2. 更新头文件 unistd.h
3. 针对这个新函数更新系统调用表
calls.S
实现系统调用
1. 在kernel/sys.c中添加函数:
asmlinkage int sysMul(int a, int b)
{
int c;
c = a*b;
return c;
}
/*asmlinkage 使用锥栈进行参数传递*/
2. 在arch/arm/include/asm/unistd.h中添
加如下代码:
#define __NR_sysMul 361
3.在arch/arm/kernel/calls.S中添加代
码,指向新实现的系统调用函数:
CALL(sysMul)
8.调用方式
#include <stdio.h>
#include <linux/unistd.h>
main()
{
int result;
result =
syscall(361,1, 2);//调用系统调用
printf("result = ", result);
}
一般情况下,用户进程是不能访问内核的。它既不能访问内核中的数据,也不能调用内核中的函数。但系统调用是一个例外。还有一个是中断
Linux内核中设置了一组用于实现各
种系统功能的子程序,称为系统调
用。用户可以通过系统调用命令在自
己的应用程序中调用它们。
2.区别
系统调用和普通的函数调用非常相
似,区别仅仅在于,系统调用由操作
系统内核实现,运行于内核态;而普
通的函数调用由函数库或用户自己提
供,运行于用户态。
3.库函数
Linux系统还提供了一些C语言函数
库,这些库对系统调用进行了一些包
装和扩展,这些库函数与系统调用的
关系非常紧密
4.系统调用数
在2.6.29 版内核中,共有系统调用332个,可
在arch/arm/include/asm/unistd.h中找到它
们。
5.使用系统调用
#include<time.h>
main()
{
time_t the_time;
the_time=time((time_t *)0); /*调用time系统调用*/
printf("The time is %ld\n",the_time);
}
/* 从格林尼治时间1970年1月1日0:00开始到现在的秒数。 */
6.工作原理
一般情况下,用户进程是不能访问内核的。它既不能访
问内核所在的内存空间,也不能调用内核中的函数。系
统调用是一个例外。
其原理是进程先用适当的值填充寄
存器,然后调用一个特殊的指令,这个指令会让用户程
序跳转到一个事先定义好的内核中的一个位置,内核根据应用程序所填充的固定值来找到相应的函数执行。
1.适当的值
在文件include/asm/unistd.h中为每一个系统调用规定了唯一的编号,这个号码称为系统调用号
#define__NR_restart_syscall (__NR_SYSCALL_BASE+0)
2.特殊的指令
v 在Intel CPU中,这个指令由中断0x80实现。
v 在ARM中,这个指令是SWI
指令(已经重命名为SVC指令)
3.固定的位置(在arm中)
ENTRY(vector_swi) <entry-common.S>。
4.相应的函数
上面过程检查系统调用号,这个号码告诉内
核进程请求哪种服务。然后,它查看系统
调用表(sys_call_table)找到所调用的内核
函数入口地址。接着,就调用函数,等返
回后,做一些系统检查,最后返回到进
程。
/* arch/arm/kernel/calls.S */
/* 0 */
CALL(sys_restart_syscall)
CALL(sys_exit)
CALL(sys_fork_wrapper)
CALL(sys_read)
CALL(sys_write)
/* 5 */
CALL(sys_open)
...... ...... ...... ...... ...... ...... ...... ...... ...... ...... ......
CALL(sys_dup3)
CALL(sys_pipe2)
/* 360 */
CALL(sys_inotify_init1)
具体流程
1.
#define __syscall(name) "swi\t" __NR_##name "\n\t“
int open( const char * pathname, int flags)
{
。。。。。。
__syscall(open);
。。。。。。
}
转化为
int open( const char * pathname, int flags)
{
。。。。。。
swi\t __NR_open
。。。。。。
}
2.
/* arch/arm/kernel/entry-common.S */
ENTRY(vector_swi)
......
..
....
....
..
......
adr tbl, sys_call_table
......
..
....
....
..
......
ldrcc pc, [tbl, scno, lsl #2]
......
......
......
@ load syscall table pointer
@ call sys_* routine
......
ENTRY(sys_call_table)
#include "calls.S"
3.
/* arch/arm/kernel/calls.S */
/* 0 */
CALL(sys_restart_syscall)
CALL(sys_exit)
CALL(sys_fork_wrapper)
CALL(sys_read)
CALL(sys_write)
/* 5 */
CALL(sys_open)
...... ...... ...... ...... ...... ...... ...... ...... ...... ...... ......
CALL(sys_dup3)
CALL(sys_pipe2)
/* 360 */
CALL(sys_inotify_init1)
/*************************************************
**************************************************/
通过反汇编c库来查看具体的系统调用过程
arm-linux-objdump -D -S libc.so.6 >log
通过分析反汇编的文件来查看具体的系统调用
/*************************************************
**************************************************/
7.实现系统调用
向内核中添加新的系统调用,需要执行 3
个步骤:
1. 添加新的内核函数
2. 更新头文件 unistd.h
3. 针对这个新函数更新系统调用表
calls.S
实现系统调用
1. 在kernel/sys.c中添加函数:
asmlinkage int sysMul(int a, int b)
{
int c;
c = a*b;
return c;
}
/*asmlinkage 使用锥栈进行参数传递*/
2. 在arch/arm/include/asm/unistd.h中添
加如下代码:
#define __NR_sysMul 361
3.在arch/arm/kernel/calls.S中添加代
码,指向新实现的系统调用函数:
CALL(sysMul)
8.调用方式
#include <stdio.h>
#include <linux/unistd.h>
main()
{
int result;
result =
syscall(361,1, 2);//调用系统调用
printf("result = ", result);
}