2013-09-25 47 views
3

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

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内核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。

[email protected]:/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 

[email protected]:/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 
[email protected]:/data/local # 
+1

大多数(所有?)系统调用在失败时返回“-1”,并将实际结果代码存储到“errno”中。也许你的结果也变成了'errno'呢? –

+0

什么是导致错误结果的论据? – Freddie

+0

@Freddie增加了案例。 – stackoverflow

回答

6

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

但是用户程序总是使用C库作为包装来进行系统调用,并且C API应该符合API标准。也就是说,C库将检查内核空间的返回值并基于此设置errno。 (请注意,errno在用户空间中,内核不知道它。) 说,如果用户视图中的syscall foo()在失败时返回-1,并应设置errno以指示错误(ERR1表示失败1, ERR2 for failure2等),内核系统调用实现将相应地返回-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" 

莱纳斯说,他将确保没有系统调用在-1 ..返回一个值-4095作为有效的结果,所以我们可以保存测试-4095。

更新:所以我猜想它是你的C库,可以转换返回值。您的平台ABI可能会定义syscall在失败时返回{-1,-256},因此C封装程序在这种情况下将返回值设置为-1,并相应地设置errno。

+0

感谢您的输入。对不起,我不知道这是必要的。它是Android Linux Kernel 3.10.xxx。平台Nexus7 ARM EABI。我不明白的是它失败的原因。 errno根本无用,因为它将-res_int设置为errno。另外,我不明白为什么它只有在res_int为{-1,-256}时才会失败。 – stackoverflow

+0

谢谢@tristan。你知道我在哪里可以找到C封装,以便我可以把一些调试日志,并确认相同? – stackoverflow

+1

@stackoverflow我不是在Android的专家,但我发现Android的C库:https://github.com/android/platform_bionic/blob/master/libc/arch-arm/bionic/syscall.S但我可能是错的。别人可能会提供更多的细节。或者,您可以将debuginfo和source包安装到您的测试机器上,并直接进入代码。 – tristan