如何从用户空间访问系统调用? [英] How to access the system call from user-space?

查看:131
本文介绍了如何从用户空间访问系统调用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我阅读了LKD 1 中的一些段落 而我只是不明白下面的内容:

I read some paragraphs in LKD1 and I just cannot understand the contents below:

从用户空间访问系统调用

通常,C库为系统调用提供支持.用户应用程序可以从标准标头中提取函数原型,并与C库链接以使用您的系统调用(或使用例程调用syscall的库例程).但是,如果您只是编写了系统调用,则怀疑glibc是否已支持它!

Generally, the C library provides support for system calls. User applications can pull in function prototypes from the standard headers and link with the C library to use your system call (or the library routine that, in turn, uses your syscall call). If you just wrote the system call, however, it is doubtful that glibc already supports it!

值得庆幸的是,Linux提供了一组宏,用于包装对系统调用的访问.它设置寄存器内容并发出陷阱指令.这些宏命名为_syscalln(),其中 n 在零和六之间.该数字与传递给syscall的参数的数量相对应,因为宏需要知道期望多少个参数,并因此将其压入寄存器.例如,考虑定义为

Thankfully, Linux provides a set of macros for wrapping access to system calls. It sets up the register contents and issues the trap instructions. These macros are named _syscalln(), where n is between zero and six. The number corresponds to the number of parameters passed into the syscall because the macro needs to know how many parameters to expect and, consequently, push into registers. For example, consider the system call open(), defined as

long open(const char *filename, int flags, int mode)

在没有显式库支持的情况下使用此系统调用的syscall宏将是

The syscall macro to use this system call without explicit library support would be

#define __NR_open 5
_syscall3(long, open, const char *, filename, int, flags, int, mode)

然后,应用程序可以简单地调用open().

Then, the application can simply call open().

对于每个宏,有2 + 2×n个参数.第一个参数对应于syscall的返回类型.第二个是系统调用的名称.接下来按照系统调用的顺序跟随每个参数的类型和名称. __NR_open定义在<asm/unistd.h>中;它是系统电话号码. _syscall3宏通过内联汇编扩展为C函数;该程序集执行上一节中讨论的步骤,将系统调用号和参数推送到正确的寄存器中,并发出软件中断以捕获到内核中.使用open()系统调用只需将这个宏放在应用程序中即可.

For each macro, there are 2+2×n parameters. The first parameter corresponds to the return type of the syscall. The second is the name of the system call. Next follows the type and name for each parameter in order of the system call. The __NR_open define is in <asm/unistd.h>; it is the system call number. The _syscall3 macro expands into a C function with inline assembly; the assembly performs the steps discussed in the previous section to push the system call number and parameters into the correct registers and issue the software interrupt to trap into the kernel. Placing this macro in an application is all that is required to use the open() system call.

让我们编写宏以使用我们出色的新foo()系统调用,然后编写一些测试代码来展示我们的努力.

Let's write the macro to use our splendid new foo() system call and then write some test code to show off our efforts.

#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;
}

应用程序可以简单地调用open() 是什么意思?

此外,对于最后一段代码,foo()的声明在哪里?以及如何使这段代码可编译和可运行?我需要包含哪些头文件?

Besides, for the last piece of code, where is the declaration of foo()? And how can I make this piece of code compilable and runnable? What are the header files I need to include?

__________
1 Linux内核开发,作者:Robert Love. PDF文件位于wordpress.com (转到第81页);

__________
1 Linux Kernel Development, by Robert Love.  PDF file at wordpress.com (go to page 81); Google Books result.

推荐答案

您首先应该了解系统调用.

You first should understand what is the role of the linux kernel, and that applications interact with the kernel only thru system calls.

实际上,应用程序在内核提供的虚拟机"上运行:它在用户空间,并且只能(在最低的计算机级别)执行用户中允许的一组机器指令CPU模式由用于进行系统调用的指令(例如SYSENTERINT 0x80 ...)增强.因此,从用户级应用程序的角度来看,系统调用是原子的伪机器指令.

In effect, an application runs on the "virtual machine" provided by the kernel: it is running in the user space and can only do (at the lowest machine level) the set of machine instructions permitted in user CPU mode augmented by the instruction (e.g. SYSENTER or INT 0x80 ...) used to make system calls. So, from the user-level application point of view, a syscall is an atomic pseudo machine instruction.

Linux Assembly Howto 解释了如何在程序集(即机器)上进行系统调用指令)级别.

The Linux Assembly Howto explains how a syscall can be done at the assembly (i.e. machine instruction) level.

GNU libc 提供了与系统调用相对应的C函数.因此,例如 open 函数是在编号为NR__open的系统调用上方的小胶水(即包装纸)(正在进行系统调用,然后更新errno).应用程序通常在libc中调用此类C函数,而不是进行syscall.

The GNU libc is providing C functions corresponding to the syscalls. So for example the open function is a tiny glue (i.e. a wrapper) above the syscall of number NR__open (it is making the syscall then updating errno). Application usually call such C functions in libc instead of doing the syscall.

您可以使用其他一些libc.例如, MUSL libc 非常简单",其代码也许更易于阅读.它还将原始的系统调用包装到相应的C函数中.

You could use some other libc. For instance the MUSL libc is somhow "simpler" and its code is perhaps easier to read. It also is wrapping the raw syscalls into corresponding C functions.

如果添加自己的syscall,则最好也实现一个类似的C函数(在您自己的库中).因此,您还应该为库提供一个头文件.

If you add your own syscall, you better also implement a similar C function (in your own library). So you should have also a header file for your library.

另请参见 intro(2) syscall(2) syscalls(2)手册页,以及 VDSO在系统调用中的作用.

See also intro(2) and syscall(2) and syscalls(2) man pages, and the role of VDSO in syscalls.

请注意,系统调用不是C函数.他们不使用调用堆栈(甚至可以在没有任何堆栈的情况下调用它们).基本上,系统调用是<asm/unistd.h>中的NR__open之类的数字,是SYSENTER机器指令,约定以下约定:哪些寄存器位于syscall的参数之前,哪些寄存器位于syscall的结果之后(包括失败).结果,在包装系统调用的C库中设置errno).系统调用约定不是ABI规范中C函数的调用约定(例如 x86-64 psABI ).因此,您需要一个C包装器.

Notice that syscalls are not C functions. They don't use the call stack (they could even be invoked without any stack). A syscall is basically a number like NR__open from <asm/unistd.h>, a SYSENTER machine instruction with conventions about which registers hold before the arguments to the syscall and which ones hold after the result[s] of the syscall (including the failure result, to set errno in the C library wrapping the syscall). The conventions for syscalls are not the calling conventions for C functions in the ABI spec (e.g. x86-64 psABI). So you need a C wrapper.

这篇关于如何从用户空间访问系统调用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆