以下のオプションは,インターフェース規約を制御するものです.これはコード生成処理において使われます.
なお,ほとんどのオプションには,肯定形式と否定形式の両方があります.-fhogeの否定形式は-fno-hogeとなります.
● -fexceptions
C++の例外処理を有効にします.詳しくはC++の回で説明します.通常,例外処理を必要としないC言語では,デフォルトでこのオプションは無効となります.ただし,C++で書かれた例外処理とリンクしている場合は,このオプションを有効にする必要があります(リスト3〜リスト5).
〔リスト3〕デフォルトでコンパイルしたアセンブラソース(test31.s)
|
.file "test31.c"
.version "01.01"
gcc2_compiled.:
.section .rodata
.LC0:
.string "%d\n"
.text
.align 4
.globl main
.type main,@function
main:
pushl %ebp
movl %esp,%ebp
subl $8,%esp
addl $-8,%esp
call test1
movl %eax,%eax
pushl %eax
pushl $.LC0
call printf
addl $16,%esp
addl $-8,%esp
call test2
movl %eax,%eax
pushl %eax
pushl $.LC0
call printf
addl $16,%esp
xorl %eax,%eax
jmp .L2
.p2align 4,,7
.L2:
movl %ebp,%esp
popl %ebp
ret
.Lfe1:
.size main,.Lfe1-main
.align 4
.globl test1
.type test1,@function
test1:
pushl %ebp
movl %esp,%ebp
movl $100,%eax
jmp .L3
.p2align 4,,7
.L3:
movl %ebp,%esp
popl %ebp
ret
.Lfe2:
.size test1,.Lfe2-test1
.align 4
.globl test2
.type test2,@function
test2:
pushl %ebp
movl %esp,%ebp
movl $200,%eax
jmp .L4
.p2align 4,,7
.L4:
movl %ebp,%esp
popl %ebp
ret
.Lfe3:
.size test2,.Lfe3-test2
.ident "GCC: (GNU) 2.95.3 20010315 (release)"
|
|
〔リスト4〕-fexceptionsオプションを付けてコンパイルしたアセンブラソース(test32.s)
|
.file "test32.c"
.version "01.01"
gcc2_compiled.:
.section .rodata
.LC0:
.string "%d\n"
.text
.align 4
.globl main
.type main,@function
main:
.LFB1:
pushl %ebp
.LCFI0:
movl %esp,%ebp
.LCFI1:
subl $8,%esp
.LCFI2:
addl $-8,%esp
call test1
movl %eax,%eax
pushl %eax
pushl $.LC0
.LCFI3:
call printf
addl $16,%esp
addl $-8,%esp
.LCFI4:
call test2
movl %eax,%eax
pushl %eax
pushl $.LC0
.LCFI5:
call printf
addl $16,%esp
xorl %eax,%eax
jmp .L2
.p2align 4,,7
.L2:
movl %ebp,%esp
popl %ebp
ret
.LFE1:
.Lfe1:
.size main,.Lfe1-main
.align 4
.globl test1
.type test1,@function
test1:
.LFB2:
pushl %ebp
.LCFI6:
movl %esp,%ebp
.LCFI7:
movl $100,%eax
jmp .L3
.p2align 4,,7
.L3:
movl %ebp,%esp
popl %ebp
ret
.LFE2:
.Lfe2:
.size test1,.Lfe2-test1
.align 4
.globl test2
.type test2,@function
test2:
.LFB3:
pushl %ebp
.LCFI8:
movl %esp,%ebp
.LCFI9:
movl $200,%eax
jmp .L4
.p2align 4,,7
.L4:
movl %ebp,%esp
popl %ebp
ret
.LFE3:
.Lfe3:
.size test2,.Lfe3-test2
.section .eh_frame,"aw",@progbits
__FRAME_BEGIN__:
.4byte .LLCIE1
.LSCIE1:
.4byte 0x0
.byte 0x1
.byte 0x0
.byte 0x1
.byte 0x7c
.byte 0x8
.byte 0xc
.byte 0x4
.byte 0x4
.byte 0x88
.byte 0x1
.align 4
.LECIE1:
.set .LLCIE1,.LECIE1-.LSCIE1
.4byte .LLFDE1
.LSFDE1:
.4byte .LSFDE1-__FRAME_BEGIN__
.4byte .LFB1
.4byte .LFE1-.LFB1
.byte 0x4
.4byte .LCFI0-.LFB1
.byte 0xe
.byte 0x8
.byte 0x85
.byte 0x2
.byte 0x4
.4byte .LCFI1-.LCFI0
.byte 0xd
.byte 0x5
.byte 0x4
.4byte .LCFI3-.LCFI1
.byte 0x2e
.byte 0x10
.byte 0x4
.4byte .LCFI4-.LCFI3
.byte 0x2e
.byte 0x0
.byte 0x4
.4byte .LCFI5-.LCFI4
.byte 0x2e
.byte 0x10
.align 4
.LEFDE1:
.set .LLFDE1,.LEFDE1-.LSFDE1
.4byte .LLFDE3
.LSFDE3:
.4byte .LSFDE3-__FRAME_BEGIN__
.4byte .LFB2
.4byte .LFE2-.LFB2
.byte 0x4
.4byte .LCFI6-.LFB2
.byte 0xe
.byte 0x8
.byte 0x85
.byte 0x2
.byte 0x4
.4byte .LCFI7-.LCFI6
.byte 0xd
.byte 0x5
.align 4
.LEFDE3:
.set .LLFDE3,.LEFDE3-.LSFDE3
.4byte .LLFDE5
.LSFDE5:
.4byte .LSFDE5-__FRAME_BEGIN__
.4byte .LFB3
.4byte .LFE3-.LFB3
.byte 0x4
.4byte .LCFI8-.LFB3
.byte 0xe
.byte 0x8
.byte 0x85
.byte 0x2
.byte 0x4
.4byte .LCFI9-.LCFI8
.byte 0xd
.byte 0x5
.align 4
.LEFDE5:
.set .LLFDE5,.LEFDE5-.LSFDE5
.ident "GCC: (GNU) 2.95.3 20010315 (release)"
|
|
〔リスト5〕Cソース(test31.c)
|
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char* argv[])
{
printf("%d\n",test1());
printf("%d\n",test2());
return 0;
}
test1()
{
return 100;
}
test2()
{
return 200;
}
|
|
このように-fexceptionsオプションを付けると,すべての関数に対してフレーム解放のための情報が生成されます.ライブラリ関数であるprintfも例外ではありません.
● -fpcc-struct-return
すべてのstruct型やunion型の値を,レジスタに入れるのではなくメモリ上に置いて返します.
メモリ効率に問題がありますが,このコードの利点は,GCCによってコンパイルされたファイルと,他のコンパイラでコンパイルされたファイルの間で相互に呼び出しが可能になるという点です.構造体をメモリ上に置いて返すための正確な規約は,ターゲットのコンフィグレーションマクロに依存します(リスト6〜リスト8).
〔リスト6〕-fno-pcc-struct-returnオプションでコンパイルしたアセンブラソース(test33.s)
|
.file "test33.c"
.version "01.01"
gcc2_compiled.:
.section .rodata
.LC0:
.string "%d\n"
.text
.align 4
.globl main
.type main,@function
main:
pushl %ebp
movl %esp,%ebp
subl $24,%esp
movl $60,-4(%ebp)
addl $-12,%esp
movl -4(%ebp),%eax
pushl %eax
call test1
addl $16,%esp
movl %eax,%eax
movl %eax,-8(%ebp)
addl $-8,%esp
movl -4(%ebp),%eax
pushl %eax
pushl $.LC0
call printf
addl $16,%esp
addl $-8,%esp
movl -8(%ebp),%eax
pushl %eax
pushl $.LC0
call printf
addl $16,%esp
xorl %eax,%eax
jmp .L2
.p2align 4,,7
.L2:
movl %ebp,%esp
popl %ebp
ret
.Lfe1:
.size main,.Lfe1-main
.align 4
.globl test1
.type test1,@function
test1:
pushl %ebp
movl %esp,%ebp
movl 8(%ebp),%edx
movl %edx,%eax
jmp .L3
.p2align 4,,7
.L3:
movl %ebp,%esp
popl %ebp
ret
.Lfe2:
.size test1,.Lfe2-test1
.ident "GCC: (GNU) 2.95.3 20010315 (release)"
|
|
〔リスト7〕-fpcc-struct-returnオプションを付けてコンパイルしたアセンブラソース(test34.s)
|
.file "test34.c"
.version "01.01"
gcc2_compiled.:
.section .rodata
.LC0:
.string "%d\n"
.text
.align 4
.globl main
.type main,@function
main:
pushl %ebp
movl %esp,%ebp
subl $24,%esp
movl $60,-4(%ebp)
leal -8(%ebp),%eax
addl $-8,%esp
movl -4(%ebp),%edx
pushl %edx
pushl %eax
call test1
addl $12,%esp
addl $-8,%esp
movl -4(%ebp),%eax
pushl %eax
pushl $.LC0
call printf
addl $16,%esp
addl $-8,%esp
movl -8(%ebp),%eax
pushl %eax
pushl $.LC0
call printf
addl $16,%esp
xorl %eax,%eax
jmp .L2
.p2align 4,,7
.L2:
movl %ebp,%esp
popl %ebp
ret
.Lfe1:
.size main,.Lfe1-main
.align 4
.globl test1
.type test1,@function
test1:
pushl %ebp
movl %esp,%ebp
movl 8(%ebp),%eax
movl 12(%ebp),%edx
movl %edx,(%eax)
jmp .L3
.L3:
movl %eax,%eax
movl %ebp,%esp
popl %ebp
ret $4
.Lfe2:
.size test1,.Lfe2-test1
.ident "GCC: (GNU) 2.95.3 20010315 (release)"
|
|
〔リスト8〕Cソース(test33.c)
|
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct tm
{
int tm_sec;
};
struct tm test1(struct tm hoge);
int main(int argc, char* argv[])
{
struct tm testtm;
struct tm testtm1;
testtm.tm_sec =60;
testtm1 = test1(testtm);
printf("%d\n",testtm.tm_sec);
printf("%d\n",testtm1.tm_sec);
return 0;
}
struct tm test1(struct tm hoge)
{
return hoge;
}
|
|
このようにtest33.s(リスト6)では関数test1から戻る際にレジスタebpにセットして戻りますが,test34.s(リスト7)ではstruct tmのサイズである4バイトのアドレスを戻しています.
もっとも,実際にこのような手法を使用するかどうか疑問です.可読性/可搬性を高めるためには使用しないほうが良いと思います.
● -freg-struct-return
struct型とunion型の値をレジスタに入れて戻す規約を使います.サイズの小さい構造体に関しては,こちらのほうが-fpcc-struct-returnよりも効率的です.-fpcc-struct-returnとその否定である-freg-struct-returnのどちらも指定しないと,GCCはこの二つの規約のうちターゲットにとって標準であるものをデフォルトとして使用します.
● -fshort-enums
enum型に対して必要となるだけのバイト数を割り当てます.
宣言のなかで示された値の最大値がintで収まる場合,そのenum型はintと等しくなります.
実際にはPC/AT互換機の規格でintが32ビットである現在は,この指定をしても意味を成しません.enum型がintであると規定されているので,それ以下の大きさにはならないのです.
enum型にintの範囲を超える値を指定した場合,enum型が8バイト長になることは可能です.その場合,プログラム中でenum型をint型であると規定してしまうとバグの元になるので注意してください.
● -fshort-double
本来はdouble型のサイズはfloat型より大きいのですが,このオプションを指定すると同一のサイズとなります(リスト9).
〔リスト9〕サイズを表示するCソース(test35.c)
|
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char* argv[])
{
double d_wk;
float f_wk;
printf("doubleのサイズは%dです\n",sizeof(d_wk));
printf("floatのサイズは%dです\n",sizeof(f_wk));
return 0;
}
|
|
プログラムを実行してサイズを表示すると,以下のようになります.
$ gcc -fshort-double test35.c
$ ./a.out
doubleのサイズは4です
floatのサイズは4です
$ gcc test35.c
$ ./a.out
doubleのサイズは8です
floatのサイズは4です
$
● -fshared-data
このオプションを指定してコンパイルした範囲では,データおよびconst指定されていない変数は,プライベートデータではなく共有データとするよう要求します.
一見使いやすいように思えますが,バグを誘発する危険度が大きいと思います.このような場合,スレッドを利用してmutexでデータを管理する方法を選択したほうが安全です.通常のGNU/Linuxではこのような共有データの使い方はできません.
● -fno-common
初期化済みでないグローバル変数をオブジェクトファイル中のbssセクションに割り当てます.
二つの異なるコンパイル単位の中でexternを使わずに同一の変数が宣言されていると,リンクする際にエラーが発生するようになるという効果があります(リスト10,リスト11).
〔リスト10〕グローバル変数が重複しているCソース(test36.c)
|
#include <stdio.h>
void test1();
void test2();
int ix;
int main(int argc, char* argv[])
{
test1();
test2();
return 0;
}
void test1()
{
printf("test1\n");
}
|
|
〔リスト11〕グローバル変数が重複しているCソース(test37.c)
|
#include <stdio.h>
int ix;
void test2()
{
printf("test2\n");
}
|
|
$ gcc -fcommon -o test36 test36.c test37.c
$ gcc -fno-common -o test36 test36.c test37.c
/tmp/ccojxEZU.o(.bss+0x0): multiple definition of `ix'
/tmp/cckUp9bG.o(.bss+0x0): first defined here
collect2: ld returned 1 exit status
$
● -fno-ident
このオプションは#ident指示子を無視します.
#ident指示子は機種によって有効に使用することが可能ですが,汎用的ではない話なので省略します.
● -fno-gnu-linker
GNU以外のリンカを使う場合に指定しますが,C++の場合はコンストラクタやデコンストラクタのリンクができなくなる恐れがあります.そのような場合には,collect2というソフトウェアを使用します.
● -finhibit-size-directive
一般的なプログラムのコンパイルには関係のない話ですが,このオプションはアセンブラの.size指示子を出力しません.関数が途中で分割されて主記憶上にロードされると問題を引き起こすことになるものは分割しません.
このオプションは,特殊なプログラムソースcrtstuff.cをコンパイルする際に使われます.これ以外では使用しません.
● -fverbose-asm
生成されるアセンブラコードをより読みやすくするために,そのアセンブラコードの中に余分なコメント情報を追加します.このオプションはコンパイラ自身をデバッグする際にしか役に立ちません.デフォルトは-fno-verbose-asmです.
● -fvolatile
ポインタを経由したメモリ参照は,すべてvolatile指定されたものとみなします.
volatile宣言されていない自動変数は,破壊される可能性があります.また最適化などで意図しないアドレスを参照するコードにされてしまった場合,それがハードウェアの入出力に関わるとき困ったことになります.
そのような状況を防止するために,このオプションが役立ちます.ただし,volatile指定すべきものは意図的にしたほうが,可読性も可搬性も高まると思います.
● -fvolatile-global
あらゆるデータ項目に対するメモリ参照はすべて暗黙にvolatile指定されたものとします.しかしstaticデータ項目をvolatile指定されたものとはみなしません.
これもやはり明示的にvolatile指定すべきだと思います.
● -fvolatile-static
staticデータに対するメモリ参照は,すべて暗黙にvolatile指定されたものとします.
● -fpic
ターゲットマシンにおいてサポートされていれば,共用ライブラリにおいて使用するのに適したposition-independent cコードを生成します.
このコードは,すべての固定アドレスにグローバルオフセットテーブルを通じてアクセスします.つまり再配置可能なコードになります.プログラムが起動するときに,ダイナミックローダがグローバルオフセットテーブルのエントリを解決します.
一般的には,ELF実行ファイルを作成する際に使用されるテクニックです.
● -fPIC
上の-fpicを指定してもマシンによってはグローバルオフセットテーブルの上限サイズが決められています.
その場合,このオプションを指定すれば回避可能です.
● -ffixed-reg
regで指定される名前のレジスタを,生成されたコード中で自動的に割り当てません(リスト12〜リスト14).
〔リスト12〕-ffixed-reg検証用Cソース(test38.c)
|
#include <stdio.h>
int main(int argc, char* argv[])
{
register a;
register b;
register c;
register d;
register e;
register f;
register g;
a = 10;
b = 20;
c = 30;
d = 40;
e = 50;
f = 60;
g = 70;
printf("test%d,%d,%d,%d,%d,%d,%d\n",a,b,c,d,e,f,g);
asm ("mov %ebx,$1000 ");
return 0;
}
|
|
〔リスト13〕-ffixed-regオプションでコンパイルしたもの(test38.s)
|
#include <stdio.h>
int main(int argc, char* argv[])
{
register a;
register b;
register c;
register d;
register e;
register f;
register g;
a = 10;
b = 20;
c = 30;
d = 40;
e = 50;
f = 60;
g = 70;
printf("test%d,%d,%d,%d,%d,%d,%d\n",a,b,c,d,e,f,g);
asm ("mov %ebx,$1000 ");
return 0;
}
|
|
〔リスト14〕オプションなしでコンパイルしたもの(オプションなしtest38.s)
|
.file "test38.c"
.version "01.01"
gcc2_compiled.:
.section .rodata
.LC0:
.string "test%d,%d,%d,%d,%d,%d,%d\n"
.text
.align 4
.globl main
.type main,@function
main:
pushl %ebp
movl %esp,%ebp
subl $28,%esp
pushl %edi
pushl %esi
pushl %ebx
movl $10,%ebx
movl $20,%esi
movl $30,%edi
movl $40,-4(%ebp)
movl $50,-8(%ebp)
movl $60,-12(%ebp)
movl $70,-16(%ebp)
movl -16(%ebp),%eax
pushl %eax
movl -12(%ebp),%eax
pushl %eax
movl -8(%ebp),%eax
pushl %eax
movl -4(%ebp),%eax
pushl %eax
pushl %edi
pushl %esi
pushl %ebx
pushl $.LC0
call printf
addl $32,%esp
#APP
mov %ebx,$1000
#NO_APP
xorl %eax,%eax
jmp .L2
.L2:
leal -40(%ebp),%esp
popl %ebx
popl %esi
popl %edi
movl %ebp,%esp
popl %ebp
ret
.Lfe1:
.size main,.Lfe1-main
.ident "GCC: (GNU) 2.95.3 20010315 (release)"
|
|
この例では以下のようなコンパイルを行いました.
$ gcc -S -ffixed-si -ffixed-di -ffixed-ax
-ffixed-bx test38.c
このようなオプションをつけた場合,si,di,ax,bxの各レジスタに値を割り当てません.
ソース中のインラインアセンブラではbxを明示的に使っているので,bxはその命令文だけで使用されています.
リスト14では,
movl $10,%ebx
movl $20,%esi
movl $30,%edi
のように値が割り当てられていますが,リスト13では,
movl $10,-4(%ebp)
movl $20,-8(%ebp)
movl $30,-12(%ebp)
のようにメモリ上に割り当てられているのがわかります.
用途としては,インラインアセンブラ中であるレジスタを独立させて使用したいときなどがあります.
● -fcall-used-reg
regで指定される名前のレジスタを,関数呼び出しで内容が破壊されてもよいレジスタとして取り扱います.
このオプションを指定してコンパイルされた関数は,指定したレジスタの待避,復元を行いません.固定的な役割をもつレジスタを指定してこのフラグを使うと,正常に動作しない恐れがあります.
● -fcall-saved-reg
regで指定される名前のレジスタを,関数呼び出しにより内容が破壊される前に退避し,呼び出し後に復元されるレジスタとして取り扱います.
やはり固定的な役割をもつレジスタを指定してこのフラグを使うと正常に動作しない恐れがあります.
● -fpack-struct
すべての構造体メンバの間を空けることなく詰めます.このオプションを使うと,生成されるコードは最適なものではなくなります.
そして,構造体メンバのオフセットはライブラリ関数の呼び出しフォーマットと一致しなくなります(リスト15〜リスト17).
〔リスト15〕-fpack-struct検証用Cソース(test39.c)
|
#include <time.h>
#include <sys/time.h>
#include <stdio.h>
struct tm_wk
{
int tm_sec; /* Seconds. [0-60] (1 leap second) */
int tm_min; /* Minutes. [0-59] */
int tm_hour; /* Hours. [0-23] */
char x;
int tm_mday; /* Day. [1-31] */
int tm_mon; /* Month. [0-11] */
int tm_year; /* Year - 1900. */
double y;
};
struct tm_wk test(struct tm_wk intm);
int main(int argc, char* argv[])
{
struct tm_wk wk;
struct tm_wk outwk;
wk.tm_sec = 10;
wk.tm_min = 20;
wk.tm_hour = 30;
wk.x = 'a';
wk.tm_mday = 40;
wk.tm_mon = 50;
wk.tm_year = 60;
wk.y = 0;
outwk = test(wk);
return 0;
}
struct tm_wk test(struct tm_wk intm)
{
struct tm_wk wk;
wk.tm_sec = 50;
return wk;
}
|
|
〔リスト16〕構造体メンバの間を詰めてコンパイルしたもの(test39_pack.s)
|
.file "test39.c"
.version "01.01"
gcc2_compiled.:
.text
.align 4
.globl main
.type main,@function
main:
pushl %ebp
movl %esp,%ebp
subl $80,%esp
pushl %edi
pushl %esi
movl $10,-36(%ebp)
movl $20,-32(%ebp)
movl $30,-28(%ebp)
movb $97,-24(%ebp)
movl $40,-23(%ebp)
movl $50,-19(%ebp)
movl $60,-15(%ebp)
movl $0,-11(%ebp)
movl $0,-7(%ebp)
leal -72(%ebp),%eax
addl $-8,%esp
addl $-36,%esp
movl %esp,%edi
leal -36(%ebp),%esi
cld
movl $8,%ecx
rep
movsl
movsb
pushl %eax
call test
addl $44,%esp
xorl %eax,%eax
jmp .L2
.p2align 4,,7
.L2:
leal -88(%ebp),%esp
popl %esi
popl %edi
movl %ebp,%esp
popl %ebp
ret
.Lfe1:
.size main,.Lfe1-main
.align 4
.globl test
.type test,@function
test:
pushl %ebp
movl %esp,%ebp
subl $48,%esp
pushl %edi
pushl %esi
movl 8(%ebp),%eax
movl $50,-36(%ebp)
movl %eax,%edi
leal -36(%ebp),%esi
cld
movl $8,%ecx
rep
movsl
movsb
jmp .L3
.L3:
movl %eax,%eax
leal -56(%ebp),%esp
popl %esi
popl %edi
movl %ebp,%esp
popl %ebp
ret $4
.Lfe2:
.size test,.Lfe2-test
.ident "GCC: (GNU) 2.95.3 20010315 (release)"
|
|
〔リスト17〕通常のコンパイルをしたもの(test39_unpack.s)
|
.file "test39.c"
.version "01.01"
gcc2_compiled.:
.text
.align 4
.globl main
.type main,@function
main:
pushl %ebp
movl %esp,%ebp
subl $80,%esp
pushl %edi
pushl %esi
movl $10,-36(%ebp)
movl $20,-32(%ebp)
movl $30,-28(%ebp)
movb $97,-24(%ebp)
movl $40,-20(%ebp)
movl $50,-16(%ebp)
movl $60,-12(%ebp)
movl $0,-8(%ebp)
movl $0,-4(%ebp)
leal -72(%ebp),%eax
addl $-8,%esp
addl $-36,%esp
movl %esp,%edi
leal -36(%ebp),%esi
cld
movl $9,%ecx
rep
movsl
pushl %eax
call test
addl $44,%esp
xorl %eax,%eax
jmp .L2
.p2align 4,,7
.L2:
leal -88(%ebp),%esp
popl %esi
popl %edi
movl %ebp,%esp
popl %ebp
ret
.Lfe1:
.size main,.Lfe1-main
.align 4
.globl test
.type test,@function
test:
pushl %ebp
movl %esp,%ebp
subl $48,%esp
pushl %edi
pushl %esi
movl 8(%ebp),%eax
movl $50,-36(%ebp)
movl %eax,%edi
leal -36(%ebp),%esi
cld
movl $9,%ecx
rep
movsl
jmp .L3
.L3:
movl %eax,%eax
leal -56(%ebp),%esp
popl %esi
popl %edi
movl %ebp,%esp
popl %ebp
ret $4
.Lfe2:
.size test,.Lfe2-test
.ident "GCC: (GNU) 2.95.3 20010315 (release)"
|
|
詰めてコンパイルしたものは,構造体の並びが以下のものに対し,
struct tm_wk
{
int tm_sec;
int tm_min;
int tm_hour;
char x;
int tm_mday;
int tm_mon;
int tm_year;
double y;
};
メモリ配置が,
movl $10,-36(%ebp)
movl $20,-32(%ebp)
movl $30,-28(%ebp)
movb $97,-24(%ebp)
movl $40,-23(%ebp)
movl $50,-19(%ebp)
movl $60,-15(%ebp)
のように構造体のバイト数そのままですが,通常は,
movl $10,-36(%ebp)
movl $20,-32(%ebp)
movl $30,-28(%ebp)
movb $97,-24(%ebp)
movl $40,-20(%ebp)
movl $50,-16(%ebp)
movl $60,-12(%ebp)
のように,4バイト境界で領域が取られます.
● -fcheck-memory-usage
このオプションは個々のメモリアクセスをチェックするための追加のコードを生成します.Checkerという不正なメモリアクセスを検出するツールがあり,このオプションで作成されたコードはそのツールに対応しています.
なお,このオプションを指定すると,メモリチェックが有効となっている関数の中では,asmキーワードや__asm__キーワードは使えません.
Checkerを使用しなければ関係ないオプションです.リスト18〜リスト20を参照するとわかりますが,生成されたコード中ではchkr_check_addrおよびchkr_set_rightへの呼び出しを行っています.
〔リスト18〕-fcheck-memory-usage検証用Cソース(test40.c)
|
test()
{
char a;
a='a';
}
|
|
〔リスト19〕メモリアクセスをチェックするための追加のコードを付加してコンパイルしたもの(test40a.s)
|
.file "test40.c"
.version "01.01"
gcc2_compiled.:
.globl chkr_set_right
.globl chkr_check_addr
.text
.align 4
.globl main
.type main,@function
main:
pushl %ebp
movl %esp,%ebp
subl $20,%esp
pushl %ebx
addl $-4,%esp
pushl $3
movl %esp,%eax
addl $-4,%esp
pushl $3
pushl $4
pushl %eax
call chkr_set_right
addl $16,%esp
pushl $4
movl %esp,%eax
addl $-4,%esp
pushl $3
pushl $4
pushl %eax
call chkr_set_right
addl $16,%esp
leal 8(%ebp),%eax
pushl %eax
movl %esp,%eax
addl $-4,%esp
pushl $3
pushl $4
pushl %eax
call chkr_set_right
addl $16,%esp
call chkr_set_right
addl $16,%esp
leal 12(%ebp),%ebx
addl $-4,%esp
pushl $3
movl %esp,%eax
addl $-4,%esp
pushl $3
pushl $4
pushl %eax
call chkr_set_right
addl $16,%esp
pushl $4
movl %esp,%eax
addl $-4,%esp
pushl $3
pushl $4
pushl %eax
call chkr_set_right
addl $16,%esp
pushl %ebx
movl %esp,%eax
addl $-4,%esp
pushl $3
pushl $4
pushl %eax
call chkr_set_right
addl $16,%esp
call chkr_set_right
addl $16,%esp
leal -4(%ebp),%ebx
addl $-4,%esp
pushl $2
movl %esp,%eax
addl $-4,%esp
pushl $3
pushl $4
pushl %eax
call chkr_set_right
addl $16,%esp
pushl $4
movl %esp,%eax
addl $-4,%esp
pushl $3
pushl $4
pushl %eax
call chkr_set_right
addl $16,%esp
pushl %ebx
movl %esp,%eax
addl $-4,%esp
pushl $3
pushl $4
pushl %eax
call chkr_set_right
addl $16,%esp
call chkr_check_addr
addl $16,%esp
movl $30,-4(%ebp)
jmp .L2
.p2align 4,,7
.L2:
movl -24(%ebp),%ebx
movl %ebp,%esp
popl %ebp
ret
.Lfe1:
.size main,.Lfe1-main
.ident "GCC: (GNU) 2.95.3 20010315 (release)"
|
|
〔リスト20〕通常のコンパイルをしたもの(test40.s)
|
.file "test40.c"
.version "01.01"
gcc2_compiled.:
.text
.align 4
.globl test
.type test,@function
test:
pushl %ebp
movl %esp,%ebp
subl $24,%esp
movb $97,-1(%ebp)
.L2:
movl %ebp,%esp
popl %ebp
ret
.Lfe1:
.size test,.Lfe1-test
.ident "GCC: (GNU) 2.95.3 20010315 (release)"
|
|
● -fprefix-function-name
このオプションは,関数名に対して生成されるシンボルに接頭語を付加します.GCCは,呼び出される関数だけでなく,定義された関数の名前にも接頭語を付加します.このオプションは上のオプションと対にして使用します.
● -finstrument-functions
このオプションは,関数の入口と出口にプロファイル用の呼び出しを生成します.
関数の中に入った直後と関数から出る直前に,次の名称のプロファイル用の関数が呼び出されます.引き数は,対象の関数のアドレスとその呼び出し箇所です.
プロトタイプは次のようになります.
void __cyg_profile_func_enter
(void *this_fn, void *call_site);
void __cyg_profile_func_exit
(void *this_fn, void *call_site);
前出のソースtest40.c(リスト18)でこのオプションを付けて生成されたコードは,リスト21のとおりです.
〔リスト21〕プロファイル用の呼び出しを付加したアセンブラソース(test41.s)
|
.file "test41.c"
.version "01.01"
gcc2_compiled.:
.globl __cyg_profile_func_enter
.globl __cyg_profile_func_exit
.text
.align 4
.globl test
.type test,@function
test:
pushl %ebp
movl %esp,%ebp
subl $24,%esp
addl $-8,%esp
movl 4(%ebp),%eax
pushl %eax
pushl $test
call __cyg_profile_func_enter
addl $16,%esp
movb $97,-1(%ebp)
.L2:
addl $-8,%esp
movl 4(%ebp),%eax
pushl %eax
pushl $test
call __cyg_profile_func_exit
addl $16,%esp
movl %eax,%eax
movl %ebp,%esp
popl %ebp
ret
.Lfe1:
.size test,.Lfe1-test
.ident "GCC: (GNU) 2.95.3 20010315 (release)"
|
|
● -fstack-check
スタックの境界を超えないようにチェックするコードを生成します.マルチスレッド環境ではこのフラグを指定すべきです.
シングルスレッド環境下では,ほとんどすべてのシステムにおいてスタックオーバフローは自動的に検出されるので,このオプションを指定する意味はありません.
● -fargument-alias
● -fargument-noalias
● -fargument-noalias-global
このオプションをユーザーが自分で使う必要はありません.
このオプションは仮引き数間,および仮引き数とグローバルデータの間の可能な関連付けを指定します.
-fargument-aliasは,引き数(仮引き数)がお互いに別名になっている可能性があること,それにグローバルデータの別名になっている可能性があることを指定します.
-fargument-noaliasは,引き数はお互いに別名になっていることはないのですが,グローバルデータの別名になっている可能性があることを指定します.
-fargument-noaliase-globalは,引き数はお互いに別名になっていないし,グローバルデータの別名にもなっていないことを指定します.
● -fleading-underscore
このオプションとその否定のオプションである-fno-leading-underscoreは,オブジェクトファイルの中でCのシンボルが表現される方法を強制的に変更します.古いアセンブリコードとのリンクをサポートします.
このオプションの指定が何をもたらすかを理解した上で使用しないと大きな混乱を招きますので,注意して使ってください.
なお,すべてのターゲットにおいて完全にサポートされているわけではありません.
前出のソースtest40.c(リスト18)でこのオプションを付けて生成されたコードは,リスト22のとおりです.
〔リスト22〕Cのシンボルが表現される方法を強制的に変更したアセンブラソース(test42.s)
|
.file "test42.c"
.version "01.01"
gcc2_compiled.:
.text
.align 4
.globl _test
.type _test,@function
_test:
pushl %ebp
movl %esp,%ebp
subl $24,%esp
movb $97,-1(%ebp)
.L2:
movl %ebp,%esp
popl %ebp
ret
.Lfe1:
.size _test,.Lfe1-_test
.ident "GCC: (GNU) 2.95.3 20010315 (release)"
|
|
このように先頭に_(アンダースコア)が付いています.
GCCのオプションの説明はこれで終わります.次に,環境変数について説明と検証を行います.
|