linux内核调用
㈠ linux 怎么调用内核导出的函数
Linux内核没有导出的函数不能调用,即使包含了头文件,也会出现符号未定义的警告,并在加载模块时失败。
以下是我的测试例子:
#include <linux/mole.h>
#include <linux/syscalls.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Linmiaohe");
MODULE_DESCRIPTION("try to evole sys_umount");
extern asmlinkage long sys_umount(char __user *name, int flags);
static int __init sys_umount_init(void)
{
sys_umount("./proc",0);
return 0;
}
static void __exit sys_umount_exit(void)
{
printk(KERN_INFO "***********sys_umount mole has been unregistered*************\n");
}
mole_init(sys_umount_init);
mole_exit(sys_umount_exit);
㈡ Linux的库函数是如何调用内核函数的
看系统调用,还有库函数,以前一直不明白,总是以为 系统调用跟库函数是一样的,但是今天才知道是不一样的。
库函数也就是我们通常所说的应用编程接口API,它其实就是一个函数定义,比如常见read()、write()等函数说明了如何获得一个给定的服务,但是系统调用是通过软中断向内核发出一个明确的请求,再者系统调用是在内核完成的,而用户态的函数是在函数库完成的。
系统调用发生在内核空间,因此如果在用户空间的一般应用程序中使用系统调用来进行文件操作,会有用户空间到内核空间切换的开销。事实上,即使在用户空间使用库函数来对文件进行操作,因为文件总是存在于存储介质上,因此不管是读写操作,都是对硬件(存储器)的操作,都必然会引起系统调用。也就是说,库函数对文件的操作实际上是通过系统调用来实现的。例如C库函数fwrite()就是通过write()系统调用来实现的。
这样的话,使用库函数也有系统调用的开销,为什么不直接使用系统调用呢?这是因为,读写文件通常是大量的数据(这种大量是相对于底层驱动的系统调用所实现的数据操作单位而言),这时,使用库函数就可以大大减少系统调用的次数。这一结果又缘于缓冲区技术。在用户空间和内核空间,对文件操作都使用了缓冲区,例如用fwrite写文件,都是先将内容写到用户空间缓冲区,当用户空间缓冲区满或者写操作结束时,才将用户缓冲区的内容写到内核缓冲区,同样的道理,当内核缓冲区满或写结束时才将内核缓冲区内容写到文件对应的硬件媒介。
系统调用与系统命令:系统命令相对API更高一层,每个系统命令都是一个可执行程序,比如常用的系统命令ls、hostname等,比如strace ls就会发现他们调用了诸如open(),brk(),fstat(),ioctl()等系统调用。
系统调用是用户进程进入内核的接口层,它本身并非内核函数,但他是由内核函数实现的,进入系统内核后,不同的系统调用会找到各自对应的内核函数,这写内核函数被称为系统调用的“服务例程”。也可以说系统调用是服务例程的封装例程。
㈢ Linux内核中shutdown系统调用
shutdown()系统调用的功能是关闭一个套接字的指定桐尺桥方向上的通信。
函数原型为:
对应的会调用内核中的函数:困睁
以ipv6为例
传输层注册的shutdown函数为tcp_shutdown:局猛
㈣ linux内核调用哪些接口分配内核地址空间的内存
kmalloc/kfree
类似于标准C中的malloc/free,kmalloc/kfree是内核中的用于常规内存分配的接口。
例如,申请1024字节的内核地址空间:
char*buff;
buff=kmalloc(1024,GFP_KERNEL);
if(!buff)
return-ENOMEM;
还有什么问题的话,可以私信我哦
㈤ 如何调用Linux内核函数
注意看这个文件
sysdeps/unix/sysv/linux/syscalls.list
里面记录着系统调用的名字和一些属性,具体我也没有研究过,不懂。
再看select的实现,很让人惊讶,一旦使用,结果就是“报错“。
int
__select (nfds, readfds, writefds, exceptfds, timeout)
int nfds;
fd_set *readfds;
fd_set *writefds;
fd_set *exceptfds;
struct timeval *timeout;
{
__set_errno (ENOSYS);
return -1;
}
libc_hidden_def (__select)
stub_warning (select)
weak_alias (__select, select)
这是因为glibc并没有实现系统调用,而是调用系统调用,
更进一步,连调用系统调用都没有一个个实现,而是使用了通用的办法,
理由很简单,所有的系统调用在linux内核头文件里都能找到,
所有的系统调用参数类型就那么几种,参数个数也是有限的,
因此没有必要针对所有的系统调用一一封装,
于是就有了这个list文件,自动生成调用系统调用的函数,
如果生成失败,也就是你看到的“报错”。
符号是有强弱的,当自动生成成功的时候,“报错”的弱符号就被忽略了。
当你在glibc中找到一个系统调用的封装源码,是以下原因,
1. 编译的目标系统不支持这个系统调用,所以自己用另一种方式实现了。
2. 这个系统调用无法使用通用的自动生成方式生成,用特化的方式覆盖。
3. 针对这个系统调用做了特别的优化。
4. 其它可能的原因。
具体可以留意
SYSCALL, PSEUDO, DO_CALL, INLINE_CALL 等名字
这两个文件是重点所在
sysdeps/unix/i386/sysdep.h
sysdeps/unix/i386/sysdep.S
要搞清楚具体的自动生成过程,恐怕得研究glibc自身的编译过程了
㈥ 如何在linux内核中调用用户空间的程序
教科书里的Linux代码例子都已作古,所以看到的代码不能当真,领会意思就行了
比如以前的init进程的启动代码
execve(init_filename,argv_init,envp_init);
现在改为
static void run_init_process(char *init_filename)
{
argv_init[0] = init_filename;
kernel_execve(init_filename, argv_init, envp_init);
}
好的,聪明人就发现,linux内核中调用用户空间的程序可以使用init这样的方式,调用 kernel_execve
不过内核还是提供了更好的辅助接口call_usermodehelper,自然最后也是调用kernel_execve
调用特定的内核函数(系统调用)是 GNU/Linux 中软件开发的原本就有的组成部分。但如果方向反过来呢,内核空间调用用户空间?确实有一些有这种特性的应用程序需要每天使用。例如,当内核找到一个设备,这时需要加载某个模块,进程如何处理?动态模块加载在内核通过 usermode-helper 进程进行。
让我们从探索 usermode-helper 应用程序编程接口(API)以及在内核中使用的例子开始。 然后,使用 API 构造一个示例应用程序,以便更好地理解其工作原理与局限。
usermode-helper API
usermode-helper API 是个很简单的 API,其选项为用户熟知。例如,要创建一个用户空间进程,通常只要设置名称为 executable,选项都为 executable,以及一组环境变量(指向 execve 主页)。创建内核进程也是一样。但由于创建内核空间进程,还需要设置一些额外选项。