встроенная сборка gcc с использованием модификатора «P» и ограничения «p» над «m» в ядре Linux

Я читаю исходный код ядра Linux (3.12.5 x86_64), чтобы понять, как обрабатывается дескриптор процесса.

Я нашел, чтобы получить дескриптор текущего процесса, я мог бы использовать функцию 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;
}

Затем я посмотрел на: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))); 

В соответствии сэта почта входное ограничение раньше было «м»(kernel_stack), что имеет смысл для меня. Но очевидно, что для улучшения производительности Линус изменил ограничение на «р» и передал адрес переменной:

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.

Также всообщение Теджун Хео сделал это комментарии:

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" модификатор и ограничение "п(&вар)» не работал. Если сегментный регистр не указан, "% Р1" всегда возвращает адрес переменной. Указатель не был разыменован. Я должен использовать скобку, чтобы разыменовать это, как "(% Р1)», Если указан сегментный регистр, без скобки gcc won 'т даже компилировать. Мой тестовый код выглядит следующим образом:

#include 

#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 для генерации ассемблеране вижу оптимизации с помощью "p" над "м", Любой ответ или комментарии высоко ценится.

Ответы на вопрос(1)

Ваш ответ на вопрос