コード生成規約に対するオプション

 以下のオプションは,インターフェース規約を制御するものです.これはコード生成処理において使われます.

 なお,ほとんどのオプションには,肯定形式と否定形式の両方があります.-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のオプションの説明はこれで終わります.次に,環境変数について説明と検証を行います.


NEW記事内インデックス    連載インデックスはこちら   Interfaceのトップ
クロスコンパイル環境について
◆コード生成規約に対するオプション
実行に影響を与える環境変数
プログラムにプロトタイプを追加するprotoizeについて, またプロトタイプを削除するunprotoizeについて

Copyright 2003 岸 哲夫

Copyright 1997-2024 CQ Publishing Co.,Ltd.