Issue
I'm recently doing some kernel coding and I found 2 unistd.h
files.
The location of the first one is /usr/include/asm/unistd.h
. The second one is from the source code of the kernel: linux/include/uapi/asm-generic/unistd.h
.
The source code's version is the same with my kernel's, but the two header files
differ from each other.
/usr/include/asm/unistd.h
(from my PC):
#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
(from the source):
#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
What's the difference? Which one should I use to indexing the sys_call_table
?
Solution
The asm-generic
one is a template version that can be used if you're developing a new architecture for the kernel. I believe you'll find that there are actually many versions of unistd.h
in the kernel source, because the ordering of system calls (and indeed system call existence) varies by architecture. Try this from the root of your kernel source hierarchy:
find . -name 'unistd*.h'
For x86 specifically, the uapi
version is generated when you build the kernel. See the Makefile
and various *.tbl
files in arch/x86/entry/syscalls/
directory. This ends up generating files:
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
(all of which are #include
d from a stub unistd.h
file).
Ultimately the creation of a linux "distro" is very architecture-specific, so it's up to the distro creator to copy the correct unistd.h
file(s) into some appropriate location within the /usr/include
hierarchy. (And of course, your libc
will also need to be compiled against the correct version in order for ordinary libc
system calls to work correctly.)
In summary, the version in /usr/include/asm
had better match your running kernel or it won't be possible to correctly generate an ad-hoc system call from a user process on your system, but you shouldn't be using that one within the kernel source hierarchy, because categorically the kernel source hierarchy never relies on user space headers. Within the kernel source, the mechanism for indexing that table is architecture-dependent because the layout and ordering of the table is itself architecture-dependent, and only architecture-specific code (the system call entry code) normally accesses the table, so only that code "needs to know" the correct indices.
Now if you're creating a new system call, you would need to go define its number in all of the unistd.h
files for all of the architectures you want it to appear in.
Answered By - Gil Hamilton