日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > linux >内容正文

linux

Linux Kernel中的系统调用分析

發(fā)布時(shí)間:2025/3/21 linux 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux Kernel中的系统调用分析 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

快速鏈接:
.
👉👉👉 個(gè)人博客筆記導(dǎo)讀目錄(全部) 👈👈👈


相關(guān)鏈接:
optee中utee syscall的實(shí)現(xiàn)(系統(tǒng)調(diào)用實(shí)現(xiàn))

文章目錄

        • 1、系統(tǒng)調(diào)用在Linux Kernel中的map表(系統(tǒng)調(diào)用的數(shù)組)
        • 2、系統(tǒng)調(diào)用的函數(shù)在Kernel中的實(shí)現(xiàn)
        • 3、系統(tǒng)調(diào)用的流程
        • 4、總結(jié)

1、系統(tǒng)調(diào)用在Linux Kernel中的map表(系統(tǒng)調(diào)用的數(shù)組)

在sys.c中定義了__SYSCALL宏

(kernel-4.19/arch/arm64/kernel/sys.c)#define __SYSCALL(nr, sym) asmlinkage long __arm64_##sym(const struct pt_regs *);

例如:

  • __SYSCALL(__NR_flock, sys_flock),其實(shí)就是定義__arm64_sys_flock函數(shù)
  • __SC_COMP(__NR_ioctl, sys_ioctl, compat_sys_ioctl),其實(shí)就是定義__arm64_compat_sys_ioctl函數(shù)

在sys.c中定義并初始化了系統(tǒng)調(diào)用的tab表

(kernel-4.19/arch/arm64/kernel/sys.c)#undef __SYSCALL #define __SYSCALL(nr, sym) [nr] = __arm64_##sym,const syscall_fn_t sys_call_table[__NR_syscalls] = {[0 ... __NR_syscalls - 1] = __arm64_sys_ni_syscall,#include <asm/unistd.h>};

剖析這段代碼,將asm/unistd.h引進(jìn)來了,其實(shí)等價(jià)于下面這句

(kernel-4.19/arch/arm64/kernel/sys.c)const syscall_fn_t sys_call_table[__NR_syscalls] = {[0 ... __NR_syscalls - 1] = __arm64_sys_ni_syscall,__arm64_compat_sys_io_setup,__arm64_sys_io_destroy,__arm64_compat_sys_io_submit......};

2、系統(tǒng)調(diào)用的函數(shù)在Kernel中的實(shí)現(xiàn)

SYSCALL_DEFINE1(arm64_personality, unsigned int, personality) {if (personality(personality) == PER_LINUX32 &&!system_supports_32bit_el0())return -EINVAL;return ksys_personality(personality); }#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__)#define SYSCALL_DEFINEx(x, sname, ...) \SYSCALL_METADATA(sname, x, __VA_ARGS__) \__SYSCALL_DEFINEx(x, sname, __VA_ARGS__)

在kernel中使用SYSCALL_DEFINEx定義的地方,都是在定義系統(tǒng)調(diào)用函數(shù),例如:
這里定義的SYSCALL_DEFINE1(setgid, gid_t, gid),其實(shí)就是定義__arm64_sys_setgid

SYSCALL_DEFINE1(setgid, gid_t, gid){return __sys_setgid(gid);}

3、系統(tǒng)調(diào)用的流程

由于Userspace中C語(yǔ)言使用的libc庫(kù)代碼,我們?cè)趉ernel中是看不到,所以就不做具體分析了。但可以知道的是,該系統(tǒng)調(diào)用的庫(kù)中,最終是要調(diào)用到svc指令的,使cpu陷入svc異常,進(jìn)而跳轉(zhuǎn)到Linux Kernel中的el0_svc向量表中。

如下展示了系統(tǒng)調(diào)用進(jìn)入Linux Kernel后的具體流程:
el0_svc–> el0_svc_handler() --> el0_svc_common() --> invoke_syscall() --> syscall_fn(), syscall_fn指向系統(tǒng)調(diào)用tab表中的具體函數(shù)

(kernel-4.19/arch/arm64/kernel/entry.S)el0_svc:mov x0, spbl el0_svc_handlerb ret_to_userENDPROC(el0_svc) (kernel-4.19/arch/arm64/kernel/syscall.c) asmlinkage void el0_svc_handler(struct pt_regs *regs) {sve_user_discard();el0_svc_common(regs, regs->regs[8], __NR_syscalls, sys_call_table); }static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,const syscall_fn_t syscall_table[]) {unsigned long flags = current_thread_info()->flags;regs->orig_x0 = regs->regs[0];regs->syscallno = scno;cortex_a76_erratum_1463225_svc_handler();local_daif_restore(DAIF_PROCCTX);user_exit();if (has_syscall_work(flags)) {/* set default errno for user-issued syscall(-1) */if (scno == NO_SYSCALL)regs->regs[0] = -ENOSYS;scno = syscall_trace_enter(regs);if (scno == NO_SYSCALL)goto trace_exit;}invoke_syscall(regs, scno, sc_nr, syscall_table);/** The tracing status may have changed under our feet, so we have to* check again. However, if we were tracing entry, then we always trace* exit regardless, as the old entry assembly did.*/if (!has_syscall_work(flags) && !IS_ENABLED(CONFIG_DEBUG_RSEQ)) {local_daif_mask();flags = current_thread_info()->flags;if (!has_syscall_work(flags)) {/** We're off to userspace, where interrupts are* always enabled after we restore the flags from* the SPSR.*/trace_hardirqs_on();return;}local_daif_restore(DAIF_PROCCTX);}trace_exit:syscall_trace_exit(regs); }static void invoke_syscall(struct pt_regs *regs, unsigned int scno,unsigned int sc_nr,const syscall_fn_t syscall_table[]) {long ret;if (scno < sc_nr) {syscall_fn_t syscall_fn;syscall_fn = syscall_table[array_index_nospec(scno, sc_nr)];ret = __invoke_syscall(regs, syscall_fn); //syscall_fn 就是tab表中的函數(shù)} else {ret = do_ni_syscall(regs, scno);}regs->regs[0] = ret; }static long __invoke_syscall(struct pt_regs *regs, syscall_fn_t syscall_fn) {return syscall_fn(regs); //調(diào)用tab表中的函數(shù) }

4、總結(jié)

  • 系統(tǒng)調(diào)用在Kernel中的map表,都在 kernel-4.19/include/uapi/asm-generic/unistd.h 中,表的名字是:sys_call_table,表中成員的示例如下:
#define __NR_io_setup 0 __SC_COMP(__NR_io_setup, sys_io_setup, compat_sys_io_setup) #define __NR_io_destroy 1 __SYSCALL(__NR_io_destroy, sys_io_destroy) #define __NR_io_submit 2 __SC_COMP(__NR_io_submit, sys_io_submit, compat_sys_io_submit) #define __NR_io_cancel 3 __SYSCALL(__NR_io_cancel, sys_io_cancel) #define __NR_io_getevents 4 __SC_COMP(__NR_io_getevents, sys_io_getevents, compat_sys_io_getevents)/* fs/xattr.c */ #define __NR_setxattr 5 __SYSCALL(__NR_setxattr, sys_setxattr) #define __NR_lsetxattr 6 __SYSCALL(__NR_lsetxattr, sys_lsetxattr) #define __NR_fsetxattr 7 __SYSCALL(__NR_fsetxattr, sys_fsetxattr) #define __NR_getxattr 8 __SYSCALL(__NR_getxattr, sys_getxattr) #define __NR_lgetxattr 9 __SYSCALL(__NR_lgetxattr, sys_lgetxattr) ......
  • 系統(tǒng)調(diào)用函數(shù)的定義,都是以SYSCALL_DEFINEx的宏定義的,例如:
SYSCALL_DEFINE1(setgid, gid_t, gid) {return __sys_setgid(gid); }SYSCALL_DEFINE1(sysctl, struct __sysctl_args __user *, args) {struct __sysctl_args tmp;size_t oldlen = 0;ssize_t result;if (copy_from_user(&tmp, args, sizeof(tmp)))return -EFAULT;if (tmp.oldval && !tmp.oldlenp)return -EFAULT;if (tmp.oldlenp && get_user(oldlen, tmp.oldlenp))return -EFAULT;result = do_sysctl(tmp.name, tmp.nlen, tmp.oldval, oldlen,tmp.newval, tmp.newlen);if (result >= 0) {oldlen = result;result = 0;}if (tmp.oldlenp && put_user(oldlen, tmp.oldlenp))return -EFAULT;return result; }

總結(jié)

以上是生活随笔為你收集整理的Linux Kernel中的系统调用分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。