モジュールを静的にリンクできるようにしたいインターフェースがあります。たとえば、FOO と呼ばれる、または特定のプロトタイプに一致するすべての関数 (別のファイルではありますが) を呼び出し、最終的に他のファイルのヘッダーなしでファイル内の関数を呼び出すことができるようにしたいと考えています。それができるハックを見つけたので不可能だとは言いませんが、ハッキングされていない方法が欲しいです。(ハックは nm を使用して関数とそのプロトタイプを取得し、関数を動的に呼び出すことができます)。また、動的リンクを使用してこれを行うことができることは知っていますが、ファイルを静的にリンクしたいと考えています。何か案は?
4 に答える
すべての関数の表を各翻訳単位に入れます。
struct functions MOD1FUNCS[]={
{"FOO", foo},
{"BAR", bar},
{0, 0}
};
次に、これらすべてのテーブルをリストするメイン プログラムにテーブルを配置します。
struct functions* ALLFUNCS[]={
MOD1FUNCS,
MOD2FUNCS,
0
};
次に、実行時にテーブルを検索し、対応する関数ポインターを検索します。
これは、テスト コードを記述する際にやや一般的です。たとえば、test_ で始まるすべての関数を呼び出したいとします。これで、すべての .C ファイルを grep して、test_.* に一致する関数名を抽出するシェル スクリプトが作成されました。次に、そのスクリプトは、すべてのテスト関数を呼び出す関数を含む test.c ファイルを生成します。
たとえば、生成されたプログラムは次のようになります。
int main() {
initTestCode();
testA();
testB();
testC();
}
それを行う別の方法は、リンカーのトリックを使用することです。これは、Linux カーネルが初期化のために行うことです。初期化コードである関数は、修飾子 __init でマークされます。これは、linux/init.h で次のように定義されています。
#define __init __section(.init.text) __cold notrace
これにより、リンカーはその関数をセクション .init.text に配置します。システムの起動後、カーネルはそのセクションからメモリを再利用します。
関数を呼び出すために、各モジュールは initcall 関数をいくつかの他のマクロ (core_initcall(func)、arch_initcall(func) など) (linux/init.h にも定義されています) で宣言します。これらのマクロは、関数へのポインターを .initcall と呼ばれるリンカー セクションに配置します。
ブート時に、カーネルは .initcall セクションを「ウォークスルー」し、そこにあるすべてのポインターを呼び出します。ウォークスルーするコードは次のようになります。
extern initcall_t __initcall_start[], __initcall_end[], __early_initcall_end[];
static void __init do_initcalls(void)
{
initcall_t *fn;
for (fn = __early_initcall_end; fn < __initcall_end; fn++)
do_one_initcall(*fn);
/* Make sure there is no pending stuff from the initcall sequence */
flush_scheduled_work();
}
シンボル __initcall_start、__initcall_end などは、リンカー スクリプトで定義されます。
一般に、Linux カーネルは、GCC プリプロセッサ、コンパイラ、およびリンカを使用して可能な限り巧妙なトリックを実行します。これは常に C トリックの優れたリファレンスです。
静的リンクが本当に必要であり、同時に、実行時に一致するすべての関数を選択する必要がありますよね? 後者は動的リンクの典型的なケースであるため、私はそう思います。
明らかに、利用可能な関数を登録するメカニズムが必要です。動的リンクはまさにこれを提供します。
私は本当にあなたがそれを行うことができるとは思わない. Cは、遅延バインディングや、必要と思われる種類のイントロスペクションを正確に行うことができません。
私はあなたの質問をよく理解していませんが。静的にリンクしながら、動的にリンクされたライブラリの機能が必要ですか? それは私には意味がありません...静的リンクには、すでにバイナリを手元に用意しておく必要があります。これにより、関数の動的ロードが簡単に実行できたとしても、時間の無駄になります。