0

私が読んでいる本には、この関数にはローカル変数があると書かれています。また、この関数は再帰的であるため、ローカル変数を持つことが重要であるとも述べています。多分私は盲目か、ローカル変数がアセンブリでどのように機能するかを理解していませんが、それはわかりません。

.type factorial, @function
factorial:
    push %rbp               # Save old base pointer.
    mov  %rsp, %rbp         # Copy stack pointer to base pointer.
    mov  16(%rbp), %rax     # Save the argument in %rax.
    cmp  $1, %rax           # End of the factorial.
    je   end_factorial
    dec  %rax               # Decrement %rax.
    push %rax               # Push onto stack for next call to factorial.
    call factorial
    mov  16(%rbp), %rbx     # %rax has return value, so load arg into %rbx.
    imul %rbx, %rax         # Multiply that by result of last call to factorial.

end_factorial:
    # Restore stack pointer and base pointer to where they were
    # before function call.
    mov %rbp, %rsp
    pop %rbp
    ret

レジスタはローカル変数と見なすことができますか? ローカル変数はのようなもので実装されていましたsub $8, %rsp

4

2 に答える 2

2

ローカル変数は、実装を通じてではなく、セマンティクスによって定義されます。

定義

関数のすべての呼び出しがその変数に対して独自の独立した値を取得する場合、変数はlocalです。そのため、変数の値は「関数に対してローカル」であると言えます。

この動作はレジスタを使用して実現できるため、これは完全に有効な実装です。

ローカル変数の保存と復元

ただし、特定のレジスタは呼び出し側で保存されていると見なされるため、ネストされた関数を呼び出す前に値をスタックに置く必要がある場合があります。そうしないと、値が失われます。ネストされた呼び出しから元の関数に戻ると、値をスタックからレジスタに復元できます。

すでに述べたように、レジスタへのアクセスは、スタックへのアクセスよりもはるかに高速です。したがって、可能な限りメインメモリよりも優先されます。

imul 16(%rbp), %raxしかし、追加の移動操作なしでは、なぜそれができなかったのかはわかりません。結局、このimul命令ではソースオペランドをインメモリにすることができます。

于 2012-10-20T18:20:09.927 に答える
1

レジスタは、ローカル変数を配置するのに完全に有効な場所です。実際、アクセスがはるかに高速であるため、メモリよりも優先されます。http://ellcc.org/demo/でこの階乗アルゴリズムをコンパイルするために、LLVM デモ ページを変更しました。x86-64 の場合、

    .file   "/tmp/webcompile/_23578_0.c"
.text
.globl  fact
.align  16, 0x90
.type   fact,@function
fact:                                   # @fact
.cfi_startproc
# BB#0:                                 # %entry
movl    $1, %eax
cmpq    $2, %rdi
jl  .LBB0_2
.align  16, 0x90
.LBB0_1:                                # %if.end
                                     # =>This Inner Loop Header: Depth=1
imulq   %rdi, %rax
decq    %rdi
cmpq    $1, %rdi
jg  .LBB0_1
.LBB0_2:                                # %return
ret
.Ltmp0:
.size   fact, .Ltmp0-fact
.cfi_endproc

この場合、コンパイラは再帰を取り除き、レジスタのみを使用して計算を行うことに注意してください。

于 2012-10-20T18:08:33.047 に答える