4

C++ プロジェクト (GCC、Linux、主に静的ライブラリ) の大規模なセットがあり、それらの間に多くの依存関係があります。次に、これらのライブラリを使用して実行可能ファイルをコンパイルし、バイナリをフロントエンドにデプロイします。そのバイナリを識別できると非常に便利です。理想的には、次の情報をバイナリから直接取得する小さなスクリプトが必要です。

$ident binary
$binary : Product=PRODUCT_NAME;Version=0.0.1;Build=xxx;User=xxx...
$  dependency: Product=PRODUCT_NAME1;Version=0.1.1;Build=xxx;User=xxx...
$  dependency: Product=PRODUCT_NAME2;Version=1.0.1;Build=xxx;User=xxx...

したがって、バイナリ自体とそのすべての依存関係に関するすべての情報が表示されます。

現在、私たちのアプローチは次のとおりです。

  1. 各製品のコンパイル中に、Manifest.h と Manifest.cpp を生成し、Manifest.o をバイナリに挿入します。

  2. ident スクリプトはターゲット バイナリを解析し、そこに生成されたものを見つけて、この情報を出力します

ただし、このアプローチは gcc の異なるバージョンに対して常に信頼できるとは限りません。SO コミュニティに質問したいのですが、この問題を解決するためのより良いアプローチはありますか?

アドバイスをありがとう

4

3 に答える 3

5

ソース コード ( yourManifest.hおよび.cpp) にデータを格納する際の問題点の 1 つは、コンパイラに依存するリテラル データのサイズ制限です。

私の提案は、を使用することldです。これにより、任意のバイナリ データを ELF ファイルに保存できます (そうですobjcopy)。独自のソリューションを作成する場合は、 をご覧くださいlibbfd

hello.cpp通常の C++ の「Hello world」の例が含まれているとします。これで、次のメイク ファイル ( GNUmakefile)が作成されました。

hello: hello.o hello.om
    $(LINK.cpp) $^ $(LOADLIBES) $(LDLIBS) -o $@

%.om: %.manifest
    ld -b binary -o $@ $<

%.manifest:
    echo "$@" > $@

ここで行っているのは、マニフェスト (ELF オブジェクト形式への変換後) もバイナリにリンクする必要があるため、リンク段階を分離することです。私は接尾辞規則を使用しているので、これは 1 つの方法ですが、他の方法も確かに可能です。たとえば、マニフェストが最終的に.oファイルになり、GNU make がそれらを作成する方法を理解できる、マニフェストのより良い命名スキームが含まれます。ここでは、レシピについて明示しています。つまり、ファイル.omから作成されたマニフェスト (任意のバイナリ データ) である.manifestファイルがあります。レシピには、バイナリ入力を ELF オブジェクトに変換することが記載されています。それ自体を作成するためのレシピは、.manifest単純に文字列をファイルにパイプします。

明らかに、あなたの場合のトリッキーな部分は、マニフェスト データを保存することではなく、生成することです。率直に言って、私はあなたのビルド システムについてほとんど知りません.manifest

ファイルに投げ込むもの.manifestは、おそらく、あなたが言及したスクリプトによって解釈できる、またはコマンドラインスイッチを実装する場合はバイナリ自体によって出力される可能性のある構造化テキストである必要があります(通常の実行可能ファイルのように動作するようにハッキングされた.soファイルやファイルは無視してください).soシェルから実行する場合)。

上記の make ファイルは依存関係を考慮していません。つまり、依存関係リストを作成するのにまったく役立ちません。各目標 (つまり、静的ライブラリなど) に対する依存関係を明確に表現すれば、おそらく GNU make を強制してそれを支援させることができます。しかし、そのルートを取る価値はないかもしれません...

また見てください:


データ (あなたの場合はマニフェスト) から生成されたシンボルに特定の名前が必要な場合は、少し異なるルートを使用し、John Ripley が説明した方法を使用する必要があります

シンボルにアクセスするには?簡単。それらを外部 (C リンケージ!) データとして宣言してから使用します。

#include <cstdio>

extern "C" char _binary_hello_manifest_start;
extern "C" char _binary_hello_manifest_end;

int main(int argc, char** argv)
{
        const ptrdiff_t len = &_binary_hello_manifest_end - &_binary_hello_manifest_start;
        printf("Hello world: %*s\n", (int)len, &_binary_hello_manifest_start);
}

記号は正確な文字/バイトです。として宣言することもできますが、後でchar[]問題が発生する可能性があります。たとえば、printf通話の場合。

私が自分でサイズを計算している理由は、a.) バッファーがゼロで終了することが保証されているかどうかわからない、および b.)*_size変数とのインターフェースに関するドキュメントが見つからなかったからです。

補足:*フォーマット文字列の はprintf、引数から文字列の長さを読み取り、出力する文字列として次の引数を選択する必要があることを示しています。

于 2012-09-28T08:13:18.680 に答える
2

.comment出力バイナリのセクションに任意のデータを挿入できます。事後的にリンカーを使用してこれを行うことができますが、おそらく次のように C++ コードに配置する方が簡単です

 asm  (".section .comment.manifest\n\t"
       ".string \"hello, this is a comment\"\n\t"
       ".section .text");

 int main() {
   ....

この例では、asmステートメントは関数の外側にある必要があります。.textこれは、コンパイラがセクションに通常の関数を配置している限り機能するはずです。そうでない場合は、明らかな代用を行う必要があります。

リンカーは.comment.manifest、最終的なバイナリですべてのセクションを 1 つの BLOB にまとめる必要があります。これを使用して、任意.oまたは実行可能ファイルからそれらを抽出できます。

objdump -j .comment.manfest -s example.o
于 2012-09-28T08:45:53.887 に答える
0

ディストリビューションの標準パッケージング システムを使用することを考えたことがありますか? 私たちの会社には何千ものパッケージがあり、毎日何百ものパッケージが自動的に展開されています。

必要なすべての情報を含む debian パッケージを使用しています。

  • 以下を含む完全な変更ログ:
    • 著者;
    • バージョン;
    • 変更の簡単な説明とタイムスタンプ。
  • 依存情報:
    • 現在のパッケージが正しく機能するためにインストールする必要があるすべてのパッケージのリスト。
  • パッケージの環境を設定するインストール スクリプト。

準備が整ったソリューションが既に存在する場合は、独自の方法でマニフェストを作成する必要はないと思います。ここで debian パッケージの HowToを見ることができます。

于 2012-09-28T06:39:42.560 に答える