【问题标题】:Which header file of system call numbers is correct?哪个系统调用号的头文件是正确的?
【发布时间】:2019-04-06 22:22:37
【问题描述】:

我最近在做一些内核编码,发现了 2 个unistd.h 文件。

第一个位置是/usr/include/asm/unistd.h。第二个来自内核源代码:linux/include/uapi/asm-generic/unistd.h。 源代码的版本和我的内核一样,但是两个头文件 彼此不同。

/usr/include/asm/unistd.h(来自我的电脑):

#define __NR_read 0
#define __NR_write 1
#define __NR_open 2
#define __NR_close 3
#define __NR_stat 4
#define __NR_fstat 5
#define __NR_lstat 6
#define __NR_poll 7
#define __NR_lseek 8
#define __NR_mmap 9

linux/include/uapi/asm-generic/unistd.h(来自来源):

#define __NR_io_setup 0
__SC_COMP(__NR_io_setup, sys_io_setup, compat_sys_io_setup)
#define __NR_io_destroy 1
__SYSCALL(__NR_io_destroy, sys_io_destroy)
#define __NR_io_submit 2
__SC_COMP(__NR_io_submit, sys_io_submit, compat_sys_io_submit)
#define __NR_io_cancel 3
__SYSCALL(__NR_io_cancel, sys_io_cancel)
#define __NR_io_getevents 4
__SC_COMP(__NR_io_getevents, sys_io_getevents, compat_sys_io_getevents)

/* fs/xattr.c */
#define __NR_setxattr 5
__SYSCALL(__NR_setxattr, sys_setxattr)
#define __NR_lsetxattr 6
__SYSCALL(__NR_lsetxattr, sys_lsetxattr)
#define __NR_fsetxattr 7
__SYSCALL(__NR_fsetxattr, sys_fsetxattr)
#define __NR_getxattr 8
__SYSCALL(__NR_getxattr, sys_getxattr)
#define __NR_lgetxattr 9

有什么区别?我应该使用哪一个来索引sys_call_table

【问题讨论】:

    标签: c linux-kernel unistd.h


    【解决方案1】:

    这实际上取决于您正在寻找的架构。这从一个拱形到另一个拱形变化,通常放在arch/$ARCH 文件夹下的某个地方。对于嵌入式架构,这通常是一个硬编码表,甚至可能会因不同的变体而改变。

    对于 x86/64,此表是在构建时自动生成的,您可以在 arch/x86/Makefile 中看到

    syscall32 := $(srctree)/$(src)/syscall_32.tbl
    syscall64 := $(srctree)/$(src)/syscall_64.tbl
    ...
    $(uapi)/unistd_32.h: $(syscall32) $(syshdr)
        $(call if_changed,syshdr)
    ...
    $(uapi)/unistd_64.h: $(syscall64) $(syshdr)
        $(call if_changed,syshdr)
    

    这基本上调用了arch/x86/entry/syscalls/syscallhdr.sh脚本,它将根据您的menuconfig自动生成您的unistd_32.h/unistd_x32.h/unistd_64.h文件。

    这意味着如果您正在寻找 x86/x64 的实际系统调用表,可以在此处找到它们: arch/x86/entry/syscalls/syscall_32.tbl/arch/x86/entry/syscalls/syscall_64.tbl

    【讨论】:

      【解决方案2】:

      asm-generic 是一个模板版本,如果您正在为内核开发新架构,则可以使用它。我相信你会发现内核源代码中实际上有很多版本的unistd.h,因为系统调用的顺序(以及系统调用的存在)因架构而异。从内核源代码层次结构的根目录尝试此操作:

      find . -name 'unistd*.h'
      

      特别是对于 x86,uapi 版本是在您构建内核时生成的。查看Makefile*.tbl 目录中的各种*.tbl 文件。这最终会生成文件:

      arch/x86/include/generated/uapi/asm/unistd_64.h
      arch/x86/include/generated/uapi/asm/unistd_32.h
      arch/x86/include/generated/uapi/asm/unistd_x32.h
      

      (所有这些都是来自存根unistd.h 文件的#included)。

      最终,Linux“发行版”的创建是非常特定于体系结构的,因此发行版创建者需要将正确的unistd.h 文件复制到/usr/include 层次结构中的某个适当位置。 (当然,您的libc 还需要针对正确的版本进行编译,以便普通的libc 系统调用能够正常工作。)

      总而言之,/usr/include/asm 中的版本更好与您正在运行的内核匹配,否则将无法从您系统上的用户进程正确生成临时系统调用,但是您不应该在内核源代码层次结构中使用那个,因为绝对内核源代码层次结构从不依赖用户空间标头。在内核源代码中,索引该表的机制是依赖于体系结构的,因为表的布局和排序本身是依赖于体系结构的,只有体系结构特定的代码(系统调用入口代码)才能正常访问表,所以只有代码“需要知道”正确的索引。

      现在,如果您要创建一个新的系统调用,则需要在所有 unistd.h 文件中为您希望它出现的所有架构定义其编号。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-04-22
        • 2021-01-22
        • 2015-04-20
        • 2010-09-27
        • 1970-01-01
        • 2013-02-10
        相关资源
        最近更新 更多