1

こんにちは私は私が書いたこのC関数をアセンブリコード(SPARCアーク)に変換しようとしていますが、セグメンテーション違反(コアダンプ)エラーが発生し続けます。この関数は、文字列を長い値に変換することになっています。私はそれをテストし、すべてのテストに合格したので、C関数を正しく実行したことを知っています。これが私が変換しようとしているC関数です。

long strToLong(char *str, int base )
{
  char *endptr;
  errno = 0;
  long num;
  num = strtol(str, &endptr, base);
  char holder[BUFSIZ];

  /*if *endptr isn't '\0' then strtol didn't get to the end of the string
  *so it wasn't a valid integer*/
  if(*endptr != '\0')
  {
    (void)fprintf(stderr, "\n\t""'%s'" "  is not an integer\n", str);
     return 0;
  }
  /*if errno isn't 0 then an error occured so print out an error message*/
  else if(errno != 0)
  { 
    (void)snprintf(holder, BUFSIZ,"\n\tConverting \"%s\" base \"%d\"\n caused an         ", str, base);
    perror(holder);
    return 0;
  }

  /*if no errors, then it was a valid integer so return the integer*/
  return num;
}

これが私が書いたアセンブリコードです。

.global strToULong

.section ".data"    

fmt1:    .asciz    "%s  is not an integer\n"    !ascii format

fmt2:
    .asciz    "Converting %s base %d\n"    !ascii format

.section ".text"

strToULong:
    save    %sp, -( 92 + 1028) & -8, %sp
    add    %fp, -4, %o1
    mov    %i0, %o0
    mov    %i2, %o2
    call    strtol
    nop
    mov    %o0, %l0
    ld    [%fp - 4], %l1
    ldub    [%l1], %l1
    cmp    %l1, %g0
    be    errno
    nop

    set    stdError, %o0
    ld    [%o0], %o0
    set    fmt1, %o1
    mov    %i0, %o2
    call    fprintf, 3
    nop

errno:
    mov    %l0, %i0
    set    errno, %l2
    ld    [%l2], %l2
    cmp    %l2, %g0
    be    return
    nop

    add    %fp, -1028, %o0
    mov    1024, %o1
    set    fmt2, %o2
    mov    %i0, %o3
    mov    %i1, %o4
    call    snprintf
    nop
    add    %fp, -1028, %o0
    call    perror
    nop
    mov    0, %i0

return:
    ret
    restore

プログラムをデバッグしましたが、strtol関数を呼び出すとセグメンテーション違反が発生します。何が間違っているのかよくわかりません。パラメータを正しく渡していると思いますが、それでもエラーが発生します。ああ、私のメインでは、FILE * StdError = stderrのように宣言されており、fprintfにパラメーターとしてstderrを渡します。

どんな助けでも適用されるでしょう。

4

1 に答える 1

1

いくつかの異なる問題が発生していますが、非常に簡単に修正できる問題の 1 つは、errno へのアクセス方法です。errno という名前のブランチを持つべきではありません。なぜなら、グローバル var errno もあり、混乱を招く可能性があるからです。

errno はグローバル変数であるため、errno をレジスタにロードすると、次のようになります。

    set errno, %l0    !sets %o0 to a pointer to errno
    st %g0,[%l0]      !set errno to 0

    set %i0, %o0      !move str to output
    set endptr, %01   !move endptr to output (defined above in .section ".data")
    set %i1, %o2      !move base to output

    call strtol,2     !calls strtol with given inputs
    nop

    ld  [%l0], %l1    !loads the value at errno into %l1

この例では、%l0 は errno へのポインターを保持し、%l1 は strtol を呼び出した後に errno の値を保持します。次に、次の方法でエラーを確認できます。

    cmp %l1,%g0       !compares errno to 0
    be endif
    nop

    /* if body */

endif:

    /* continued code */

これにより、いくつかの問題を乗り越えることができます。アセンブリを書いているとき、狂ったようにコメントアップすることは本当に役に立ちます。各行の後に、ローカル変数を追跡する上部のブロックがあります。組み立ては見た目ほど簡単ではないので、本当に役に立ちます。

于 2012-05-08T22:42:47.673 に答える