はじめに
MySQLのストレージエンジンは、MySQLが提供する関数を使用します。そのため、通常はMySQLのストレージエンジンをWindows上でmysqldのコアにリンクすることが必要です。これは、mysqldが.dllではなく.exeであり、必要な関数がすべてエクスポートされないことによります。したがって、自作のプラグインを作成するときに、必要な関数をすべてインポートすることは不可能です...少なくとも理論上は。
しかしありがたいことに、MySQLでは、リリースの配布物の中に.mapファイルが付属しています。この中には、必要なインポート関数のアドレスがすべて示されています。そこで私は、次のようなアイデアをひらめきました。
Microsoft Visual C バージョン6のリンカーには、遅延読み込みの機能があります。必要なDLL関数を実行中に読み込むことができる機能です。その場合、リンカーは、IATのポインタを、特別なインポートコードに対応付けます。簡単に言うと、必要な関数への最初のアクセス時にLoadLibrary()
とGetProcAddress()
を呼び出して、IATのエントリを正しいアドレスで上書きするというコードです。遅延読み込みの詳細については、http://www.microsoft.com/msj/1298/hood/hood1298.aspxを参照してください。
幸い、遅延読み込みのコードは、リンカー自身が生成するものではありません。Microsoft Visual Studio 6以降に同梱されているdelayimp.lib内の、あらかじめ定義された関数を呼び出しているだけです。さらに幸いなことに、遅延インポートローダーのソースコードも同梱されています(VC98\Include\DELAYHLP.CPP)。ここまで言えば、私のアイデアがおわかりになるかもしれません。
そのアイデアとは、遅延インポートローダーを自分で作成するというものです。この遅延インポートローダーは、要求された関数へのエントリポイントを.mapファイルに基づいて解決し、その正しい関数ポインタをIATに書き込みます。本稿のプラグインは、すべてのコードが含まれたmysqld.exeプロセスのコンテキストで動作するので、必要なコードのfarポインタさえわかればOKです。もちろん、.exeファイルが再配置されていないかどうかをチェックして、最終的に.mapファイルのアドレスを再配置する必要はあります。しかしそれは大きな問題ではありません。必要な読み込みアドレスも.mapファイルに含まれているからです(アドレス - 必要な読み込みアドレス + 実際の読み込みアドレス
)。モジュールのモジュールハンドルは読み込みアドレスとまったく同じなので、これは簡単です。このようなdelayimp.libを作成して、自作のプラグインにリンクし、すべてのインポートを実行時に動的に解決するという方法で行くことにします。ただし仕様上、リンカーには、関数宣言を解決するインポートライブラリが必要です。
では、始めることにしましょう。
まずは、一連の作業を行うためのビルド環境をセットアップする必要があります。MySQLのソースディレクトリにwin\delayloadディレクトリを作成してください。