私はこのコードを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_pointer
into %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に必要な再配置を正確に挿入させるには?