분석하고 있는 부분은 다음과 같습니다.
percpu_from_op [ arch/x86/include/asm/percpu.h ]
typeof(var) ret__;
asm(op "l "__percpu_arg(1)",%0" \
: "=r" (ret__) \
: "m" (var));
위 소스를 전처리기를 거쳐서 최종 치환한 형태는 아래있습니다.
int ret__;
asm("mov" "l "%fs:%P1",%0" \
: "=r" (ret__) \
: "m" (var));
참고로 여기서 var는 per_cpu__cpu_number 입니다.
"=r"은 범용레지스터 (eax, ebx, ecx, edx)에 해당하는 것으로 레지스터를 출력하겠다는 의미일테고,
"m"은 메모리로 per_cpu__cpu_number를 입력하겠다는 것인데, 그 위에 Instruction 부분이 이해가 안갑니다.
"mov" "l "%fs:%P1",%0" <<<--- 이부분의 뜻이 뭔가요 ?
전체적으로 종합해서
asm("mov" "l "%fs:%P1",%0" \
: "=r" (ret__) \
: "m" (var));
위 문장의 의미는 무엇이 되나요 ?
percpu 영역은 GDT 내에 전용 디스크립터를 따로 만들어두고 접근한다는 것을 이해하시는 것이 중요합니다.
따라서 일반 변수처럼 (암시적으로 사용되는) ds 세그먼트 레지스터를 사용하지 않고 fs를 이용해서 접근해야 합니다.
창우님 말씀처럼 percpu 영역은 user 모드에서 접근할 수 없지만
user 모드에서 percpu와 비슷한 효과를 내는 것으로 TLS (thread local storage)가 있습니다.
(물론 개념이나 적용되는 상황이 다릅니다만.. ;;)
둘 다 세그먼트 디스크립터를 조작해야 하기 때문에 고려할 사항이 많습니다.
이런 테스트 프로그램을 짜봤는데, 어셈 처리하는 부분에서 Segmentation Fault가 발생합니다.
#include <stdio.h>
struct kernel_symbol{
unsigned long value;
const char *name;
};
int cpu_number = 10;
#define MODULE ""
#define TEST(sym, sec) \
extern typeof(sym) sym; \
static char b_##sym[] \
__attribute__((section("data.module"), aligned(1))) \
= MODULE #sym; \
static struct kernel_symbol __ksymtab_##sym \
__attribute__((__used__)) \
__attribute__((section("ksymtab" sec), unused)) \
= { (unsigned long)&sym, b_##sym }
#define __stringify_1(x...) #x
#define __stringify(x...) __stringify_1(x)
#define __percpu_seg fs
#define __percpu_arg(x) "%%"__stringify(__percpu_seg)":%P" #x
int main(void){
TEST(cpu_number, "");
typeof(int) ret__;
char *string = "hihi";
printf(__percpu_arg(1)"\n");
asm("mov" "l "__percpu_arg(1)",%0" \
: "=r" (ret__) \
: "m" (__ksymtab_cpu_number));
return 0;
}