2

私はこのコードをClang互換の「GNUextendedasm」で記述しました。

namespace foreign {
    extern char magic_pointer[];
}

extern "C" __attribute__((naked)) void get_address_of_x(void)
{
    asm volatile("movq %[magic_pointer], %%rax\n\t"
                 "ret"
                 : : [magic_pointer] "p"(&foreign::magic_pointer));
}

私はそれが次のアセンブリにコンパイルされることを期待していました:

_get_address_of_x:
## InlineAsm Start
    movq    $__ZN7foreign13magic_pointerE, %rax
    ret
## InlineAsm End
    ret  /* useless but I don't think there's any way to get rid of it */

しかし、代わりに私はこの「ナンセンス」を取得します:

_get_address_of_x:
movq    __ZN7foreign13magic_pointerE@GOTPCREL(%rip), %rax
movq    %rax, -8(%rbp)
## InlineAsm Start
movq -8(%rbp), %rax
    ret
## InlineAsm End
ret

どうやらClangは&foreign::magic_pointerinto %rax(関数にとって致命的)の値を割り当ててから、存在nakedすらしていないスタックフレームにさらに「スピル」して、インラインasmブロックで再びそれを引き抜くことができるようにしています。

では、手動の名前マングリングに頼らずに、Clangに必要なコードを正確に生成させるにはどうすればよいですか?私はただ書くことができたという意味です

extern "C" __attribute__((naked)) void get_address_of_x(void)
{
    asm volatile("movq  __ZN7foreign13magic_pointerE@GOTPCREL(%rip), %rax\n\t"
                 "ret");
}

しかし、それを助ける方法があれば、私は本当にそれをしたくありません。

を押す前に、と制約"p"を試しました。しかし、64ビットのポインタオペランドでは正しく機能していないようです。Clangは、オペランドをレジスタに割り当てることができないというエラーメッセージを表示し続けました。これは、何かおかしなことが起こっているようです。"i""n"%flags


ここで「XY問題」を解決することに興味がある人のために:引数がこのマジックポインタ値に設定され、他の引数が元の値に基づいて設定されている別の関数を呼び出す、はるかに長いアセンブリスタブを実際に作成しようとしてfoo(void *p, ...)pますこのアセンブリスタブが入力された時点でのCPUレジスタの値。(したがって、機能します。)任意の会社のポリシーは、最初からファイルにnaked気の毒なことを書くことを防ぎます。.Sその上、私は本当にの代わりに書きたいです。とにかく、それはスタックまたはレジスタに一時的な結果をこぼすことがこの文脈で厳密に冗長である理由を説明するはずです。foreign::magic_pointer__ZN7foreign...etc...


おそらく書く方法がいくつかあります

asm volatile(".long %[magic_pointer]" : : [magic_pointer] "???"(&foreign::magic_pointer));

Clangに必要な再配置を正確に挿入させるには?

4

2 に答える 2

2

これがあなたが望むものだと思います:

namespace foreign {
    extern char magic_pointer[];
}

extern "C" __attribute__((naked)) void get_address_of_x(void)
{
    asm volatile ("ret" : : "a"(&foreign::magic_pointer));
}

このコンテキストでは、「a」は%rax使用する必要があることを指定する制約です。次に、Clang はインライン asm を実行する準備として のアドレスをロードします。必要なのはこれだけですmagic_pointer%rax

asmテキストで参照されていない制約を定義しているため、少し危険です。それが技術的に許可されている/明確に定義されているかどうかはわかりませんが、最新のclangでは機能します。

clang 3.0-6ubuntu3 では (怠け者でgcc.godbolt.orgを使用しているため)、 を使用すると-fPIC、次の asm が得られます。

get_address_of_x:                       # @get_address_of_x
    movq    foreign::magic_pointer@GOTPCREL(%rip), %rax
    ret
    ret

そしてなし-fPIC

get_address_of_x:                       # @get_address_of_x
    movl    foreign::magic_pointer, %eax
    ret
    ret
于 2012-12-11T20:26:07.547 に答える
1

OPはこちら。

最終的には、マジック値を返すヘルパーextern "C"関数を作成し、アセンブリ コードからその関数を呼び出すだけになりました。Clang は私の元のアプローチを何らかの方法でサポートする必要があると今でも考えていますが、私の実際のケースでのそのアプローチの主な問題は、x86-32 にスケーリングされなかったことです。x86-64 では、 -relativeを使用して単一の命令で任意のアドレスをロード%rdxできます。しかし、x86-32 では、任意のアドレスをロードすると、膨大な量コード、ディレクティブ、2 つのメモリ アクセスが発生します... 私は、それらすべてを手作業で書き込もうとしたくなかったのです。だから私の最終的なアセンブリコードは次のようになります%ripmov-fPIC.indirect_symbol

asm volatile(
    "...save original register values...;"
    "call  _get_magic_pointer;"
    "movq  %rax, %rdx;"
    "...set up other parameters to foo...;"
    "call  _foo;"
    "...cleanup..."
    );

よりシンプルでクリーン。:)

于 2012-12-13T20:43:01.573 に答える