は私がカーネルとスレッドの上に、ユーザのスレッドを実装し、ユーザースレッドがカーネルスレッド間を移動する際、thread_local
変数は、変数もvolatile
としてタグ付けされていても、以前のカーネルの場所から読み込まれ、ことを観察しています。カーネルスレッド間の移行後にthread_local変数を強制的にリロードすることはできますか?
コンパイラは単なる関数呼び出しとしてユーザレベルswapcontext
を見ているので、以下の例では、単純な関数呼び出しに問題があることを示しています。
#include <stdio.h>
struct Foo {
int x;
int y;
};
__thread Foo* volatile foo;
void bar() {
asm("nop");
}
void f() {
foo->x = 5;
bar();
asm volatile("":::"memory");
// We desire a second computation of the address of foo here as an offset
// from the FS register.
foo->y = 7;
}
int main(){
foo = new Foo;
f();
delete foo;
}
次に、コンパイルとディスアセンブルのコマンドを実行します。 -fPIC
フラグは、この問題を再現するために必要なようだ、と私はライブラリを構築していますので、また私のユースケースのために必要であることに注意してください。上記のコードは、ファイルにここTL.cc
g++ -std=c++11 -O3 -fPIC -Wall -g TL.cc -o TL
objdump -d TL
と呼ばれていると仮定すると、機能f()
の組立ダンプです。
400760: 53 push %rbx
# Notice this computation happens only once.
400761: 64 48 8b 04 25 00 00 mov %fs:0x0,%rax
400768: 00 00
40076a: 48 8d 80 f8 ff ff ff lea -0x8(%rax),%rax
400771: 48 89 c3 mov %rax,%rbx
400774: 48 8b 00 mov (%rax),%rax
400777: c7 00 05 00 00 00 movl $0x5,(%rax)
40077d: e8 ce ff ff ff callq 400750 <_Z3barv>
# Observe that the value of rbx came from before the function call,
# so if the function bar() actually returned on a different kernel
# thread, we would be referencing the original kernel thread's
# version of foo, instead of the new kernel thread's version.
400782: 48 8b 03 mov (%rbx),%rax
400785: c7 40 04 07 00 00 00 movl $0x7,0x4(%rax)
40078c: 5b pop %rbx
40078d: c3 retq
40078e: 66 90 xchg %ax,%ax
は、我々はrax
がメモリから再ロードされているレジスタを観察するが、それはメモリ位置はbar()
への呼び出しの前に決定されました。
fs
レジスタのオフセットから変数のアドレスを強制的にリロードする方法はありますか?
は、私はそれらが存在する場合、GCC固有のハックを使用して元気です。
はここ
g++ (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
シンプルな 'asm volatile(" ":::" memory ");'あなたのためのトリックですか? – tmyklebu
いや、それはTLS変数のアドレスの再計算を強制しないので、それはレジスタにキャッシュされた値をメモリにアクセスしていないにもかかわらず、それはまだ古いアドレスを使用しています。 – merlin2011
関連するソースコードを投稿できますか? –