2011-11-02 8 views
8

私は現在、別の位置に移動されたコードが変数とクラスポインタを読み込む32ビットでスキーム置換スキームを使用しています。 x86_64は絶対アドレス指定をサポートしていないので、コードの新しい位置で変数の正しいアドレスを取得することができません。詳細な問題は、リッピング相対アドレス指定のために、命令ポインタアドレスがコンパイル時と異なることである。x86_64のランタイムコード置換のための絶対アドレス指定

x86_64または別の方法で絶対アドレス指定を使用して、命令ポインタ以外の変数のアドレスを取得する方法はありますか?

次のようなもの:leaq variable(%%rax), %%rbxも役に立ちます。私は命令ポインタに依存したくない。

答えて

6

x86_64のコードモデルを使用してみてください。 gccでは、これは-mcmodel = largeで選択できます。コンパイラは、コードとデータの両方に64ビット絶対アドレス指定を使用します。

-fno-picを追加して、位置独立コードの生成を禁止することもできます。

編集:私は-mcmodel =大と小テストアプリケーションを構築し、得られたバイナリ(この場合アドレスに)絶対64ビット即値の負荷である

400b81:  48 b9 f0 30 60 00 00 movabs $0x6030f0,%rcx 
400b88:  00 00 00 
400b8b:  49 b9 d0 09 40 00 00 movabs $0x4009d0,%r9 
400b92:  00 00 00 
400b95:  48 8b 39    mov (%rcx),%rdi 
400b98:  41 ff d1    callq *%r9 

ような配列を含みます間接的な呼び出しまたは間接的な読み込みが続きます。命令シーケンス

moveabs variable, %rbx 
addq %rax, %rbx 

フラグのようないくつかの副作用が

+0

-mcmodel = largeが解決策になるはずです。私はgccのosxコンパイラがそれをサポートしていない理由を調査する必要があります – nux

+0

多分それは古いです。小規模(標準)および中規模のコード・モデルが早期に追加され、大型モデルが後で追加されました。 – hirschhornsalz

+0

私はあなたにとても感謝しています。これは非常によく見え、絶対に問題を解決する絶対に解決します。 – nux

2

あなたが求めているのは、実行可能ですが、それほど簡単ではありません。

これを行う1つの方法は、命令のコード移動を補うことです。 RIP相対アドレッシング(012h、0dh、15h、1dh、25h、2dh、35h、または3dhのModRMバイトを持つ)を使用するすべての命令を見つけ、その移動量(移動量)でdisp32フィールドを調整する必要がありますしたがって、仮想アドレス空間では+/- 2GBに制限されます。これは、64ビットアドレス空間が4GBを超えると保証されない可能性があります)。

また、ほとんどの場合、たとえば、複数で、すべての元の命令を置き換え、それらの等価物とそれらの命令を置き換えることができます。

; These replace the original instruction and occupy exactly as many bytes as the original instruction: 
    JMP Equivalent1 
    NOP 
    NOP 
Equivalent1End: 

; This is the code equivalent to the original instruction: 
Equivalent1: 
    Equivalent subinstruction 1 
    Equivalent subinstruction 2 
    ... 
    JMP Equivalent1End 

どちらの方法は、少なくともいくつかの基本的なx86の分解ルーチンが必要になります。

元のコードのパッチされたコピーを含むメモリが元のコードの+/- 2GB以内になるようにするには、WindowsでVirtualAlloc()(またはそれに相当するもの)を使用する必要があります。特定のアドレスでの割り当ては失敗する可能性があります。

プリミティブ分解だけでなく、完全な命令のデコードと生成も必要です。

回避策は他にもあります。

RFLAGSレジスタにTFフラグを設定して、すべての命令の実行終了時にCPUがsingle-stepデバッグ割り込みを生成させるように命令境界を見つけることもできます。デバッグ例外ハンドラはそれらをキャッチし、次の命令のRIPの値を記録する必要があります。私はこれがWindowsのStructured Exception Handling (SEH)(デバッグ割り込みでは試したことがない)を使用して実行できると信じています。これを行うには、すべてのコードをすべての命令で実行する必要があります。

Btwには、64ビットモードでの絶対アドレス指定があります。たとえば、0A0hから0A3hまでのオペコードを使用するMOVの/からのアキュムレータ命令を参照してください。

+0

等を変更すると、(存在しない)「leaq offset64bit(%RAX)、%のRBX」に相当し、答えてくれてありがとう。私が理解している限り、実行時にmovのアドレス値を再計算する方法があります。これはスキームのために重く見えるので、それが私が別の実装について考えている唯一の方法なら、 – nux