私のタイトルが適切かどうかわかりません:私は時々知っています(私がargv []を使いたいときに)コンパイラはスペースをアレンジする必要がありますコマンドライン引数のスタック。今私は単純なプログラムを書いて、Cコンパイラが単純なC配列をどのように扱うのか見ています(実際にはstd::array
と同じ方法で扱います)。私はManjaro Linux 64ビットを使用しています。 Cのコードは次のようになります。コンパイラがスタック上にスペースを作る理由
#include <stdio.h>
int main(){
int a[5] = {1,2,3,4,5};
//printf("%d", a[1]);
return 0;
}
アセンブリは(gcc main.c -fno-asynchronous-unwind-tables -o XD.s -S
から)出力生成:私はprintf
の文のコメントを外したときに、今
.file "main.c"
.text
.globl main
.type main, @function
main:
pushq %rbp
movq %rsp, %rbp
movl $1, -32(%rbp)
movl $2, -28(%rbp)
movl $3, -24(%rbp)
movl $4, -20(%rbp)
movl $5, -16(%rbp)
movl $0, %eax
popq %rbp
ret
.size main, .-main
.ident "GCC: (GNU) 6.3.1 20170109"
.section .note.GNU-stack,"",@progbits
を、コードは次のようになります。
.file "main.c"
.section .rodata
.LC0:
.string "%d"
.text
.globl main
.type main, @function
main:
pushq %rbp
movq %rsp, %rbp
subq $32, %rsp
movl $1, -32(%rbp)
movl $2, -28(%rbp)
movl $3, -24(%rbp)
movl $4, -20(%rbp)
movl $5, -16(%rbp)
movl -28(%rbp), %eax
movl %eax, %esi
movl $.LC0, %edi
movl $0, %eax
call printf
movl $0, %eax
leave
ret
.size main, .-main
.ident "GCC: (GNU) 6.3.1 20170109"
.section .note.GNU-stack,"",@progbits
真ん中は明らかで、ちょうどprintf
と呼んでいます。しかし、なぜコンパイラはsubq $32, %rsp
行をここに置いたのですか?なぜそれはprintf
の声明なしで、最初の例に表示されません?
最適化をオンにしないで生成されたコードを検査することは価値がありません。 – DeiDei
おそらく$ 32はASCIIの '2'を意味し、計算する代わりにこの値をハードコーディングしただけですか?どのような最適化が有効になっていますか? – Lundin
"最初の例でprintf文を使わないと、なぜ表示されませんか?" (積み重ねた)最も深い関数なので、それは必要ありません。 printfを呼び出すバージョンはスタックを保存する必要があります。これは、printf自体がそれを壊すからです。しかし、デイデイの最適化されていないコードは最適化されていないので、何かの中に何があるのかを尋ねる意味はありません – Tommylee2k