Linux体系结构
内核空间与用户空间是程序执行的两种不同状态,通过调用和硬件中断才能完成从用户空间到内核空间的转移。如右图所示:
linux体系结布光
从上图获知,Linux由用户空间和内核空间
通常情况下,用户进程是不能访问内核的。它既不能访问内核所在的显存空间,也不能调用内核中的函数。Linux内核中设置了一组用于实现各类系统功能的子程序,用户可以通过调用她们访问linux内核的数据和函数,这种系统调用插口(SCI)称为系统调用。
系统调用和普通函数的区别:
系统调用和普通的函数调用十分相像,区别仅仅在于,系统调用由操作系统内核实现,运行于内核态;而普通的函数调用由函数库或用户自己提供,运行于用户态。
系统调用数:
在2.6.32版内核中,共有系统调用365个,可在arch/arm/include/asm/unistd.h中找到它们。
/*Thisfilecontainsthesystemcallnumbers*/
#define__NR_restart_syscall(__NR_SYSCALL_BASE+0)
#define__NR_exit(__NR_SYSCALL_BASE+1)
#define__NR_fork(__NR_SYSCALL_BASE+2)
......
#define__NR_preadv(__NR_SYSCALL_BASE+361)
#define__NR_pwritev(__NR_SYSCALL_BASE+362)
#define__NR_rt_tgsigqueueinfo(__NR_SYSCALL_BASE+363)
#define__NR_perf_event_open(__NR_SYSCALL_BASE+364)
系统调用的功能:
主要分为3大类:
(1)进程控制类
fork创建一个子进程
clone根据指定条件创建子进程
execve运行可执行文件
...
(2)文件控制操作
fcntl文件控制
open打开文件
read读文件
...
(3)系统控制
ioctlI/O总控制函数
reboot重新启动
—sysctl读写系统参数
...
使用系统调用函数举例:
下边通过time函数系统调用实现从格林尼治时间1970年1月1日0:00开始到现今的秒数。
#include
main()
time_tt_time;
t_time=time((time_t*)0);/*调用time系统调用*/
printf("Thetimeis%ldn",t_time);
系统调用工作原理:
通常情况下,用户进程是不能访问内核的。它既不能访问内核所在的显存空间,也不能调用内核中的函数。系
统调用是一个例外。其原理是(1)进程先用适当的值填充寄存器,(2)之后调用一个特殊的指令,(3)这个指令会让用户程序跳转到一个事先定义好的内核中的一个位置。(4)进程可以跳转到的固定的内核位置。这个过程检测系统调用号,这个号码告诉内核进程恳求哪种服务。之后,它查看系统调用表(sys_call_table)找到所调用的内核函数入口地址。接着,就调用函数,等返回后,做一些系统检测linux内核系统调用,最后返回到进程。
工作原理概述:
(1)适当的值
所有适当的值我们都可以在include/asm/unistd.h中找到,在这个文件中为每一个系统调用规定了惟一的编号,称作系统调用号。
#define__NR_utimensat(__NR_SYSCALL_BASE+348)
#define__NR_signalfd(__NR_SYSCALL_BASE+349)
#define__NR_timerfd_create(__NR_SYSCALL_BASE+350)
#define__NR_eventfd(__NR_SYSCALL_BASE+351)
#define__NR_fallocate(__NR_SYSCALL_BASE+352)
这儿面每一个宏就是一个系统调用号
(2)特殊的指令
在IntelCPU中linux内核系统调用linux makefile,这个指令由中断0x80实现
在ARM中,这个指令是SWI(softwhereinterrupt:软中断指令),现今重新命名为SVC
(3)固定的位置
每位CPU固定的位置是不一样的,在ARM体系中这个固定的内核位置是ENTRY(vector_swi)(在archshkernelentry-common.S),也就是PC表针会跳转到这个位置
(4)相应的函数
内核依照应用程序传递来的系统调用号linux安装,从系统调用表sys_call_table找到相应的内核函数
CALL(sys_restart_syscall)
CALL(sys_exit)
CALL(sys_fork_wrapper)
实例:
工作原理(应用):下边是一个从用户open调用到找到内核中具体的系统调用函数入口地址的大体流程
#define__syscall(name)"swit"__NR_##name"nt“
intopen(constchar*pathname,intflags)
。。。。。。
__syscall(open);
。。。。。。
转化为
intopen(constchar*pathname,intflags)
。。。。。。
swit__NR_open//#define__NR_open(__NR_SYSCALL_BASE+5)
。。。。。。
//内核入口
/*arch/arm/kernel/entry-common.S*/
ENTRY(vector_swi)
……………………
adrtbl,sys_call_table@loadsyscalltablepointer
……………………
ldrccpc,[tbl,scno,lsl#2]@callsys_*routine
……………………
ENTRY(sys_call_table)
#include"calls.S"
/*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)
本文原创地址://gulass.cn/ltxjgnhkjyyh.html编辑:刘遄,审核员:暂无