x86_64 Linux 上定义的 ioctl 系统调用的用户空间包装器在哪里?
Where is userspace wrapper for ioctl system call defined on x86_64 Linux?
我(出于好奇)一直想知道 ioctl 系统调用的用户 space 包装器是在 x86_64 Linux 上定义的。我的第一个想法是 glibc——在我的 Fedora 24 盒子上检查已安装版本的暴露符号后,我可以看到(除非我做错了)libc 将 ioctl 符号暴露为 'W',这意味着它是一个弱具有默认实现的符号。 misc/ioctl.c 的 glibc 源代码树中的默认实现似乎是一个存根,只是将 errno 设置为 ENOSYS 和 returns -1.
尽管如此,ioctl 仍然有效(显然,否则我的系统将不会非常有用)。我知道它可能是文件中某处的汇编代码,以某种方式组装和链接,从而覆盖了 glibc 公开的弱符号。我也知道应用程序完全有可能通过 glibc 系统调用包装器或直接使用程序集使用系统调用直接调用 ioctl。
也就是说,考虑到我碰巧观察到的库源代码 (libdrm) 包含标准的 ioctl header /usr/include/sys/ioctl.h,并且似乎不包含它自己的实现我可以看到的包装纸,我想知道我应该看哪里。
这是我为更深入地了解 GNU/Linux 系统的最低级别而努力的一部分。感谢您的指点,如果之前有人问过这个问题,我深表歉意,但如果有的话,我看不到任何答案。
更新:我忽略了上面提到的,但我也检查了内核映射的虚拟 vdso 库 - 我只能在其中找到以下内容:
0000000000000a00 W clock_gettime
0000000000000db0 W getcpu
0000000000000c40 W gettimeofday
0000000000000000 A LINUX_2.6
0000000000000d90 W time
0000000000000a00 T __vdso_clock_gettime
0000000000000db0 T __vdso_getcpu
0000000000000c40 T __vdso_gettimeofday
0000000000000d90 T __vdso_time
更新:关于 glibc 默认定义是一个存根,我似乎是不正确的。正如 nos 在评论中指出的那样,反汇编表明它正在执行真正的系统调用。我已经发布了一个答案来反映这一点。
正如我对原问题的评论中提到的,它确实在libc中实际定义,在我的例子中如下:
00000000000f8ce0 <ioctl>:
f8ce0: b8 10 00 00 00 mov [=10=]x10,%eax
f8ce5: 0f 05 syscall
f8ce7: 48 3d 01 f0 ff ff cmp [=10=]xfffffffffffff001,%rax
f8ced: 73 01 jae f8cf0 <ioctl+0x10>
f8cef: c3 retq
f8cf0: 48 8b 0d 71 31 2c 00 mov 0x2c3171(%rip),%rcx # 3bbe68 <_DYNAMIC+0x308>
f8cf7: f7 d8 neg %eax
f8cf9: 64 89 01 mov %eax,%fs:(%rcx)
f8cfc: 48 83 c8 ff or [=10=]xffffffffffffffff,%rax
f8d00: c3 retq
f8d01: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
f8d08: 00 00 00
f8d0b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
这里显然是在进行系统调用——正如 nos 所说,它必须是自动生成的,这就是为什么我无法在 glibc 源代码树中直接找到它的原因。
我(出于好奇)一直想知道 ioctl 系统调用的用户 space 包装器是在 x86_64 Linux 上定义的。我的第一个想法是 glibc——在我的 Fedora 24 盒子上检查已安装版本的暴露符号后,我可以看到(除非我做错了)libc 将 ioctl 符号暴露为 'W',这意味着它是一个弱具有默认实现的符号。 misc/ioctl.c 的 glibc 源代码树中的默认实现似乎是一个存根,只是将 errno 设置为 ENOSYS 和 returns -1.
尽管如此,ioctl 仍然有效(显然,否则我的系统将不会非常有用)。我知道它可能是文件中某处的汇编代码,以某种方式组装和链接,从而覆盖了 glibc 公开的弱符号。我也知道应用程序完全有可能通过 glibc 系统调用包装器或直接使用程序集使用系统调用直接调用 ioctl。
也就是说,考虑到我碰巧观察到的库源代码 (libdrm) 包含标准的 ioctl header /usr/include/sys/ioctl.h,并且似乎不包含它自己的实现我可以看到的包装纸,我想知道我应该看哪里。
这是我为更深入地了解 GNU/Linux 系统的最低级别而努力的一部分。感谢您的指点,如果之前有人问过这个问题,我深表歉意,但如果有的话,我看不到任何答案。
更新:我忽略了上面提到的,但我也检查了内核映射的虚拟 vdso 库 - 我只能在其中找到以下内容:
0000000000000a00 W clock_gettime
0000000000000db0 W getcpu
0000000000000c40 W gettimeofday
0000000000000000 A LINUX_2.6
0000000000000d90 W time
0000000000000a00 T __vdso_clock_gettime
0000000000000db0 T __vdso_getcpu
0000000000000c40 T __vdso_gettimeofday
0000000000000d90 T __vdso_time
更新:关于 glibc 默认定义是一个存根,我似乎是不正确的。正如 nos 在评论中指出的那样,反汇编表明它正在执行真正的系统调用。我已经发布了一个答案来反映这一点。
正如我对原问题的评论中提到的,它确实在libc中实际定义,在我的例子中如下:
00000000000f8ce0 <ioctl>:
f8ce0: b8 10 00 00 00 mov [=10=]x10,%eax
f8ce5: 0f 05 syscall
f8ce7: 48 3d 01 f0 ff ff cmp [=10=]xfffffffffffff001,%rax
f8ced: 73 01 jae f8cf0 <ioctl+0x10>
f8cef: c3 retq
f8cf0: 48 8b 0d 71 31 2c 00 mov 0x2c3171(%rip),%rcx # 3bbe68 <_DYNAMIC+0x308>
f8cf7: f7 d8 neg %eax
f8cf9: 64 89 01 mov %eax,%fs:(%rcx)
f8cfc: 48 83 c8 ff or [=10=]xffffffffffffffff,%rax
f8d00: c3 retq
f8d01: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
f8d08: 00 00 00
f8d0b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
这里显然是在进行系统调用——正如 nos 所说,它必须是自动生成的,这就是为什么我无法在 glibc 源代码树中直接找到它的原因。