プロセスディスクリプタの処理方法を理解するためにLinuxカーネルソースコード(3.12.5 x86_64)を読んでいます。gccインラインアセンブリーLinuxカーネルの "m"の上に "P"と制約 "p"を使用する
私は次のように実装されてcurrent_thread_info()関数を使用することができ、現在のプロセスの記述を取得することが判明:
static inline struct thread_info *current_thread_info(void)
{
struct thread_info *ti;
ti = (void *)(this_cpu_read_stable(kernel_stack) +
KERNEL_STACK_OFFSET - THREAD_SIZE);
return ti;
}
そしてIはthis_cpu_read_stable()
に見:
#define this_cpu_read_stable(var) percpu_from_op("mov", var, "p" (&(var)))
#define percpu_from_op(op, var, constraint) \
({ \
typeof(var) pfo_ret__; \
switch (sizeof(var)) { \
...
case 8: \
asm(op "q "__percpu_arg(1)",%0" \
: "=r" (pfo_ret__) \
: constraint); \
break; \
default: __bad_percpu_size(); \
} \
pfo_ret__; \
})
#define __percpu_arg(x) __percpu_prefix "%P" #x
#ifdef CONFIG_SMP
#define __percpu_prefix "%%"__stringify(__percpu_seg)":"
#else
#define __percpu_prefix ""
#endif
#ifdef CONFIG_X86_64
#define __percpu_seg gs
#else
#define __percpu_seg fs
#endif
拡張マクロあるべき次のようなインラインasmコード:
asm("movq %%gs:%P1,%0" : "=r" (pfo_ret__) : "p"(&(kernel_stack)));
this postによれば、入力制約は "m"(kernel_stack)であり、それは私にとって意味があります。しかし、明らかにパフォーマンスを向上させるために、Linusが「P」への制約を変更し、変数のアドレス渡さ:postでも
It uses a "p" (&var) constraint instead of a "m" (var) one, to make gcc
think there is no actual "load" from memory. This obviously _only_ works
for percpu variables that are stable within a thread, but 'current' and
'kernel_stack' should be that way.
Tejunホこのコメント製:修飾子を組み合わせると
Added the magical undocumented "P" modifier to UP __percpu_arg()
to force gcc to dereference the pointer value passed in via the
"p" input constraint. Without this, percpu_read_stable() returns
the address of the percpu variable. Also added comment explaining
the difference between percpu_read() and percpu_read_stable().
しかし、私の実験を」 P "修飾子と制約" p(& var) "が機能しませんでした。セグメントレジスタが指定されていない場合、 "%P1"は常に変数のアドレスを返します。ポインタは参照解除されませんでした。私は "(%P1)"のように逆参照するために括弧を使用する必要があります。セグメントレジスタが指定されている場合、括弧なしでgccはコンパイルされません。私のテストコードは次の通りです:
#include <stdio.h>
#define current(var) ({\
typeof(var) pfo_ret__;\
asm(\
"movq %%es:%P1, %0\n"\
: "=r"(pfo_ret__)\
: "p" (&(var))\
);\
pfo_ret__;\
})
int main() {
struct foo {
int field1;
int field2;
} a = {
.field1 = 100,
.field2 = 200,
};
struct foo *var = &a;
printf ("field1: %d\n", current(var)->field1);
printf ("field2: %d\n", current(var)->field2);
return 0;
}
私のコードに何か問題はありますか?または、gccのオプションを追加する必要がありますか?また、アセンブリコードを生成するためにgcc -Sを使用したとき、私は "m"より "p"を使って最適化を見ませんでした。どんな答えやコメントも大歓迎です。
'gcc-help @ gcc.gnu.org'に問い合わせて、コンパイラの正確なバージョンを教えてください... –