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 回答