我在LKD1中读了一些段落,但是我就是无法理解下面的内容:
从用户空间访问系统调用
通常,C库提供对系统调用的支持。用户应用程序可以从标准头文件中获取函数原型,并链接C库以使用您的系统调用(或反过来使用您的系统调用的库例程)。但是,如果您刚刚编写了系统调用,那么glibc是否已经支持它仍然存疑!
幸运的是,Linux提供了一组宏来包装对系统调用的访问。它设置寄存器内容并发出陷阱指令。这些宏命名为_syscalln()
,其中n
介于零和六之间。该数字对应传递到系统调用中的参数数量,因为宏需要知道要期望多少个参数,并相应地推入寄存器。例如,考虑定义为open()
的系统调用:
long open(const char *filename, int flags, int mode)
使用此系统调用而无需显式库支持的系统调用宏将是:
#define __NR_open 5
_syscall3(long, open, const char *, filename, int, flags, int, mode)
然后,应用程序只需调用
open()
。对于每个宏,有2 + 2×n个参数。第一个参数对应于系统调用的返回类型。第二个是系统调用的名称。接下来按照系统调用的顺序依次列出每个参数的类型和名称。
__NR_open
定义在<asm/unistd.h>
中;它是系统调用号。 _syscall3
宏扩展为具有内联汇编的C函数;汇编执行前面讨论过的步骤,将系统调用号和参数推送到正确的寄存器中并发出软件中断以陷入内核。将此宏放置在应用程序中就足以使用open()
系统调用。让我们编写宏来使用我们新的精彩
foo()
系统调用,然后编写一些测试代码来展示我们的努力。#define __NR_foo 283
__syscall0(long, foo)
int main ()
{
long stack_size;
stack_size = foo ();
printf ("The kernel stack size is %ld\n", stack_size);
return 0;
}
“the application can simply call open()
”的意思是应用程序可以简单地调用open()
函数。
此外,对于最后一段代码,foo()
的声明在哪里?我该如何使这段代码可编译和可运行?我需要包含哪些头文件?
__________
1 《Linux内核开发》,作者Robert Love。WordPress.com上的PDF文件(请前往第81页);Google图书结果。