리눅스커널의 공간 사용법

(무선)네트워크 2009. 9. 10. 01:57 Posted by 알 수 없는 사용자

리눅스 커널 코드를 분석하다보면 분명 작성된 언어는 C언어인데 처음보는 낯선 키워드등 분석이 잘 안되는 경우가 있습니다.

이는 메크로함수나 함수 포인터 등 #define으로 새로 정의되어 사용되는 키워드들 때문에 가독성이 떨어지기 때문입니다.
 
그 중 한 예로 리눅스의 스케줄링을 담당하는 schedule() 함수를 보면,

asmlinkage void __sched schedule(void)

이렇게 함수가 구성되어 있습니다.

이를 하나씩 살펴 보겠습니다.

asmlinkage는 어셈블리와 링크가 가능하다는 뜻 즉, 어셈블리어로 짜여진 코드에서 이 함수를 호출 할 수 있다는 뜻입니다.

__sched 이 키워드는 linux/include/linux/sched.h에 정의 되어 있습니다.

#define __sched __attribute__((__section__(".sched.text")))

다음과 같은 형태로 정의되어 있는데 ( 점점 더 복잡하게 되는 것 같습니다. )

__attribute__ 는 윈도우의 #pragma 와 비슷한 것으로 c의 표준은 아닙니다.

#pragma는 cl컴파일러에서 작동하며, __attribute__는 gcc컴파일러에서 작동하며 사용되는 용도는 비슷합니다.

__attribute__ 키워드의 대표적인 예로는

typedef struct
{
char a;
int b;
}asdf;

이런 구조체가 있을때 sizeof(asdf) 라고 하면 결과는 8이 나옵니다.

int a = sizeof(char)+sizeof(int);

printf("%d\n", a);

라고 했을 때 결과는 5가 나옵니다.

이는 packing(natural boundary)때문에 일어나는 현상입니다.

이를 정확한 값을 얻고 싶다면

typedef struct
{
char a;
int b;
}__attribute__(packed) asdf;

이렇게 하면 정확한 값이 나옵니다.  (윈도우에서는 #pragma pack(1) 라고 하면 됩니다.)

이 외에 __attribute__(x) 안에 들어갈 수 있는 것은 여러가지가 있습니다.

그럼 다시 돌아와서 살펴 보도록 하겠습니다.
 
__attribute__((__section__(".sched.text")))

이 키워드는 ".sched.text라는 섹션을 만들어서 그 섹션안에 schedule()함수의 내용을 넣어라" 라는 뜻이 됩니다.

이렇게 함으로써 얻을 수 있는 이점으로 섹션은 build 타임에 relocation이 가능하게 되는데,
 
초기화 역할을하는 특정 섹션을 만들어 그 안에 넣은 후 사용하다가 더이상 필요 없을 시 이 섹션을 날려 버립니다.

이런 방식으로 메모리 공간을 아낄 수 있습니다.
 
리눅스에서는 보통 커널공간이 1GB이고, 유저공간이 3GB입니다.(설정에 따라 달라질 수는 있습니다.)

만약 task_struct등 커널 오브젝트의 증가나 컨택스트 스위칭 등 커널 자원을 소비하는 작업을 할 때 커널 공간이 부족하다면 시스템 운영상 곤란 할 것입니다.

실제로 start_kernel() 함수도

asmlinkage void __init start_kernel(void)

#define __init __attribute__ ((__section__ (".text.init")))

이렇게 정의되어 있습니다.

즉 .text.init섹션에 start_kernel함수의 내용을 넣었다가 초가화가 끝나고 나면 이 섹션을 날리면서 메모리 공간을 절약합니다.

이렇게 리눅스에서는 커널공간을 효율적으로 관리하고 있습니다.

관련된 pdf파일을 첨부합니다. 관련된 내용은 아주 조금 있지만 전반적으로 읽어두면 커널을 이해하는데 조금 도움이 될듯합니다.