[OSASK 6690] Re: go_0020b.

  こんにちは、川合です。


FORM-Akkie さんは 2003/11/22 23:41:06 の「[OSASK 6688] FORM: Re:
 go_0020b.」で書きました:

>>  そうかなあ。>ディスクよりも時間  osaskgoに限って言えば、1MBを
>>超えるサイズは時間以上に問題だろうと思うのですが・・・。
> 大きすぎるのは確かに問題ですけど、同じ五日間かけるなら、
>数パーセントしか縮まないよりは数倍速くなる方がよいと思う
>のです。機能(?)密度もぐっと上がりますよね?

  これはまったくそのとおりです。

  こういうのは機能密度とは違う気がしますが、いいたいことはよくわ
かります。

>>  もし時間がかかって困るということなら、最後のリリース時以外には
>>いつも、bim2binのオプションに「maxdis:1k」とでも書いておいてくだ
>>さい(orgを作るときも、binを作るときも)。見違えるほど速くなりま
>>す。
> なるほど。圧縮率を下げるという方法がありましたか。実践的
>だなあ。……でもせこい気が(^^;

  はい、せこいです。でも、時間のロスだあ、と叫ぶような状況は回避
できるかと。もちろん一番いいのは、圧縮ルーチンをまともにしてさら
にmaxdis指定を活用することであります。

>>  そもそも、CやC++のstatic変数は初期値を指定しなければ初期値は全
>>て0とするのが仕様で、その意味ではCでbss領域が生成されることは普
>>通ありません(GCCとかは、参照される前に書かれるかどうかを慎重に
>>チェックして、大丈夫と分かったものだけにbss属性をあたえていた、
>>はず・・・ということで、多くのケースではうまく判定できず、dataセ
>>クションになります)。
> 私の記憶が確かなら、staticでなくてかつ初期値のないグロー
>バル変数はbss領域に入ります。すると……mallocしなくても

  その記憶は僕の持っている書類と食い違っています。残念ながら。

  ANSIのプログラミング言語C, X3.195-1989の解説(K&Rの付録)によ
ると、次のような記述があります。

---

A4.1 記憶クラス

  記憶クラスには自動的と静的(static)の二つがある。(中略)自動
的なオブジェクトはあるブロックに局所的なもので、そのブロックから
出ると捨てられてしまう。ブロックの中で宣言を行なうと、記憶クラス
が指定されていないか、あるいはauto指示子が指定されていれば自動オ
ブジェクトが創られる。(中略)
  一方、静的なオブジェクトはブロックに局所的であってもよいし、す
べてのブロックの外部にあってもよいが、いずれの場合も、その値は関
数やブロックから出たり入ったりする間も保持される。ある関数プログ
ラムを含むブロックも含めてブロックの中では、静的なオブジェクトは
キーワードstaticで宣言する。関数定義と同じレベルですべてのブロッ
クの外側で宣言されたオブジェクトは常に静的である。staticキーワー
ドを使えば、それらはある特定の翻訳ユニットに対して局所的にできる
。これで内部リンケージが与えられるわけである。明示的な記憶クラス
を省くか、あるいはキーワードexternを使うことにすれば、それらはプ
ログラム全体に対して広域的になる。これが外部リンケージである。

A8.7 初期化

  (前略)明示的に初期化されない静的なオブジェクトは、それに定数
0が代入されたかのように初期化される。明示的に初期化されない自動
オブジェクトの初期値は、不定である。(後略)

---

  以上の記述にしたがえば、グローバル変数宣言においてstaticキーワ
ードつけるかどうかは、リンケージの範囲を指定するためのもので、初
期値の振る舞いを左右するためのものではありません(staticと書いて
も書かなくても静的変数、つまり僕がいうところのstatic変数になるわ
けです)。したがって、

#include <stdio.h>

int g[100];

int main()
{
    int i, s = 0;
    for (i = 0; i < 100; i++)
        s += g[i];
    printf("%d\n", s);
    return 0;
}

の結果は、常に0でなくてはならないのです(配列にする必要はないん
ですけどね)。

  しかし、I.Tak.さんの記憶が間違っているということにはなりません
。そのコンパイラは、bssが自動で0初期化されると想定して、そのよう
なコードを出力したのかもしれないからです。

  もし時間があれば、上記プログラムのgの宣言にstaticを付けたり外
したりして、生成されるアセンブラソースを観察してみてください。

  と書きましたが、ついでなので、gcc-3.2.3ベースのMinGWで観察して
みました。

・int g[100];の場合:
    .comm _g, 400

・static int g[100];の場合:
    .lcomm _g,400

・int g[100] = { 0 };の場合:
    .globl _g
    .data
    .align 32
_g:
    .long 0
    .space 396

・static int g[100] = { 0 };の場合:
    .data
    .align 32
_g:
    .long 0
    .space 396

こうなりました。なおGOでは、初期値を一つも指定しなくてもdataセク
ションに回されて、
..globl _g
    .data
    .balign 16
_g:
    .space 400
となります。

  asの擬似命令の説明(*1)によると、.space 400は400バイトのゼロフ
ィルを意味します。不定値ではありません。また.lcommについては、
bssセクションに確保されて、ランタイムで0クリアされると明記され
ています。.commの説明には、uninitialized memoryを割り当てるとい
う説明しかなく、ゼロクリアはasとしては規定していないようです。に
もかかわらず、MinGWが.commを使うのは、win32ではゼロクリアしたメ
モリをくれることを仮定できるからなんだろうと思います。

  ちなみに今回のテストで判明したことですが、GCCはろくなチェック
をしないで全部bssに回していました。これは僕の[OSASK 6685]の記述
が間違っていたことを意味します。チェックしていたのは、lcc-win32
だったような気がします。

*1:
http://sources.redhat.com/binutils/docs-2.12/as.info/Pseudo-Ops.html#Pseudo%20Ops

>グローバル変数を使えばいいじゃねえか、ということになるわけ
>です、私の発想では(大規模なツールで乱用すると危険ですが)。
>そうするとmallocの処理が無くなったり引数が減ったりして
>うれしいかなあ。微妙ですか。でもこれだと引数が全て定数に
>なるのでlib_execcmd()が使いやすいんですよ。

  結局、これをやるには、Cで初期値不定のstatic変数を確保する新た
な文法を確立する必要がありそうです。単にmalloc減らしやlib_execcm
dの全パラメータ定数化を目指すなら、普通に静的変数を取ればいいで
すが、サイズがでかいとその分だけdataセクションの肥大化を招きます
。しかしまあ10MBだとしてもtek0で数バイトにまとまるので、これもそ
れほど問題ではないと思っているのですが・・・。


  それでは。

--
    川合 秀実(KAWAI Hidemi)
OSASK計画代表 / システム設計開発担当
E-mail:kawai !Atmark! imasy.org
Homepage http://www.imasy.org/~kawai/

ML番号でジャンプ
ML単語検索