复制linux内核,如何在Linux内核中实现clone(2)syscall的另一种...

How glibc handles the clone()?

普通的syscall包装器是不够的,因为要由用户空间来切换堆栈.上面的程序集文件对除syscall外在用户空间中实际需要执行的操作提供了非常有用的注释.

All the parameters of syscall in kernel are not exactly the same as clone in glibc, so how is these variation handled?

映射到syscall的C库函数是包装器函数.

例如,考虑POSIX.1 write() C库低级I / O函数和Linux write()syscall.参数与错误条件基本相同,但是错误返回值不同.如果发生错误,C库函数将返回-1,并设置errno,而Linux syscall将返回负错误代码(基本上与errno值匹配).

如果你看例如sysdeps/unix/sysv/linux/x86_64/sysdep.h,您可以看到x86-64上用于Linux的基本syscall包装器可以归结为

# define INLINE_SYSCALL(name, nr, args...) \n ({ \n unsigned long int resultvar = INTERNAL_SYSCALL (name, , nr, args); \n if (__glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (resultvar, ))) \n { \n __set_errno (INTERNAL_SYSCALL_ERRNO (resultvar, )); \n resultvar = (unsigned long int) -1; \n } \n (long int) resultvar; })

它只调用实际的系统调用,然后检查系统调用的返回值是否指示错误;如果是,则将结果更改为-1并相应地设置errno.它看起来很有趣,因为它依靠GCC扩展来使其表现为单个语句.

假设您在Linux中添加了一个新的syscall,

SYSCALL_DEFINE2(splork, unsigned long, arg1, void *, arg2);

并且,无论出于何种原因,您都希望将其公开给用户空间

int splork(void *arg2, unsigned long arg1);

没问题!您只需要提供一个最小的头文件,

#ifndef _SPLORK_H

#define _SPLORK_H

#define _GNU_SOURCE

#include

#include

#ifndef __NR_splork

#if defined(__x86_64__)

#define __NR_splork /* syscall number on x86-64 */

#else

#if defined(__i386)

#define __NR_splork /* syscall number on i386 */

#endif

#endif

#ifdef __NR_splork

#ifndef SYS_splork

#define SYS_splork __NR_splork

#endif

int splork(void *arg2, unsigned long arg1)

{

long retval;

retval = syscall(__NR_splork, (long)arg1, (void *)arg2);

if (retval < 0) {

/* Note: For backward compatibility, we might wish to use

*(__errno_location()) = -retval;

here. */

errno = -retval;

return -1;

} else

return (int)retval;

}

#else

#undef SYS_splork

int splork(void *arg2, unsigned long arg1)

{

/* Note: For backward compatibility, we might wish to use

*(__errno_location()) = ENOTSUP;

here. */

errno = ENOTSUP;

return -1;

}

#endif

#endif /* _SPLORK_H */

SYS_splork和__NR_splork是定义新系统调用的系统调用号的预处理程序宏.由于官方内核源代码和头文件中可能还没有包含系统调用号,因此上述头文件针对每种受支持的体系结构均明确声明了该号.对于不支持它的体系结构,splork()函数将始终使用errno == ENOTSUP返回-1.

但是请注意,Linux系统调用仅限于6个参数.如果您的内核功能需要更多功能,则需要将参数打包到一个结构中,将该结构的地址传递给内核,然后使用copy_from_user()将值复制到内核中的同一结构.

在所有Linux体系结构中,指针和long的大小相同(int可能小于指针),因此我建议您在此类结构中使用long或固定大小的类型将数据传递到内核或从内核传递数据.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值