【问题标题】:Linux kernel system call returns -1 instead of {-1, -256}Linux 内核系统调用返回 -1 而不是 {-1, -256}
【发布时间】:2013-09-30 13:01:39
【问题描述】:

我是内核新手,正面临一个奇怪的问题。我编写了一个概念验证计算器系统调用,虽然它适用于大多数计算,但当 SUBTRACTION 结果介于 -1 到 -256 之间时,它会返回 -1。如果有人可以对可能发生的事情有所了解,将不胜感激。下面是系统调用代码。

 SYSCALL_DEFINE3(calc, int, a, int, b , char, op) {
  int res_int;

  switch(op) {
    case '+': res_int = a + b;
              break;
    case '-': res_int = a - b;
              break;
    case '*': res_int = a * b;
              break;
    case '/': res_int = (a*1000) / b;
              break;
  }           

  printk(KERN_INFO "KERNEL CALC RESULT : %d %c %d = %ld",a, op, b, res_int);
  return res_int;
} 

编辑: 内核版本:Android Linux Kernel 3.10.xxx。 平台:Nexus7 ARM EABI。 我不明白为什么它会失败。 errno 根本没有用,因为它将 -res_int 设置为 errno。另外,我不明白为什么只有当 res_int 为 {-1, -256} 时它才会失败。

a=1200, b=1300 op='-' => res_int=-100 是 printk 打印 -100 的示例,但在我的用户空间应用程序中,我收到 -1。

看起来当 res_int 为 {-1, -256} 时,errno 被设置为 -res_int。

root@android:/data/local # ./calc                                              
Please enter request in 'num1 oper num2' format: 
2.45 - 2.2
returned from syscall with res_int = 250
errno = 22, strerror(errno) = Invalid argument
Calculator result = 0.250000

root@android:/data/local # ./calc                                              
Please enter request in 'num1 oper num2' format: 
2.2 - 2.45
returned from syscall with res_int = -1
errno = 250, strerror(errno) = Unknown error 250
Calculator result = -0.001000
root@android:/data/local # 

【问题讨论】:

  • 大多数(全部?)系统调用在失败时返回-1,并将实际结果代码存储到errno。也许你的结果也被放入errno
  • 产生错误结果的论据是什么?
  • @Freddie 添加了示例。
  • 你的平台是什么?

标签: linux kernel system-calls


【解决方案1】:

您没有提到您的内核版本和平台,但是从内核的角度来看,系统调用通常在成功时返回零,在错误时返回负数。通常这是内核人员和应用程序开发人员之间的 ABI 约定,因此代码可以相互理解。

但是用户程序总是使用 C 库作为包装器来进行系统调用,并且 C API 应该符合 API 标准。也就是说,C 库将检查来自内核空间的返回值,并据此设置 errno。 (请注意,errno 在用户空间中,内核不知道。) 比如说,如果从用户的角度来看,系统调用 foo() 在失败时返回 -1,并且应该设置 errno 来指示错误(ERR1 表示失败 1,ERR2 表示失败 2,等等),内核系统调用实现将返回 -ERR1 或 -ERR2相应地,C 库将检查返回值是否为零,如果它是负数,它将向用户返回 -1 并将 errno 设置为 ERR1/ERR2。 希望这会有所帮助。

更新:我检查了 glibc 的 x86_64 代码,这可能有助于理解这一点:

        .text
ENTRY (syscall)
        movq %rdi, %rax         /* Syscall number -> rax.  */
        movq %rsi, %rdi         /* shift arg1 - arg5.  */
        movq %rdx, %rsi
        movq %rcx, %rdx
        movq %r8, %r10
        movq %r9, %r8
        movq 8(%rsp),%r9        /* arg6 is on the stack.  */
        syscall                 /* Do the system call.  */
        cmpq $-4095, %rax       /* Check %rax for error.  */
        jae SYSCALL_ERROR_LABEL /* Jump to error handler if error.  */
L(pseudo_end):
        ret                     /* Return to caller.  */

PSEUDO_END (syscall)
File: "sysdeps/unix/sysv/linux/x86_64/syscall.S"

Linus 说他将确保 no syscall 返回 -1 .. -4095 中的值作为有效结果,因此我们可以使用 -4095 进行保存测试。

更新:所以我是您的 c 库转换了返回值。您的平台 ABI 可以定义在失败时返回 {-1, -256} 的系统调用,因此 C 包装器在这种情况下将返回值设置为 -1 并相应地设置 errno。

【讨论】:

  • 感谢您的意见。对不起,我不知道这是需要的。它是 Android Linux 内核 3.10.xxx。平台 Nexus7 ARM EABI。我不明白为什么它会失败。 errno 根本没有用,因为它将 -res_int 设置为 errno。另外,我不明白为什么只有当 res_int 为 {-1, -256} 时它才会失败。
  • 谢谢@tristan。你知道我在哪里可以找到 C 包装器,以便我可以放置一些调试日志并进行确认吗?
  • @stackoverflow 我不是 Android 专家,但我发现了 android c lib:github.com/android/platform_bionic/blob/master/libc/arch-arm/… 但我可能是错的。其他人可能会提供更多详细信息。或者您可以将 debuginfo 和源包安装到您的测试机器并直接进入代码。
猜你喜欢
  • 2014-12-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-05
  • 2013-08-06
  • 2010-09-20
  • 1970-01-01
相关资源
最近更新 更多