アセンブリでTLS変数をインクリメントしたいのですが、アセンブリコードにセグメント化エラーがあります。コンパイラに他のレジスタやメモリを変更させたくありません。 gccの入力と出力の構文を使用せずにこれを行う方法はありますか?アセンブリ内のスレッドローカルストレージ
__thread unsigned val;
int main() {
val = 0;
asm("incl %gs:val");
return 0;
}
アセンブリでTLS変数をインクリメントしたいのですが、アセンブリコードにセグメント化エラーがあります。コンパイラに他のレジスタやメモリを変更させたくありません。 gccの入力と出力の構文を使用せずにこれを行う方法はありますか?アセンブリ内のスレッドローカルストレージ
__thread unsigned val;
int main() {
val = 0;
asm("incl %gs:val");
return 0;
}
あなたが本当に何らかの理由でこれを実行できるようにする必要がある場合、あなたはこのように、Cでそのアドレスをプリロードすることにより、アセンブリ言語からスレッドローカル変数にアクセスする必要があります
__thread unsigned val;
void incval(void)
{
unsigned *vp = &val;
asm ("incl\t%0" : "+m" (*vp));
}
これは、スレッドローカル変数にアクセスするために必要なコードシーケンスがGCCでサポートされているOSとCPUの組み合わせごとに異なり、実行可能ではなく共有ライブラリ用にコンパイルしている場合にも変わります(つまり-fPIC
)。上記の構文は、コンパイラがあなたのために正しいコードシーケンスを出力することを可能にします。余分な命令なしにスレッドローカル変数にアクセスすることができる場合、アドレス生成はアセンブリ操作に折りたたまれます。実例として、ここではどのようにGCC 4.7のx86/Linuxは、いくつかの異なる可能なモードで上記をコンパイルするために(私は明確にするため、すべての場合にアセンブラディレクティブの束を取り除かました)...
# -S -O2 -m32 -fomit-frame-pointer
incval:
incl %gs:[email protected]
ret
# -S -O2 -m64
incval:
incl %fs:[email protected]
ret
# -S -O2 -m32 -fomit-frame-pointer -fpic
incval:
pushl %ebx
call __x86.get_pc_thunk.bx
addl $_GLOBAL_OFFSET_TABLE_, %ebx
leal [email protected](,%ebx,1), %eax
call [email protected]LT
incl (%eax)
popl %ebx
ret
# -S -O2 -m64 -fpic
incval:
.byte 0x66
leaq [email protected](%rip), %rdi
.value 0x6666
rex64
call [email protected]
incl (%rax)
ret
ですすべての4つの例がの場合は、x86/OSX用にコンパイルした場合と、x86/Windows用にもう一度異なる場合があります。
1)なぜ、 '' val + = 1; ''を書くことができないのですか? 2)それを書いて、 '-O2 -S 'でコンパイルし、アセンブリ出力を調べます。 '__thread'変数にアクセスする方法について間違っていることがわかります。 – zwol
@Zackあなたはそれについての答えを書くことができますか? – 0x90
val ++はmovl $ 0x1、%gs:0xfffffffcに変換されますが、私はasm( "movl $ 1、%gs:val")を手動でmovl $ 0x1、%gs:0x8049f14に変換します。私のプログラムでアドレス0xfffffffcを取得する方法。 – Yogi