2012-01-06 15 views
0

共有ライブラリを使用するアプリケーションに応じて異なるメモリ管理ルーチンを使用するように、既存の共有ライブラリを変更します。C共有ライブラリ:静的変数の初期化+プロセス間のグローバル変数の可視性

2人のメモリ管理ルーチンの家族があるでしょう(今のところ):

  • 標準のmalloc、のcallocなどが

私が来たのmallocの

  • 特化したバージョンのcallocなどの機能この問題を解決する可能性のある方法で(ここではSOの一部の人々の助けを借りて)まだいくつかの灰色の領域があり、私は今まで私の提案に関するいくつかのフィードバックをしたいと思います。

    これは私が修正を実装するつもり方法です:

    1. は、malloc関数/のcallocなどの既存のコールを交換/ my_callocなどmy_mallocでこれらの新機能は、代わりにハードコーディングされた関数を呼び出した正しく割り当て関数ポインタを呼び出します名前。

    2. 標準のCメモリ管理ルーチンを指すように、共有ライブラリがmy_mallocなどで使用する関数ポインタを初期化するメカニズムを提供します。これにより、この共有ライブラリに依存するアプリケーションに下位互換性を提供することができます。同様に変更する必要があります。 C言語では、静的な変数の初期化を使用してこれを行うことができました。 - 同じ 'パターン'をC言語で使用できるかどうか不明です。

    3. 新しい冪等関数initAPI(タイプ)関数を導入しました。これは、アプリケーションによって呼び出される(起動時に)、共有ライブラリで異なるmem mgmtルーチンを使用する必要があります。 initAPI()関数はメモリmgmt func ptrsを適切な関数に代入します。例えば、関数はAPIコールがライブラリに行われた後に呼び出さないでください - - このように私はinitAPI()、または、それが呼び出されたときに呼び出すことができる人を制限することができれば

    明らかに、それが望ましいだろうメモリー管理ルーチンが変更されます。ですから、私はそれがどこで誰によって呼び出されるかを制限したいと思います。これは、C++でメソッドを非公開にすることで解決できるアクセス上の問題です.Cでこれを行う方法がわかりません。

    上記の2と3の問題は、C++では簡単に解決できますが、 C言語での問題を解決するには、C言語でこれらの問題を解決したいと思います。

    最後に、前述のように関数ポインタを正しく初期化することができると仮定します。共有ライブラリを使用して異なるプロセス間で共有することができます。関数ポインタはグローバル変数として実装されます(私はあまりにもスレッドの安全性を心配していません - ある時点でmutexロックでアクセスをラップすることも考えています)*共有ライブラリを使用する各アプリケーションはメモリ管理ルーチンを妨害すべきではありません共有ライブラリを使用する別のアプリケーションで使用されます。

    私はshlibを使ってプロセス間で共有されるコード(データではない)だと思っていますが、私はそれを確認したいと思います - 好ましくはそのアサーションをバックアップするリンクを付けてください。

    注:上記の「アーキテクチャ」の結果として今後発生する可能性のあるスレッド問題を軽視すると、誰かが私に警告してくれます!

    ところで、私は具体的な質問がないためにLinuxの(Ubuntuの)上のライブラリ

  • +0

    "これは** money ** mgmtルーチンを変更します" ...あなたはもっと気をつけてください:-) – pmg

    +0

    @pmg:Oh snap !. Freudian slip there :) –

    +0

    ちょうど説明:これはLinux固有の質問ですか? – Asaf

    答えて

    1

    -1を構築しています。テキストは長く、より冗長に書かれている可能性があり、単一の疑問符が含まれていません。あなたの問題に対処するために今

    :共有ライブラリの(あなたは「グローバル変数」と呼ぶもの)

    静的データは、プロセスごとのです。あるプロセスのグローバル変数は、別のプロセスのグローバル変数を妨げません。ミューテックスの必要はありません。

    Cでは、関数を呼び出すことができる[1]を制限することはできません。その名前を知っているか、それへのポインタを持っている人なら誰でも呼び出すことができます。 initAPI()をコードすると、呼び出された最初のライブラリ関数でない場合にプログラムを視覚的に中止する(クラッシュさせる)ことができます。あなたは図書館の作家であり、ゲームのルールを設定しており、ルールを尊重しないコーダーに対しては義務はありません。

    [1]関数をstaticで宣言することができます。つまり、同じ翻訳単位内のコードによってのみ名前で呼び出すことができます。それを指すポインタを取得することができれば誰でもポインタを介して呼び出すことができます。このような関数はライブラリから「エクスポート」されないため、このシナリオには当てはまりません。

    0

    あなたの初期化関数であることを必要とすることは十分に簡単です:

    メインスレッド
  • から呼び出さ
    • クライアントは正確に一度
    • とクライアントがオプションを提供することができることをそれを呼び出すことがパラメータごとに関数ポインタを指定する
  • 0

    異なるアプリケーションを別々のプロセスで実行する場合は、ダイナミックライブラリを使用するのが非常に簡単です。
    ライブラリは単にmalloc()とfree()を呼び出すことができ、それをオーバーライドするアプリケーションは別のライブラリを読み込むことができます。
    これは、LD_PRELOAD環境変数を使用して行うことができます。
    ライブラリがdlopen()でロードされている場合は、最初にmallocライブラリをロードしてください。

    これは基本的に、valgrindなどのmallocを置き換えるツールです。

    +0

    希望の結果を得るには、 'LD_PRELOAD'と' dlopen'のどちらも必要としません。 –

    1

    達成する本:

    メモリ管理ルーチン2つのファミリーが存在します(今のところ):

    • 標準のmalloc、のcallocなどの機能のmallocの
    • 特化したバージョン、のcallocなど

    Li上の動的ライブラリnuxはとなり、となります。ではなく、では複雑なスキームが必要です(また、LD_PRELOADまたはdlopenは@ugorenによって提案されていません)。

    mallocと友だちの特殊バージョンを提供する場合は、これらのルーチンをメイン実行可能ファイルにリンクするだけです。 Voila:あなたの既存の共有ライブラリは、そこからそれをピックアップします。は変更が必要ありません

    mallocを、 libmymalloc.so、そしてそのライブラリをの前にlibcの前に置いて、同じ結果を達成してください。

    ダイナミックローダーは最初に表示されるmallocを使用し、a.outからリストを検索し、リンクコマンドラインにリストされているのと同じ順序で他のライブラリを検索します。

    UPDATE:

    さらに反射に、私はあなたが働く提案するものとは思いません。

    はい、それます仕事(私は私のメインの実行可能ファイルにtcmallocをリンクすることにより、その機能おき日を使用します)。

    あなたの共有ライブラリ(APIを提供するもの)がmallocを "裏に"呼び出すとき、(おそらくいくつかの)malloc実装はそれを取得しますか? 最初に動的リンカーに見えるもの。 の実装をa.outにリンクすると、となり、になります。

    +0

    ほとんど真実に聞こえません。しかし、私はあなたのコメントを完全に理解しているかどうかはわかりません。カスタム関数(pallocなど)を囲む独自のバージョンのmallocなどを定義すると、リンク時に「複数の定義済みのシンボル」エラーが発生しませんか。さもなければ、これははるかに簡単な解決策です。 –

    +0

    さらに詳しく述べると、あなたが提案するものはうまくいくとは思わない。あなたは私の質問を誤解しているかもしれません。共有ライブラリは、他のアプリケーションが(期待通りに)関数を呼び出すAPIを公開します。ただし、APIの関数を呼び出すと、共有ライブラリによってメモリが割り当て/割り当て解除されます。アプリケーションは、APIコールの結果として共有ライブラリーによって「舞台裏で」行われているメモリ管理を認識していません。言い換えれば、共有libは現在、標準Cメモリ管理機能を使用するためにハードコードされています。いくつかのAPPSがメモリ管理に使用する関数を変更できるように変更したい –

    +0

    '@Homunculus Reticulli' - 関数の介在を使って、共有ライブラリ内でハードコーディングされたメモリ管理呼び出しを独自のラッパー呼び出しで置き換えることができます共有ライブラリを再コンパイルせずに機能します。これにより、アプリケーションは必要に応じてメモリ管理に使用する機能を変更できます。私はこの概念を[私の答え](http://stackoverflow.com/a/8762134/203667)で簡単に触れました。 – jschmier

    3

    私は質問がどのようなものであるか完全にはわからないので、私は使用する可能性のある情報を提供しようとします。

    あなたはと指定しましたが、あなたもGNUツールチェーンを使用していると想定するのはおそらく安全です。


    GCCは実行がmain()に入る前に自動的に呼び出される関数を起こしコンストラクタfunction attributeを提供します。これを使用して、ライブラリ初期化ルーチンinitAPI()が呼び出されたときの制御を向上させることができます。ライブラリが実行時にロードされるか、ライブラリがロード時にロードされている場合main()前に開始された場合、ライブラリ初期化の場合

    void __attribute__ ((constructor)) initAPI(void); 
    

    は、コンストラクタルーチンは dlopen()戻る前に実行されます。


    GNUリンカを使用すると、システム機能のためのラッパーを提供することを可能にする--wrap <symbol>オプションがあります。 __real_malloc()

    あなたは--wrap mallocとリンクする場合は、malloc()への参照は(あなたが実装している)​​にリダイレクトされます、との言及は、元malloc()にリダイレクトされます(ので、あなたのラッパー実装内から呼び出すことができます)。

    代わりに元malloc()への参照を提供するために、--wrap mallocオプションを使用してのあなたはまた、動的dlsym()を使用して、元のmalloc()へのポインタを読み込むことができます。元のmalloc()をラッパーから直接呼び出すことはできません。ラッパー自体への再帰呼び出しとして解釈されるからです。

    #define _GNU_SOURCE 
    #include <stdio.h> 
    #include <stdint.h> 
    #include <dlfcn.h> 
    
    void * malloc(size_t size) { 
        static void * (*func)(size_t) = NULL; 
        void * ret; 
    
        if (!func) { 
         /* get reference to original (libc provided) malloc */ 
         func = (void *(*)(size_t)) dlsym(RTLD_NEXT, "malloc"); 
        } 
    
        /* code to execute before calling malloc */ 
        ... 
    
        /* call original malloc */ 
        ret = func(size); 
    
        /* code to execute after calling malloc */ 
        ... 
    
        return ret; 
    }

    私は自分自身のラッパー関数の呼び出しと動的ライブラリ内の関数への呼び出しを交換に関する追加情報についてはTutorial: Function Interposition in Linux題しJay Conrod'sブログの記事を読んでお勧めします。

    関連する問題