質問

この質問はに関連しています これです その答えと同様に。

取り組んでいるビルドでugさを発見しました。状況は、次のように見えます(Gmake形式で書かれています)。これは、SPARCおよびX86ハードウェアの32ビットメモリモデルに特に適用されます。

OBJ_SET1  := some objects
OBJ_SET2  := some objects

# note: OBJ_SET2 doesn't get this flag
${OBJ_SET1} : CCFLAGS += -PIC

${OBJ_SET1} ${OBJ_SET2} : %.o : %.cc
  ${CCC} ${CCFLAGS} -m32 -o ${@} -c ${<}

obj1.o       : ${OBJ_SET1}
obj2.o       : ${OBJ_SET2}
sharedlib.so : obj1.o obj2.o
obj1.o obj2.o sharedlib.so :
  ${LINK} ${LDFLAGS} -m32 -PIC -o ${@} ${^}

明らかに、共有オブジェクトにPICの有無にかかわらずコンパイルされたオブジェクトを混ぜることができます(これは何年も使用されています)。私はそれが良いアイデア/賢いかどうかを知るのに十分なことを私は写真について十分に知りません、そして私の推測はこの場合、それは必要ではありませんが、むしろそれが起こっているのです。ビルドの新しいものについて。

私の質問は次のとおりです。

  1. これは安全ですか
  2. それは良い考えですか
  3. 結果として潜在的な問題が発生する可能性があります
  4. すべてを写真に切り替えると、気をつけたいと思うかもしれない非自明なゴッチャがあります。
役に立ちましたか?

解決

私もこの質問を書いたことを忘れました。

最初にいくつかの説明が順調です:

  • 非PICコードは、OSによって[Most?] Modern OSのメモリ内の任意の位置にロードされる場合があります。すべてがロードされた後、テキストセグメントを修正するフェーズ(実行可能なものが終了する)を通過して、グローバル変数に正しく対処します。これをやってのけるには、テキストセグメントが書くことができなければなりません。
  • PIC実行可能ファイルデータは、OSによって1回ロードされ、複数のユーザー/プロセスで共有できます。ただし、OSがこれを行うには、テキストセグメントが読み取り専用である必要があります。つまり、修正はありません。コードはグローバルオフセットテーブル(GOT)を使用するようにコンパイルされているため、GOTに関連するグローバルに対処し、修正の必要性を軽減できます。
  • 共有オブジェクトがPICなしで構築されている場合、それは厳密に必要であるとは思わないことが強く奨励されています。 OSがテキストセグメントを修正する必要がある場合、それはマークされた読み取りワイトであるメモリにロードすることを余儀なくされます...これにより、プロセス/ユーザー間での共有が防止されます。
  • 実行可能なバイナリが構築されている / / picで、ボンネットの下で何がうまくいかないのかわかりませんが、いくつかのツールが不安定になるのを目撃しました(神秘的なクラッシュなど)。

回答:

  • PIC/非PICの混合、または実行可能ファイルでPICを使用すると、不安定性を予測して追跡するのが難しくなります。その理由についての技術的な説明はありません。
    • ... SEGFAULTS、バスエラー、スタックの破損などを含めること。
  • 共有オブジェクトの非PICは、おそらく深刻な問題を引き起こすことはありませんが、プロセスやユーザーでライブラリを何度も使用すると、より多くのRAMが使用される可能性があります。

更新(4/17)

それ以来、私はの原因を発見しました いくつか 私が以前に見たクラッシュの。説明する:

/*header.h*/
#include <map>
typedef std::map<std::string,std::string> StringMap;
StringMap asdf;

/*file1.cc*/
#include "header.h"

/*file2.cc*/
#include "header.h"

int main( int argc, char** argv ) {
  for( int ii = 0; ii < argc; ++ii ) {
    asdf[argv[ii]] = argv[ii];
  }

  return 0;
}

... それから:

$ g++ file1.cc -shared -PIC -o libblah1.so
$ g++ file1.cc -shared -PIC -o libblah2.so
$ g++ file1.cc -shared -PIC -o libblah3.so
$ g++ file1.cc -shared -PIC -o libblah4.so
$ g++ file1.cc -shared -PIC -o libblah5.so

$ g++ -zmuldefs file2.cc -Wl,-{L,R}$(pwd) -lblah{1..5} -o fdsa
#     ^^^^^^^^^
#     This is the evil that made it possible
$ args=(this is the song that never ends);
$ eval ./fdsa $(for i in {1..100}; do echo -n ${args[*]}; done)

その特定の例はクラッシュすることはないかもしれませんが、それは基本的にそのグループのコードに存在していた状況です。それであれば します クラッシュそれはおそらく破壊者にあり、通常は二重のエラーです。

何年も前に彼らが付け加えた -zmuldefs それらのビルドに、定義されたシンボルエラーを増やすことを取り除きます。コンパイラは、グローバルオブジェクトでコンストラクター/デストラクタを実行するためのコードを発します。 -zmuldefs メモリ内の同じ場所に住むように強制しますが、exeと問題のあるヘッダーを含む各ライブラリのコンストラクター/デストラクタを1回実行します。したがって、ダブルフリーです。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top