Linux ioctl return 值由谁解释?
Linux ioctl return value interpreted by who?
我正在使用一个自定义内核字符设备,它的 ioctl()
有时 return 有很大的负值(大约几千,比如 -2000)。
在用户空间中,我没有从 ioctl 调用中获得这些值 return。相反,我得到一个 return 值 -1,errno
设置为内核模块 (+2000) 的取反值。
据我所知,google、__syscall_return()
是应该将负 return 值解释为错误的宏。但是,它似乎只寻找 -1 到 -125 之间的值。所以我没想到这些大的负值会被翻译。
这些 return 值是在哪里翻译的?这是预期的行为吗?
我在 Linux 2.6.35.10 和 EGLIBC 2.11.3-4+deb6u6.
翻译和移动到 errno
发生在 libc
级别。根据 http://www.makelinux.net/ldd3/chp-6-sect-1
,Gnu libc
和 μClibc
都将至少 -4095
的负数视为错误条件
请参阅 https://github.molgen.mpg.de/git-mirror/glibc/blob/85b290451e4d3ab460a57f1c5966c5827ca807ca/sysdeps/unix/sysv/linux/aarch64/ioctl.S 了解 ioctl
的 Gnu libc
实现。
所以,在 BRPocock 的帮助下,我将在这里报告我的发现。
linux 内核将对所有系统调用进行错误检查(来自 unistd.h):
#define __syscall_return(type, res) \
do { \
if ((unsigned long)(res) >= (unsigned long)(-125)) { \
errno = -(res); \
res = -1; \
} \
return (type) (res); \
} while (0)
Libc 还将对所有系统调用进行错误检查(来自 syscall.S):
.text
ENTRY (syscall)
PUSHARGS_6 /* Save register contents. */
_DOARGS_6(44) /* Load arguments. */
movl 20(%esp), %eax /* Load syscall number into %eax. */
ENTER_KERNEL /* Do the system call. */
POPARGS_6 /* Restore register contents. */
cmpl $-4095, %eax /* Check %eax for error. */
jae SYSCALL_ERROR_LABEL /* Jump to error handler if error. */
ret /* Return to caller. */
PSEUDO_END (syscall)
Glibc 给出了 4096 值的原因(来自 sysdep.h):
/* Linux uses a negative return value to indicate syscall errors,
unlike most Unices, which use the condition codes' carry flag.
Since version 2.1 the return value of a system call might be
negative even if the call succeeded. E.g., the `lseek' system call
might return a large offset. Therefore we must not anymore test
for < 0, but test for a real error by making sure the value in %eax
is a real error number. Linus said he will make sure the no syscall
returns a value in -1 .. -4095 as a valid result so we can savely
test with -4095. */
__syscall_return 似乎在新内核中丢失了,我还没有研究过。
我正在使用一个自定义内核字符设备,它的 ioctl()
有时 return 有很大的负值(大约几千,比如 -2000)。
在用户空间中,我没有从 ioctl 调用中获得这些值 return。相反,我得到一个 return 值 -1,errno
设置为内核模块 (+2000) 的取反值。
据我所知,google、__syscall_return()
是应该将负 return 值解释为错误的宏。但是,它似乎只寻找 -1 到 -125 之间的值。所以我没想到这些大的负值会被翻译。
这些 return 值是在哪里翻译的?这是预期的行为吗?
我在 Linux 2.6.35.10 和 EGLIBC 2.11.3-4+deb6u6.
翻译和移动到 errno
发生在 libc
级别。根据 http://www.makelinux.net/ldd3/chp-6-sect-1
libc
和 μClibc
都将至少 -4095
的负数视为错误条件
请参阅 https://github.molgen.mpg.de/git-mirror/glibc/blob/85b290451e4d3ab460a57f1c5966c5827ca807ca/sysdeps/unix/sysv/linux/aarch64/ioctl.S 了解 ioctl
的 Gnu libc
实现。
所以,在 BRPocock 的帮助下,我将在这里报告我的发现。
linux 内核将对所有系统调用进行错误检查(来自 unistd.h):
#define __syscall_return(type, res) \
do { \
if ((unsigned long)(res) >= (unsigned long)(-125)) { \
errno = -(res); \
res = -1; \
} \
return (type) (res); \
} while (0)
Libc 还将对所有系统调用进行错误检查(来自 syscall.S):
.text
ENTRY (syscall)
PUSHARGS_6 /* Save register contents. */
_DOARGS_6(44) /* Load arguments. */
movl 20(%esp), %eax /* Load syscall number into %eax. */
ENTER_KERNEL /* Do the system call. */
POPARGS_6 /* Restore register contents. */
cmpl $-4095, %eax /* Check %eax for error. */
jae SYSCALL_ERROR_LABEL /* Jump to error handler if error. */
ret /* Return to caller. */
PSEUDO_END (syscall)
Glibc 给出了 4096 值的原因(来自 sysdep.h):
/* Linux uses a negative return value to indicate syscall errors,
unlike most Unices, which use the condition codes' carry flag.
Since version 2.1 the return value of a system call might be
negative even if the call succeeded. E.g., the `lseek' system call
might return a large offset. Therefore we must not anymore test
for < 0, but test for a real error by making sure the value in %eax
is a real error number. Linus said he will make sure the no syscall
returns a value in -1 .. -4095 as a valid result so we can savely
test with -4095. */
__syscall_return 似乎在新内核中丢失了,我还没有研究过。