組み込みシステムで使用される動作するバイナリがあります。今、私はそれに何らかのパッチを書きたいと思っています。パッチは、メイン プログラムの下の RAM にロードされ、メイン プログラムから呼び出されます。問題は、パッチから使用されるいくつかの関数の手動で設定されたアドレスを使用するようにgccに指示する方法です。言い換えれば、古いコードには機能sin()
があり、 nm を使用しsin()
て古いコードのアドレスを見つけることができました。パッチを適用したコードsin()
(またはメイン プログラムの何か) を使用しsin()
、パッチを適用したコードをリンクしている間、関数の静的アドレスを使用するように gcc (または ld またはその他のもの) に指示したいと考えています。出来ますか?
1 に答える
sin()
問題は、パッチを適用したコードの元の関数へのすべての参照を置き換えるように指定したことです。そのためには、参照を解決するために使用されるすべてのオブジェクト コード データをランタイム システムに含める必要があり、元のコードを変更可能にする必要があります (たとえば、ROM にない)。
Windriver の RTOS VxWorks は、あなたが提案していることに近いことを行うことができます。その方法は、「部分リンク」 (GNU リンカ オプション) を使用して-r
、実行時に解決されるリンクを含むオブジェクト ファイルを生成することです。これにより、未解決のリンクを含むオブジェクト ファイル、つまり不完全な実行可能ファイルを作成できます。VxWorks 自体には、部分的にリンクされたオブジェクト ファイルを動的にロードして参照を解決できるローダーとランタイム「リンカー」が含まれています。ただし、読み込まれたオブジェクト ファイルは、既に読み込まれているオブジェクト コードを使用して完全に解決できる必要があります。そのため、循環依存関係はありません。この例では、システムをリロード/再起動して、オブジェクト ファイルを含むオブジェクト ファイルが以前sin()
に読み込まれるようにする必要があります。そうしないと、後でロードされたものだけが新しい実装を使用します。
したがって、VxWorks (または同様の機能を持つ OS) を使用する場合、ソリューションはおそらく単純です。そうでない場合は、独自のローダー/リンカーを実装する必要があります。もちろん可能ですが、簡単ではありません。
もう 1 つのおそらくより単純な可能性は、すべての呼び出し (または少なくとも置き換えたいすべての呼び出し) が実行時に解決されるように、変数に保持するポインターを介してすべてのコードで関数を呼び出すことです。パッチをロードしてから、sin()
関数のポインターを変更して、その後のすべての呼び出しが新しい関数に対して行われるようにする必要があります。このアプローチの問題は、アプリオリに知る必要があることです。後でどの関数を置き換えたいか、またはすべての関数をそのように呼び出す可能性があります (これは、メモリの観点から非常に高価になる可能性があります。このソリューションでは、関数をマークできる何らかのプリプロセッサまたはコード ジェネレータを用意すると便利です。これはこの方法で「動的」になり、ポインターと呼び出しコードを自動的に生成できます。たとえば、次のようにコードを記述できます。
__dynamic void myFunction( void ) ;
...
myFunction() ;
カスタムプリプロセッサは以下を生成します:
void myFunction( void ) ;
void (*__dynamic_myFunction)(void) = myFunction() ;
...
__dynamic_myFunction() ;
次に、パッチ/ローダー コードは、myFunctionDyn に置換関数のアドレスを再割り当てします。
__dynamic_xxxxx シンボルの名前とアドレスだけを含む「動的シンボル テーブル」を生成し、それをアプリケーションに含めて、ロードされたオブジェクト ファイル内のシンボルと xxxxx 名を照合することにより、ローダーが __dynamic_xxxxx 変数を変更できるようにすることができます。プレーン バイナリをロードしますが、リンク情報をローダーに提供する必要があります。つまり、再割り当てする __dynamic_xxxxx 変数とそれに割り当てるアドレスです。