달력

03

« 2010/03 »

  •  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  •  
  •  
  •  

'wkoh+development'에 해당되는 글 3

  1. 2008/05/07 Distributing Python Modules
  2. 2008/03/04 asmlinkage
  3. 2008/02/29 FAQ/DoWhile0
2008/05/07 18:09

Distributing Python Modules wkoh+development2008/05/07 18:09

Python Module 의 배포를 위해서는 일반적으로 Python Distribution Utilities ("Distutils") 라는 모듈을 사용하게 된다. 작성한 Python 모듈을 패키지할 필요성이 생겨서 이에 대해서 살펴보면서 정리를 한다.

1.1 Concepts

Distutils 를 사용하는 것은 모듈 개발자와 3rd 파티 모듈을 설치하려는 사용자/관리자 모두에게 매우 간단할 일이다. 개발자로서는

  • setup 스크립트를 작성
  • (선택에 따라서는) setup 설정 파일을 작성
  • 소스 배포를 생성
  • (선택에 따라서는) 하나 혹은 그 이상의 개발된 배포파일을 생성

의 일을 갖게 된다.

이러한 태스크들의 각각에 대해서 본 문서에서 설명하게 된다.

more..

Posted by wkoh
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 되어 있다고도 한다.
TAG Kernel, Linux
Posted by wkoh
2008/02/29 10:19

FAQ/DoWhile0 wkoh+development2008/02/29 10:19

커널 코드를 보다보면 #define do {...} while(0) 가 종종 쓰인다. 이러한 부분이 kernelnewbies.org 에 있어서 간단히 정리해 놓는다.

  • (Dave Miller는) Empty statements의 경우 컴파일러가 warning으로 간주하기 때문에 dowhile0 블럭을 사용한다.
  • (Dave Miller는) local variables를 선언하는 basic block으로 간주할 수 있다.
  • (Ben Collins는) 이는 조건이 담긴 코드에서 보다 복잡한 메크로를 사용할 수 있도록 지원하다고 말하고 있다. 만약 몇줄로 이뤄진 하나의 매크로가 다음과 같다면...
#define FOO(x) \
printf("arg is %s\n", x); \
do_something_useful(x);

이제 이러한 함수를 다음과 같이 사용할 때:
if (blah == 2)
FOO(blah);

이는 다음과 같이 해석된다.
if (blah == 2)
printf("arg is %s\n", blah);
do_something_useful(blah);;

여기서 보이다시피 원치않게도 do_something_useful은 조건문에 속하지 않게 된다. 그래서
dowhile0를 사용하여
if (blah == 2)
do {
printf("arg is %s\n", blah);
do_something_useful(blah);
} while (0);
와 같은 형태로 만드는 것이다.
  • (Per Persson은) Muller 와 Collins가 지적한 바와 같이 block statement를 사용하길 원할때, 몇몇줄의 코드와 local variables를 선언할 수 있다고 언급했다. 그러나 일반적으로 사용할 때는 차라리 다음과 같이 사용하는 편이 더욱 직관적이겠다.
#define exch(x,y) { int tmp; tmp=x; x=y; y=tmp; }

그러나 이는 어떤 경우에 대해서는 정상적으로 동작하지 않는다. 다음 코드는 두개의 브랜치를 가지는 If-statement 이다.
if (x > y) exch(x,y); // Branch 1 else do_something(); // Branch 2 그러나 이는 오직 하나의 브랜치만을 갖고있는 if-statement로 해석되게 된다. 다음과 같이...
if (x > y) { // Single-branch if-statement!!! int tmp; // The one and only branch consists tmp = x; // of the block. x = y; y = tmp; } ; // empty statement else // ERROR!!! "parse error before else" do_something();
블럭 뒤에 바로 나오는 semi-colone(;)이 문제가 된 것이다. 이에 대한 해결책은 역시 dowhile0를 사용하는 것이다. 그러면 블럭의 capabilities를 갖는 하나의 statement 를 사용하게 되는 것으로, 다음과 같이 해석될 것이다.
if (x > y) do { int tmp; tmp = x; x = y; y = tmp; } while(0); else do_something();
  • (Bart Trojanowski는) gcc는 dowhile0 블럭을 대체할 수 있는 Statement-Expressions를 제공하고 있다고 언급했다. 이는 위의 장점에 더욱 읽기 쉽다라는 추가적인 장점을 제공한다.
#define FOO(arg) ({         \
           typeof(arg) lcl; \
           lcl = bar(arg);  \
           lcl;             \
    }) 
Posted by wkoh