当前位置: 首页 > 面试题库 >

如何从用户空间访问系统调用?

蔚承天
2023-03-14
问题内容

我阅读了LKD 1中的一些段落,但 我无法理解以下内容:

从用户空间访问系统调用

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

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

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

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

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

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

对于每个宏,都有2 +
2×n个参数。第一个参数对应于syscall的返回类型。第二个是系统调用的名称。接下来按照系统调用的顺序跟随每个参数的类型和名称。的__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;
}

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

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

1 Linux内核开发 ,作者:Robert Love。
在wordpress.com上的PDF文件(转到第81页);
Google图书的结果。


问题答案:

首先,您应该了解linux内核的作用,并且应用程序
通过系统调用 才能 与内核交互。

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

在Linux的大会HOWTO解释了如何一个系统调用可以在组件(即机器指令)的水平来完成。

的GNU库被提供对应于所述系统调用的C函数。因此,例如,开放函数是数字syscall上方的一小块胶水(即包装纸)NR__open(它使syscall然后更新errno)。应用程序通常在libc中调用此类C函数,而不是进行syscall。

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

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

另请参见intro(2)和syscall(2)和syscalls(2)手册页,以及VDSO在syscalls中的作用。

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



 类似资料:
  • 问题内容: Linux内核内部用户内存和内核内存的区别是什么 (就给内核空间提供安全性而言)? 我可以从用户空间在内核地址空间中写入什么不同的方式? 我知道的一种方法是通过系统调用 。我们可以使用多个系统调用,但最后它们都是系统调用。即使在系统调用中,我们也将数据发送到内核空间,在此它(驱动程序或相应的模块)调用诸如copy_from_user()之类的函数将数据从用户空间复制到内核空间。在这里,

  • 问题内容: 在运行Linux的基于ARM的系统上,我有一个将内存映射到物理地址的设备。从所有地址都是虚拟的用户空间程序中,如何从该地址读取内容? 问题答案: 您可以使用系统调用将设备文件映射到用户进程内存。通常,设备文件是物理内存到文件系统的映射。否则,您必须编写一个内核模块来创建此类文件或提供一种将所需内存映射到用户进程的方法。 另一种方法是将/ dev / mem的部分重新映射到用户内存。 编

  • Ceph v0.55 及后续版本默认开启了 cephx 认证。从用户空间( FUSE )挂载一 Ceph 文件系统前,确保客户端主机有一份 Ceph 配置副本、和具备 Ceph 元数据服务器能力的密钥环。 在客户端主机上,把监视器主机上的 Ceph 配置文件拷贝到 /etc/ceph/ 目录下。 sudo mkdir -p /etc/ceph sudo scp {user}@{server-mac

  • 目标是为每个行添加具有修改时间的列。 鉴于 预期的 我写了一个函数来获取修改时间 修改时间:长=1580708401253 ...但它在查询中不起作用 组织。阿帕奇。火花SparkException:作业因阶段失败而中止:阶段54.0中的任务0失败4次,最近的失败:阶段54.0中的任务0.3丢失(TID 408,srs-hdp-s1.dev.kontur.ru,executor 3):org。阿帕

  • 你可以访问用户空间目标变量,所用的语法与第3.3节第二部分,“目标变量”中访问内核空间的语法相同。在Linux中,用户代码和内核代码使用的地址空间是隔绝的。不过SystemTap可以在使用->运算符时找到恰当的地址空间。 对于指向基本类型(如整数和字符串)的指针,可以使用下列的函数访问用户空间的数据。每个函数的第一个参数都是指向数据的指针(address)。 user_char(address)

  • 我跟随谷歌登录Android系统。现在我可以得到idToken,但我之前使用的后端服务器正期待访问令牌,因为我之前使用谷歌登录。现在我不想改变我的服务器端。但是我仍然如何使用谷歌登录并在我的Android应用程序中获得访问令牌,以便我可以验证我的用户到我的后端服务器。 我以前使用Google Play服务7.5.0,现在使用Google Play服务最新版本8.3.0。