[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[OSASK 00056] edimg0j, obj2bim4d.


  こんばんは、川合です。

  自分で予定していた時期よりもかなり遅くなりましたが、edimg0jを
一般公開します。

  これは、 http://hrb.osask.jp/wiki/?q_and_a にて ざんにさん の
 2006-11-05 (日) 08:56:31 のアドバイスを反映させたものです。具体
的には、エラーチェック部分を強化しています。

  さらにobj2bim4dも一般公開します。これはbaysideさんからのアドバ
イスを反映させたもので、.objファイルのセクション数の許容数を16か
ら64へと大幅に増やし(いずれにせよ、obj2bimが理解できるセクショ
ンは .text、.data、.bssの3種類だけで、残りは無視されます)、さら
にシンボルが多重定義されてもリンク処理を続行させるためのオプショ
ンなどを追加しています。これにより、g++(+gas)で生成した.objを
リンクできる可能性が向上していると思います。

  セクション数の増加については、たぶんgasが、デバッグ情報などコ
ード生成に直接関係のないセクションを13以上つくっているらしいので
このような修正が意味を持つようです。

  またシンボルの多重定義の問題は、inline属性をもつ関数をヘッダフ
ァイルで使うと頻繁に発生してしまうと思われます。特に、

"test.hpp" :

class A {
    virtual int func(int a);
};

class B : A {
    inline int func(int a) { return a * a; }
};

のようなクラスをヘッダファイル内で定義して、class Bのオブジェク
トを作る.cppが複数あって、それをリンクするとシンボルの多重定義に
なってしまうでしょう。

・a.cppで #include "test.hpp" して、class B のオブジェクトを使う
    → a.obj内に関数funcが生成される(inline指定があってもvirtual
       であれば関数のポインタが必要になるので、コンパイラは関数の
       実体を生成する)。

・b.cppで #include "test.hpp" して、class B のオブジェクトを使う
   → b.obj内にも全く同じ理由で関数funcが生成される。コンパイラは
      あとでa.objとb.objがリンクされることなんて知りえないので、
      b.obj内にfuncを生成するのは避けられない。

・a.objとb.objをリンクすると当然ながらfuncがシンボル多重定義エラー
    になる
    →リンカにしてみれば、funcにリンクしてほしいという要求があった
      場合にどちらのfuncにリンクしていいのかが分からない。

  これを避けるにはinline指定をやめて、

"test.hpp" :

class A {
    virtual int func(int a);
};

class B : A {
    int func(int a);
};

"test.cpp" :

#include "test.cpp"
int B::func(int a)
{
    return a * a;
}

のようにすればいいことになります。しかしinline指定をしたいことは
結構あるでしょうし、よそからクラスライブラリをもらってきた場合は
inline指定が満載になっているかもしれません(ちなみにinlineと明示
されていなくても、ヘッダファイル内に関数の実体が記述されていれば
同じことが起きます。でもinlineになることを期待しないのであれば、
ヘッダファイル内に関数の実体までも書いてしまうのは、ただバイナリ
がでかくなったり実行時のキャッシュヒット率を下げるだけなのですが
・・・まあソースの可読性は上がるのかもしれませんけどね)。

  自分はvirtualなんか使わないから関係ないと思うかもしれませんが
継承すればデストラクタにはvirtual属性がつきますので(継承の意味
を考えれば当然ですが)、結局この問題はC++を使う以上、頻繁に起き
る問題でしょう。

  そんなわけで、obj2bim4dではredefineエラーを警告に変えました。
警告なのでリンク作業は続行されます。この場合funcへのリンクを要求
された場合に、どちらのfuncの実体へリンクするかは、リンカの裁量で
決めます。キャッシュヒット率を下げないようにするため、どれか一つ
だけを集中的に使うようにしています。・・・無視するのではなく警告
するようにしたのは、redefineはCやasmの通常のプログラミング下では
相変わらず重大なエラーであって、これを報告しなくなるのはobj2bim
の重大な退化であると考えたからです。

  警告になったとはいっても、実はobj2bim4dはデフォルトでは警告を
エラー扱いするため、これだけでは何も解決しません。これは未解決リ
ンクが残っているという警告に対し、「こんなの警告じゃなくてエラー
にしてmakeを止めてくれ!」という意見がたくさんあったからです。・
・・僕としては、未解決リンクがあったとしても、その未解決リンクが
必要になる状況にならないのであればとりあえず実行はできるのだし、
開発途中ではこれくらいの柔軟さがあったほうが助かるので(わざわざ
リンカを黙らせるためだけにダミー関数を作る必要がない)、やはりエ
ラーにはしません。その代わりに、警告をエラー扱いにするというモー
ドを付け、それをデフォルトで有効にしておきました。

  もちろんこのモードは変更できます。 obj2bimには stack: や map:
などいろいろなオプションがありますが、従来のこれらに加えて、
werr:0 というオフションがあります。これは警告をエラー扱いにしな
いようにさせる指定です。逆に警告をエラー扱いさせることをあえて明
示したければ、 werr:1 としてください。

  これでredefine問題はクリアできるわけですが、しかしそれでも、
redefineの警告がたくさん出るのは見苦しいものです。意図した結果な
のにわざわざ問題を指摘するかのように警告が出てしまっては、本当は
見逃してはいけない別の警告を見逃してしまう原因にもなりかねません
。ということで、redefine警告だけを全く出さないようにするオプショ
ンもつけました。 wredef:0 です。このオプションは、警告を表示させ
ないというようなものではなく、redefineは意図したものであって警告
に値しないという指定なので、これをやるなら werr:1 のままでも問題
ありません。つまり、g++で作った.objをリンクするためには、 werr:0
を指定するのではなく、 wredef:0 を指定すればいいのです。どうして
かというと、これなら未解決リンクが残っている場合にはmakeが止まっ
てくれますからね。

  baysideさんによると、セクション数とredefineをなんとかすればg++
の.objはリンクできるという話だったので、これで何とかなると思うの
ですが、実は僕は忙しくて実験できていないので、まだダメかもしれま
せん。もしうまくいかなければ指摘してください。折をみてさらに改良
します。

  edimg0jとobj2bimのダウンロードは、

    http://osask.jp/files/

からできます。

  [OSASK 00055]のnaskのバグ指摘も気になるので次はこれをなんとして
(大変そうなら後回しにして)、そのあとにOSASK ver.4.8のリリース作
業を再開したいです。

  それでは。

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

一覧(今月):     投稿順     スレッド順