2008/03/04 18:31
asmlinkage wkoh+development2008/03/04 18:31
친구랑 이야기 하다가 asmlinkage 에 대해서 말이 튀어나왔다. 사실 예전에 os 수업때 system call 을 만들면서 사용했던 매크로인 것 같은데.. 하면서 xen 의 source 에서 definition을 찾아보았다.
#if defined(__x86_64)
...
#define asmlinkage
...
#endif
...
#elif defined(__i386__)
...
#define asmlinkage __attributre__((regparm(0)))
...
#endif
i386에서 해당 기능을 보자면... kernelnewbies 에서는 다음과 같이 나와있다.
"This is a #define for some gcc magic that tells the compiler that the function should not expect to find any of its arguments in registers (a common optimization), but only on the CPU's stack."
이말인 즉슨... 원래 다들 알다시피 기본적으로는 function call 을 할 때 stack을 통해서 call를 하게 되어있다. 하지만 일부 컴파일러에서 optimization을 하면서 이를 register를 통해서 call 하도록 변경하는 경우가 발생하는데... 이부분은 이렇게 하면 안된다~ 라고 이야기 하고 있는 부분이다. 즉, CPU's stack에서만 아규먼트를 찾아야지, register에서 찾아서는 안된다. 라고 언급하고 있는 부분이 된다.
하지만 이러한 부분은 x86_64 와 i386에서 다르게 처리하고 있다. xen hypervisor 의 소스를 보자면...
- arch/x86/traps.c
1124 */
1125 asmlinkage void do_early_page_fault(struct cpu_user_regs *regs)
1126 {
1127 static int stuck;1128 static unsigned long prev_eip, prev_cr2;
1129 unsigned long cr2 = read_cr2();
역기서 i386의 경우에는 asmlinkage 가 위에서와 같이 정의된 형태로 해석이 될터이고, x86_64에서는 empty 로 정의가 되었으니 아무것도 없게 해석될 것이다. 이에 대해서 실제 early_page_fault 를 호출하는 부는 어떻게 되어있나 살펴보면...
- arch/x86/x86_32/entry.S
539 ENTRY(early_page_fault)
540 SAVE_ALL(1f,1f)
541 1: movl %esp,%eax
542 pushl %eax
543 call do_early_page_fault
544 addl $4,%esp
545 jmp restore_all_xen
와 같이 arguments를 STACK에 저장하고 이를 해당 call을 수행하게 된다. 이때, call은 asmlinkage를 사용하고 있고 i386에서는 asmlinkage 가 empty가 아니기 때문에, call 의 arguments를 stack에서 찾게 된다.
- arch/x86/x86_64/entry.S
580 ENTRY(early_page_fault)
581 SAVE_ALL
582 movq %rsp,%rdi
583 call do_early_page_fault
584 jmp restore_all_xen
하지만 위와 같이 i386이 아닌 x86_64 시스템에서는 그렇지 않음을 볼 수 있다. 이는 구조에 따른 calling convention에 관련된 문제인 듯하다. 실제 x86_64 구조에서는 calling convention에서 1~4번 파라메터의 경우, 레지스터에 넣고 5번부터는 stack에 넣어서 처리하게 되어있다고 한다. 하지만 callee가 stack을 이용해서 처리할 때를 대비하여 stack상에 4개의 파라메터를 위한 0x20 (32bytes)사이즈의 stack 공간을 예약한다고 한다.
linux kernel 상에서는 asmlinkage 에 대해서 define 되어있는 구조는 i386 뿐이며, ia64의 경우에는 __attributre__((syscall_linkage))로 선언되어 있고, 나머지에 대해서는 empty 로 defined 되어 있다고도 한다.
#if defined(__x86_64)
...
#define asmlinkage
...
#endif
...
#elif defined(__i386__)
...
#define asmlinkage __attributre__((regparm(0)))
...
#endif
i386에서 해당 기능을 보자면... kernelnewbies 에서는 다음과 같이 나와있다.
"This is a #define for some gcc magic that tells the compiler that the function should not expect to find any of its arguments in registers (a common optimization), but only on the CPU's stack."
이말인 즉슨... 원래 다들 알다시피 기본적으로는 function call 을 할 때 stack을 통해서 call를 하게 되어있다. 하지만 일부 컴파일러에서 optimization을 하면서 이를 register를 통해서 call 하도록 변경하는 경우가 발생하는데... 이부분은 이렇게 하면 안된다~ 라고 이야기 하고 있는 부분이다. 즉, CPU's stack에서만 아규먼트를 찾아야지, register에서 찾아서는 안된다. 라고 언급하고 있는 부분이 된다.
하지만 이러한 부분은 x86_64 와 i386에서 다르게 처리하고 있다. xen hypervisor 의 소스를 보자면...
- arch/x86/traps.c
1124 */
1125 asmlinkage void do_early_page_fault(struct cpu_user_regs *regs)
1126 {
1127 static int stuck;1128 static unsigned long prev_eip, prev_cr2;
1129 unsigned long cr2 = read_cr2();
역기서 i386의 경우에는 asmlinkage 가 위에서와 같이 정의된 형태로 해석이 될터이고, x86_64에서는 empty 로 정의가 되었으니 아무것도 없게 해석될 것이다. 이에 대해서 실제 early_page_fault 를 호출하는 부는 어떻게 되어있나 살펴보면...
- arch/x86/x86_32/entry.S
539 ENTRY(early_page_fault)
540 SAVE_ALL(1f,1f)
541 1: movl %esp,%eax
542 pushl %eax
543 call do_early_page_fault
544 addl $4,%esp
545 jmp restore_all_xen
와 같이 arguments를 STACK에 저장하고 이를 해당 call을 수행하게 된다. 이때, call은 asmlinkage를 사용하고 있고 i386에서는 asmlinkage 가 empty가 아니기 때문에, call 의 arguments를 stack에서 찾게 된다.
- arch/x86/x86_64/entry.S
580 ENTRY(early_page_fault)
581 SAVE_ALL
582 movq %rsp,%rdi
583 call do_early_page_fault
584 jmp restore_all_xen
하지만 위와 같이 i386이 아닌 x86_64 시스템에서는 그렇지 않음을 볼 수 있다. 이는 구조에 따른 calling convention에 관련된 문제인 듯하다. 실제 x86_64 구조에서는 calling convention에서 1~4번 파라메터의 경우, 레지스터에 넣고 5번부터는 stack에 넣어서 처리하게 되어있다고 한다. 하지만 callee가 stack을 이용해서 처리할 때를 대비하여 stack상에 4개의 파라메터를 위한 0x20 (32bytes)사이즈의 stack 공간을 예약한다고 한다.
linux kernel 상에서는 asmlinkage 에 대해서 define 되어있는 구조는 i386 뿐이며, ia64의 경우에는 __attributre__((syscall_linkage))로 선언되어 있고, 나머지에 대해서는 empty 로 defined 되어 있다고도 한다.
이올린에 북마크하기
