これは、プラットフォームの呼び出し規約と標準ライブラリの実装方法によって異なります。
たとえば、次のプログラムを考えてみましょう。
#include <stdio.h>
int main(void)
{
printf("Hello, World\n");
return 0;
}
そしてそれをコンパイルするための次のコマンドライン:
gcc -S -std=c99 -pedantic -Wall -Werror syscall.c
gcc2.96を使用する32ビットRedHatボックス(i686)では、次のマシンコードを取得します。
1 .file "syscall.c"
2 .version "01.01"
3 gcc2_compiled .:
4 .section .rodata
5 .LC0:
6 .string "Hello、World \ n"
7.text。
8 .align 4
9 .globl main
10 .type main、@ function
11メイン:
12 pushl%ebp
13 movl%esp、%ebp
14 subl $ 8、%esp
15 subl $ 12、%esp
16 pushl $ .LC0
17printfを呼び出す
18 addl $ 16、%esp
19 movl $ 0、%eax
20休暇
21 ret
22 .Lfe1:
23 .size main、.Lfe1-main
24 .ident "GCC:(GNU)2.96 20000731(Red Hat Linux 7.2 2.96-112.7.2)"
16行目は、文字列リテラルのアドレスをスタックにプッシュしてから、printf
呼び出されます。
gcc4.1.2を使用した64ビットSLES10ボックス(x86_64)で、同じ方法でコンパイルされた同じコードを次に示します。
1 .file "syscall.c"
2 .section .rodata
3 .LC0:
4 .string "Hello、World"
5.text。
6.globlメイン
7 .type main、@ function
8メイン:
9 .LFB2:
10 pushq%rbp
11 .LCFI0:
12 movq%rsp、%rbp
13 .LCFI1:
14 movl $ .LC0、%edi
15コールプット
16 movl $ 0、%eax
17休暇
18 ret
;;
;; 追加コンテンツは含まれていません
;;
この場合、行14は、文字列リテラルのアドレスをスタックにプッシュするのではなく、レジスタ( )に書き込みます。%edi
このバージョンのgccは、型の単一の引数を渡しているので、へchar *
の呼び出しを置き換えることができることを理解するのに十分賢いことにも注意してくださいputs
。
どちらの場合も、呼び出しを行うときに新しいスタックフレームを作成しています。違いは、スタックフレームの内容です。Red Hatボックスには、文字列リテラルのアドレスが含まれます。SLES 10ボックスでは、そうではありません。