English
FAQ開発環境GNU開発環境
戻る進む
FAQ/開発環境

GNU開発環境


gccで漢字が使いたい。

Q)
gccでコメント等に漢字文字列を使う事は出来るのでしょうか。

A)
基本的には、漢字コードは使う事は出来ません。(勿論通る場合もあります。) が、gcc SOA96/3/28以降のバージョンでは、デフォルトでC++と同じ//による コメントを使用出来ます。これを使えば、漢字を使っても問題はないと 思われます。


GNUでのアセンブリでの開発環境について。

Q)
GNU環境で、アセンブラルーチンの作り方と、アセンブルの方法が、よく分かりません。

A)
GNU環境下のアセンブラでの開発は、コーディングルールによって大きく分けて2つの方法が考えられます。それぞれの方法を説明すると、

1) 日立アセンブラのコーディングルール
日立アセンブラでは、データの文字列表現が可能な他、ALIGNやSECTIONに関する指定は細かくできます。
このコーディングルールはこれまでSHCASMでのコードがそのまま使用できますので過去の資産が有効に活用できます。
このフォーマットで書かれたソースをアセンブルするにはIP作成用のツールやSBL6のパッケージに含まれているAWKスクリプトやGAWK.EXE(UNIX版ではawk) といったAWKプログラム、それらを起動させるバッチファイルであるGASM.BAT(UNIXの場合gasm.scr)が必要になります。これらのスクリプトで日立アセンブラの表現をGNU ASでのアセンブリコードにコンバートし、GNU asでアセンブルすることが可能になります。

2) GNUアセンブラのコーディングルール
GNU asでは、基本的なコードは全て小文字になります。これまでにGNU asでの開発を経験された方でしたらこちらの方が良いと思います。
呼び出しオプションは、gccと似て、

 as -o object source -Iinclude -Ooptimizeflag

SGIでは、

 sh-as -o object source -Iinclude -Ooptimizeflag

といったようにしてアセンブルします。オプティマイズ等の指定もgcc同様の方法で出来ます。 又、このコーディングルールで書かれたものは、gccから直接アセンブルする事も可能です。
GNU asのコーディングルールに関しては、英語ではありますがgccのパッケージに付いているinfoファイルを参照ください。
infoファイルの見方は、

 info as

で、読みたい項目の所でRETキーを押せばその項目に関する詳しい説明が出てきます。


gccでコンパイルするとgo32でエラーが出る。

Q)
SGLのサンプルプログラムをコンパイルしようとすると以下の所で止まってしまうのですが何故でしょう?
GCC、SGL共にネットから落としたもので、バージョンがSGLが2.0A、GCCが、95/10/26のものです。

> C:¥SGL¥SAMPLE¥S_2_2>make
> ld -Tsl.lnk -oformat srec -Map sl.map -e ___Start main.o polygon.o 
>   ../../lib/libsgl.a ../../lib/libgcc.a -o sl.s
> go32 version 1.12.maint1 Copyright (C) 1994 DJ Delorie
> Error:This program requires a version of go32(1.12.maint2) newer than 
>   this one.
> make.exe: *** [sl.s] Error 1

A)
主に以下の原因が考えられます。

  1. 使っているgo32.exeのバージョンが古い。

  2. Windows95のDOS窓を使っている場合には、プロパティの設定によってはこのような症状の出る可能性があります。


gcc 3/28版でSBLがコンパイル出来ない。

Q)
SGL TOOL KIT (1996/4/30) の gcc をインストールしたところ、make 時に以下のようなエラーが出ます。gccsh/ 以下を古いものに戻すとこのエラーは出ません。
ライブラリにSGL ではなく SBL を利用していますが、それが関係しているのでしょうか?

c:/gccsh/bin/../lib/libgcc.a(__main.o): In function `__do_global_dtors':
libgcc2.c(.text+0x2c): undefined reference to `__dtors'
libgcc2.c(.text+0x30): undefined reference to `__dtors_end'
c:/gccsh/bin/../lib/libgcc.a(__main.o): In function `__do_global_ctors':
libgcc2.c(.text+0x68): undefined reference to `__ctors_end'
libgcc2.c(.text+0x6c): undefined reference to `__ctors'
make.exe: *** [mltest.cof] Error 1

gcc のバージョンは、

gcc driver version cygnus-2.7-96q1 SOA-960328 executing gcc version 
cygnus-2.7-96q1

です。

A)
SBLでリンクしているリンクファイル(多分saturn.lnkという名前になっている事と思われます。)に、以下のセグメントを追加してください。


.tors  ALIGN(0x10) :
{
	___ctors = . ;
	*(.ctors)
	___ctors_end = . ;
	___dtors = . ;
	*(.dtors)
	___dtors_end = . ;
}

これは、GCCのバージョンアップに伴い、C++のコーディングが内部的にサポートされ、シンボル情報が追加されたためです。

.ctorは、C++のグローバルコンストラクタ(構築子)セクション、.dtorは、C++のグローバルデストラクタ(消滅子)セクションのことです。


gccのオプティマイズをあげても速度が上がらない。

Q)
GCCコンパイラで、最適化レベルを0にしても3にしても、プログラム(およそ40000h位)を実行した際、処理速度に全く変化がみられないようです。
どのような理由が考えられるでしょうか?
-Oを除く、その他のコンパイルオプションはサンプルと同じものを使用しています。

A)
ライブラリ依存のコードの場合、(つまりライブラリの関数が非常に多い場合) 最適化しても、速度的にもサイズ的にもあまり変化は見られないと思われます。
又、最適化されるコード以外のコードを多用していても当然の事ながら最適化の効果というものはあまり見られません。

gccで使える最適化オプションについて簡単に説明すると、

-fthread-jumps:
jump命令が既に結果の分かっている他の比較命令やブランチに飛んでいないかを調べ、比較命令のアドレスではなく、ブランチ命令のアドレスをjumpの飛び先にします。

-fdefer-pop:
スタックにPUSHの必要な関数の呼び出しが複数続けて存在する場合スタックのPOPを幾つかの関数の呼び出しを待ち、まとめて行ないます。

-fcse-follow-jumps:
jump命令の飛び先が他のパスによって通されていない場合、jump命令を追いかけて探します。

-fcse-skip-blocks:
条件つきでブロックをスキップするjump命令を追いかけます。

-fexpensive-optimizations:
実行速度を考慮した最適化を行ないます。
このオプションは主に複数の簡単な命令にまとめる類のオプティマイズオプションに影響を与えます。

-fstrength-reduce:
出来るだけループを使わないようなコードを吐き出します。

-finline:
出来る限り関数のコールをインライン化します。

-fcaller-saves:
余分な命令を削除しレジスタの使用を節約します。

-freturn-cse-after-loop:
ループオプティマイズの後、再びループから似通ったコードを取り除きます。

-fschedule-insns2:
レジスタのアロケーションを行なった後、命令の最適化を行ないます。

-fomit-frame-pointer:
フレームポインタが必要でない時、r14を普通のレジスタとして使うことを許可します。

-funroll-loops:
forループなどを開いてコード化する事を許可します。
詳細については英語ではありますが、GCCのINFOファイルにあります。場所は、

 gcc->Invoking GCC->Optimize Options

です。そちらを参照ください。


gccの吐き出すエラーリストをファイルに落す何か良い方法はありませんか?

Q)
コンパイル・エラーが発生した時など、エラー情報をリダイレクトして エディタ上でタグ・ジャンプなどに活用したいのですが、エラーをstdout ではなくstderrに出力しているようなので、ファイルに落せません。
出来れば、 エラーの出たファイル・行番号などの情報は、stdoutに出力するように 変更していただければ幸いです。

A)
確かにgccなどのUNIX環境で作成されたツール類はエラーの出力先をSTDERRに している事が多いため、DOSなどの環境ではその出力をリダイレクト出来ません。
しかし、環境変数GO32に2r1というパラメータを設定すると、STDERR、STDOUT の両出力が、STDOUTに出されますので、エラー出力をリダイレクト出来ます。
具体的には、SATURN¥GCCSH¥SETENV.BATの

 GO32=...

の部分を

 GO32=2r1

としてください。(EMMの部分はCPUが386以下の場合のみ必要になります。) 別の対策としては、gccのオプションで、

 -Wno-*

の類を使ってエラーメッセージの出力を制限する事ができます。
このオプションの詳細については、infoコマンドでGccのInvokingに関する項目を御覧ください。


変数や関数にセクションを設定したい。

Q)
gcc環境で関数や変数などに任意にSECTIONを割り当てたいのですが、どうやったらいいのでしょうか?

A)
gcc環境でSECTIONの指定は、関数又は変数単位で出来ます。(関数内のコードの一部を別セクションに置くといったことは出来ません。)
やり方を説明すると、関数や変数の宣言部を以下のようにします。

  型宣言子 シンボル __attribute__ ((section ("セクション名")));

例えば、

char stack[10000] __attribute__ ((section ("STACK")));
int  flag         __attribute__ ((section ("COMMON"))) = 10;
void ExpandData( void ) __attribute__ ((section ("Overlay")));

又、リンク時にこのセクション名が定義されていなければなりません。
リンク時のセクションの宣言については一般的に、

 SGLの場合'sl.lnk'
 SBLの場合'saturn.lnk'

というファイルに収められています。
もし新しいセクションを指定しなければならない場合、このファイルを 参考にしながら、新しいセクションを追加する必要があります。


長いコマンドをコマンドラインから入力したい。

Q)
長いコマンドをコマンドラインから入力したい。

A)
GCCはいわゆる「サブコマンドファイル」をサポートしています。

 gcc ilename ...

とすることで、GCCはコマンドラインオプションをファイルから読み込むことが出来ます。


Cの関数中でインラインアセンブラを使いたい。

Q)

A)
インライン アセンブラを"__asm__" を使用して定義する代わりに、"_asm_volatile" を使用して定義してください。
これによってインラインアセンブラをオプティマイズ、もしくは取り除いたりしないようになります。

GCC は volatile でないインラインアセンブラをオプティマイズした際に間違った結果を返すことが知られています。
また、もしインライン アセンブラのフラグメントの最後で、レジスタコンストレイント (resister constraints) を分ける二つのコロンを忘れると、 GCC は通常クラッシュします。もしインライン アセンブラにレジスターコンストレイントが無くても、必ずコロンを二つ付けるようにしてください。

GCCはインラインアセンブラセクションをファンクションの外にも置く事が出来るので、全てをアセンブラで書いたルーチンを Cソースの中に作ることが可能です。
Cの関数外でアセンブリを使う時には "volatile" キーワードはコンパイラを惑わすだけなので無視してください。

C ソースの中の関数外に書かれたインラインアセンブラはソースレベルでのデバッグは出来ません。- もし大きなサイズのアセンブリコードを 書きたい時には、アセンブリのファイルを別に作ることをお薦めします。
これによって恐らくソース レベルでのデバッグが正しく行われます。


GCC がメッセージ "garbage at end of number" を返す。

Q)
gccでコンパイル時"garbage at end of number"というエラーメッセージが出ます。
これは、どういう時に起こるのでしょうか?

A)
こんな感じの記述をされていませんか?

 "0x1800E+OFFSET"

GCCはこれを"0E+OFFSET"の部分が浮動小数表記に見えるため、浮動小数と解釈されます。
これを防ぐには、"E"と"+"の間にスペースを入れてください。


gccをつかって、除算器を使用したい。

Q)
gccでは普通、除算器を使用したコードを生成しないと聞いたのですが、どうすれば、除算器を使用したコードを生成できるのでしょうか?

A)
SH2 は39クロックで動作する並列除算器を持っています。 GCC はこの除算器を使用していません。
次に簡単に除算器を使用するためのマクロの例を二つ挙げます。

C の場合:

/*
** void Set_Hardware_Divide(int, int);
**
** Set the dividend and divisor of the hardware divide unit.
** The divider requires 37 clocks to calculate a result,
** so you want to execute some other code before retrieving the result.
*/
#define Set_Hardware_Divide(x,y) ¥
  ({ ¥ 
     int *div_unit = (int *)0xffffff00; ¥ 
     int dividend = x, divisor = y;     ¥ 
     __asm__ volatile ("mov.l %0,@(4,%2); mov.l %1,@%2" ¥ 
       : /* no output */                          ¥ 
       : "r" (dividend), "r" (divisor), "r" (div_unit)); ¥ 
  });
/*
** int Get_Hardware_Divide(void)
**
** Retrieves division result from the hardware divide unit.
** If less than 37 clocks have elapsed the CPU will be halted
** until the result is ready.
*/
#define Get_Hardware_Divide() ¥
  ({ ¥ 
    int *div_unit = (int *)0xffffff00; ¥
    int __result; ¥
    __asm__ volatile ("mov.l @(0x1c,%1),%0" ¥
      : "=r" (__result) ¥ 
      : "r" (div_unit)); ¥ 
    __result; ¥ 
  });

除算処理をするには、Set_Hardware_Divideをコールしなければなりません。
除算器が計算をしている間に、幾つかのCのコードを実行した後、Get_Hardware_Divideをコールして計算結果を入手します。
メインライン及び、割り込みプログラムの両方が除算器を使用しないように注意してください。
もしメインラインプログラムと割り込みルーチンの両方が除算器を使用すると、メインラインの除算の結果が書き換えられ、原因の特定できない非常に厄介なバグが発生します。
もし除算器をメインライン、及びインターラプトコードの両方で使用しなければならない場合は、除算器を使用しているRAR及び、RSRを割り込み処理上でセーブ&リストアする必要があります。

除算器の使用は、MACレジスタを使用するため非常に危険が伴います。

(SGLの関数内部では除算器、乗算器を使うためMACレジスタの整合性が取れなくなる可能性があります。)使用する際にはMACレジスタの 状態に十分気をつけてください。この機能を使った事による動作の不安定や暴走などについてはテクニカルサポートでは責任を負いかねます。


C++でコードを組みたい。

Q)
C++でコーディングしたいのですが。

A)
結論からいうとSATURNのプログラムにC++のコードは入れないでください。

例えば、


int main(void)
{
  cout << "hello, world";
}

上のプログラムはC++では448kにもなります。通常、C++のプログラムは以下の二つの理由によりとてつもなく大きくなります。

  1. 作成されるコードが効果的でない。
  2. 大きなライブラリを取り込んでしまう。


効率的なコーディングのテクニックは?

Q)
gccを使ってSATURNのプログラムを書く時に有効なテクニックを教えてください。

A)

1) 次のようなコードは避けましょう。

temp[index++] = a;
temp[index++] = b;
temp[index++] = c;

ANSI Cでは、ステートメントの最後で全ての変数をアップデートするよう指示しています。
そのため、作成されたコードは

"index" を各ステートメントでアップデートしています。


temp[index]   = a;
temp[index+1] = b;
temp[index+2] = c;
     index += 3;  

他の解決方法は、"index" を "register int" として特定することです。
index をレジスタライズする必要はありませんが、indexから直接実行はされません。 (ポインターを通して書き込みをしてもindexの値は書き換えられません。)

2) ローカル変数の使用
グローバル変数を使用するには時間がかかります。- SH2 は値を手に入れるために次のコードを実行しなければなりません。


mov.l L2,r1
mov.l @r1,r1

ローカル変数の使用にはグローバル変数ほど時間を要しません。
スタックリレイティブであり、パラメーターは始めの四つのレジスタr4-r7を通るためにより高速です。

3) 右にシフトを行うのならば、 unsigned int を使用する。
SH2は右への算術シフト命令を持っていません。そのため、gcc は符号付きの値を右へ算術シフトするために大きなコードを作成します。
符号無しで右へ算術シフト出来る変数を使うようにしてください。

4) 小さな関数を書く。
gccはレジスターを使いすぎると悲惨なコードを作成してしまいますので、一つの関数の中であまり多くのレジスタを使わないようにしてください。
百行を越すような大きな関数は、幾つかの小さな関数に分けるようにしてください。


ソースとアセンブリの対応表を出したい。

Q)
gccでコンパイル時にCのソースとアセンブリの対応が分かるようにしたいのですが何かいい方法はありませんか?

A)
gccに-Wa,-ahlというオプションをつけてコンパイルしてみてください。
対応の分かるリストが標準出力に出力されます。
但し、コンパイルオプションとして-gが付けられていないとソースコードが出力されません。

<< 出力の例 >>
      gcc -g -O -Wa,-ahl main.c
                         :
        19:main.c        ****       j = 0xf000;
        77 004c D10E                  mov.l   L10,r1
        78 004e 9215                  mov.w   L14,r2
        79 0050 2121                  mov.w   r2,@r1
        21:main.c        ****     } else {
        81 0052 A003                  bra     L4
        82 0054 0009                  nop
        83                    L6:
                         :

makeは、どこのものを使ったらいいの?

Q)
Make時に意味不明のエラーが出る。

A)
基本的にこちらから提供するMakefileは、GNU Make用に書かれたものです。
これを、Microsoft MakeやBoland Makeで実行しようとすると理解し難いエラーが発生する事があります。
それぞれMakeには、方言があり若干ずつ異なる場合があります。


オリジナルのライブラリを作りたい。

Q)
gcc 用のライブラリアンは無いのでしょうか。

A)
GNU環境でライブラリを作る方法は次の通りです。

オブジェクトファイルを作成する。
GNUパッケージにはいっているARコマンド(SGI環境の場合はsh-ar)を使って次のように記述します。

 AR r userlib.a userobjs.o ...

userlib.aは、デスティネーションのライブラリファイル
userobjs.oはライブラリ化したいオブジェクトファイル。
これは複数列挙できます。
このコマンドで作成したものを

 ranlib userlib.a

としてシンボル情報を活性化します。(SGI版の場合はranlibコマンドの代わりにsh-ranlibを使います。)
こうして作成されたライブラリは、他のライブラリ同様に使用することが出来ます。
又一度まとめたライブラリに新しいオブジェクトを追加したい場合、一度アーカイブを解く必要があります。アーカイブを解くには、

 ar x userlib.a

出力したオブジェクトファイルに新しいオブジェクトを加えて、以上の操作を繰り返せば新しいライブラリの完成です。


gasmってなぁに?

Q)
プログラムのmakefleで使用されている、gasm(GNUのアセンブラ?)が、こちらには無いのですが、これは提供していただけるのでしょうか?

A)
gasmは、拡張子からも分かるようにバッチファイルですのでこの場所をパスに通してやることで、gasm自体は実行できます。
ただ、このバッチファイルは同じディレクトリ内にある"awk"(オーク)と呼ばれるパターン処理言語用のスクリプトファイルを用いて、ソースファイルを加工しながらコンパイル(アセンブル)します。
PC版のawkに関しては、SGL(96/4/30)版のCD-ROM或は、技術情報フォーラムにアップされているSBLの中に含まれています。
UNIXは、システムの標準ツールですので、改めて用意する必要はありません。


"can't open blah: interrupted system call"というエラーメッセージが出る。

Q)
PCでLDを実行すると

 "can't open blah: interrupted system call"

というエラーメッセージが出る。

A)
充分なファイルディスクリプターがありません。CONFIG.SYS に FILE=30 と書き加えてください。


PC上でLDを実行しようとすると"Not enough memory" とエラーメッセージが出る。

Q)
PCでLDを実行しようとすると"1Not enough memory" とエラーメッセージが出る。

A)
DOS extender で使えるメモリーが、どの程度空いているかを見るには、

 go32

とタイプしてください。
どの程度の RAM と SWAP スペースが使用可能かが報告されます。
もし EMM386 を使用している場合には、

 EMM386 AUTO

とすることで、XMS を必要な時に EMS にコンバートし、RAM の使用可能容量を増やす事が出来ます。


リンカーの動作が遅い。

Q)
リンカーの動作が遅い。

A)
テンポラリーファイルに、RAMdisk を使用してみてください。
これによって、リンクの時間が劇的に短縮されたとの報告がたくさんあります。


オブジェクトファイルやCOFFファイルのディスアセンブルを掛けたい。

Q)
デバッガを使わずに、オブジェクトファイルやCOFFファイルの中身をディスアセンブルしたいのですが。

A)
objdump(IRIXの場合sh-objdump)というコマンドを使います。
例えば、COFFファイルをディスアセンブルしたい場合、

 objdump -d sl.cof

とすると、sl.cofのディスアアセンブルリストが表示されます。
但し、バイナリデータの場合、スタートアドレス等の情報が欠けてしまうため、ディスアセンブルする事が出来ません。
objdumpコマンドの詳細については、附属のインフォメーションファイルを御覧ください。


ライブラリファイルやCOFFファイルのシンボル情報を見たい。

Q)
ライブラリファイルや、COFFファイルなどのシンボルマップリストを表示したい。

A)
nm(IRIXの場合sh-nm)を使います。

 nm libsgl.a

などとすれば、libsgl.aのシンボルリストが表示されます。


戻る進む
FAQ開発環境GNU開発環境
Copyright SEGA ENTERPRISES, LTD,. 1997