Linux内核系统调用返回-1而不是{-1,-256} [英] Linux kernel system call returns -1 instead of {-1, -256}

查看:379
本文介绍了Linux内核系统调用返回-1而不是{-1,-256}的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm a kernel newbie and am facing a weird issue. I have written a proof-of-concept calculator syscall and while it works fine for most computations, it is returning -1 when the SUBTRACTION result is between -1 to -256. If someone can throw some light on what could be happening, would appreciate it. Below is the syscall code.

 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}时它才会失败.

Kernel version: Android Linux Kernel 3.10.xxx. Platform: Nexus7 ARM EABI. What I don't understand is why it is failing. The errno is not useful at all since it is setting -res_int to errno. Also, I don't understand why it is failing only when res_int is {-1, -256}.

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

a=1200, b=1300 op='-' => res_int=-100 is an example case where printk prints -100, but in my userspace app, I receive -1.

当res_int为{-1,-256}时,errno设置为-res_int.

It looks like when res_int is {-1, -256}, errno is being set to -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 # 

推荐答案

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

You didnt' mention your kernel version and platform but fwiw, from kernel's perspective a syscall usually returns zero on success and a negative number on error. Generally this is the ABI convention between kernel folks and application developers so the code can understand each other.

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

But user program always uses C library as a wrapper to make system calls and the C API should comply with the API standard. That is, the C library will check the return value from kernel space and set the errno based on that. (Note that errno is in user space and kernel doesn't know it.) Say, if syscall foo(), from user's view, returns -1 on failure and should set the errno to indicate the error (ERR1 for failure 1, ERR2 for failure2, etc), the kernel syscall implementation would return -ERR1 or -ERR2 accordingly and the C library would check the return value against zero and if it's negative, it will return -1 to user and also set errno to ERR1/ERR2. Hope this helps.

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

Update: I checked the x86_64 code of glibc, and this may help understand this:

        .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.

Update: so I guess it's your c library that converts the return value. You platform ABI may define that syscall returning {-1, -256} on failure so the C wrapper sets the return value to -1 in such cases and set the errno accordingly.

这篇关于Linux内核系统调用返回-1而不是{-1,-256}的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆