2

一部の教科書によると、コンパイラはsub*ローカル変数にメモリを割り当てるために使用します。

たとえば、HelloWorldプログラムを作成します。

int main()
{
    puts("hello world");
    return 0;
}

これは64ビットOSのアセンブリコードにコンパイルされると思います。

    subq    $8, %rsp
    movq    $.LC0, (%rsp)
    calq    puts
    addq    $8, %rsp

subq引数に8バイトのメモリ(ポイントのサイズ)を割り当て、割り当てaddqを解除します。

しかし、入力するとgcc -S hello.c(Mac OS X 10.8ではllvm-gccを使用します)、アセンブリコードを取得します。

.section    __TEXT,__text,regular,pure_instructions
.globl  _main
.align  4, 0x90
_main:
Leh_func_begin1:
       pushq    %rbp
Ltmp0:
    movq    %rsp, %rbp
Ltmp1:
    subq    $16, %rsp
Ltmp2:
    xorb    %al, %al
    leaq    L_.str(%rip), %rcx
    movq    %rcx, %rdi
    callq   _puts
    movl    $0, -8(%rbp)
    movl    -8(%rbp), %eax
    movl    %eax, -4(%rbp)
    movl    -4(%rbp), %eax
    addq    $16, %rsp
    popq    %rbp
    ret

   .......

L_.str:
      .asciz     "hello world!"

callqなしでこれの周り。なんで?そして、その機能は何ですか?addqsubqaddq $16, %rsp

ご入力いただきありがとうございます。

4

1 に答える 1

5

にローカル変数がありませんmain()puts()その中にあるのは、文字列のアドレスである に渡されるパラメータの疑似変数だけです"hello world"

最後の逆アセンブリによると、呼び出し規約は、最初のパラメーターがスタックではなくレジスターputs()に渡されるように見えるrdiため、このパラメーターに割り当てられたスタックスペースがありません。

ただし、最適化を無効にしてプログラムをコンパイルしているため、不必要なスタック領域の割り当てと、その領域への読み書きが発生する可能性があります。

このコードはそれを示しています:

subq    $16, %rsp ; allocate some space
...
movl    $0, -8(%rbp) ; write to it
movl    -8(%rbp), %eax ; read back from it
movl    %eax, -4(%rbp) ; write to it
movl    -4(%rbp), %eax ; read back from it
addq    $16, %rsp

これらの 4 つのmov命令は、単純な 1 つのみと同等でmovl $0, %eaxあり、そのためにメモリは必要ありません。

-O2コンパイル コマンドのように最適化スイッチを追加すると、逆アセンブリでより意味のあるコードが表示されます。

また、スタック ポインターの位置合わせを維持する目的でのみ、いくつかの領域割り当てが必要になる場合があることにも注意してください。これにより、パフォーマンスが向上し、メモリ アクセスの位置合わせが正しくないという問題が回避されます (有効にすると、位置合わせが正しくないアクセスで #AC 例外が発生する可能性があります)。

上記のコードもそれを示しています。これらの 4 つのmov命令は 8 バイトのメモリしか使用しませんが、命令addsub命令はスタックを 16 ずつ拡大および縮小します。

于 2012-10-14T19:35:41.400 に答える