5

私はカーネル初心者で、奇妙な問題に直面しています。概念実証の電卓システムコールを作成しましたが、ほとんどの計算では問題なく動作しますが、SUBTRACTION の結果が -1 から -256 の間の場合は -1 を返します。誰かが何が起こっているのかに光を当てることができれば、それを感謝します. 以下はsyscallコードです。

 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。私が理解していないのは、なぜそれが失敗しているのかです。-res_int を errno に設定しているため、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 # 
4

1 に答える 1

8

カーネルのバージョンとプラットフォームについては言及しませんでしたが、カーネルの観点からすると、システムコールは通常、成功時にゼロを返し、エラー時に負の数を返します。一般に、これはカーネル関係者とアプリケーション開発者の間の ABI 規則であり、コードが相互に理解できるようになっています。

ただし、ユーザー プログラムは常に C ライブラリをラッパーとして使用してシステム コールを作成し、C API は API 標準に準拠する必要があります。つまり、C ライブラリはカーネル空間からの戻り値をチェックし、それに基づいて errno を設定します。(errno はユーザー空間にあり、カーネルはそれを認識していないことに注意してください。) たとえば、syscall foo() がユーザーの観点から、失敗時に -1 を返し、エラーを示すように errno を設定する必要がある場合 (失敗 1 の場合は ERR1、ERR2 failure2 など) の場合、カーネル syscall 実装はそれに応じて -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} を返す syscall を定義する場合があるため、そのような場合、C ラッパーは戻り値を -1 に設定し、それに応じて errno を設定します。

于 2013-09-25T07:14:21.837 に答える