강좌 & 팁
글 수 2,412
2012.09.28 23:38:11 (*.52.177.29)
43730
제가 커널 산책을 시작하면서
그 수 많은 것 중에서
가장 먼저 시스템 콜을 다루는 이유는
커널을 제대로 이해하기 위해서는
다른 무엇 보다도
시스템 콜의 구현 매커니즘을 잘 이해해야 하기 때문입니다.
커널의 가장 핵심적이고 중요한 처리는
이 시스템 콜이 이루어지는 과정에서 처리 되고 있기 때문입니다.
이 부분에 대한 이해가 되지 않으면 커널의 동작을 이해하기가 매우 어렵습니다.
특히 프로세스와 관련된 부분에서는 더욱 그렇습니다.
ARM 프로세서용 리눅스 커널에서
시스템 콜은 ARM 에서는 SWI 명령을 이용하여 구현됩니다.
리눅스 커널에서
이 SWI 명령을 이용해 어떻게 시스템 콜이 구현되는가를 알아보러 가기 전에
시스템 콜에 대해서 한번 더 살펴보고 가 봅시다.
시스템 콜은 시스템 제어 루틴을 호출하는 것입니다.
예를 들어 여러분이 잘 알고 있는 open() 이라는 함수는 시스템 콜입니다 .
파일을 열고 닫는 것은 리눅스 커널이 제공하는 기능이기 때문입니다.
( strcpy() 함수는 시스템 콜이 아닙니다. 이것은 glibc 라이브러리가 제공하는 것입니다.)
시스템은 상당히 많은 기능을 제공하고 있기 때문에
시스템 콜은 매우 많은 함수군으로 구성됩니다.
하지만 SWI 명령이 수행되었을 때
입셉션 핸들러에 의해서 수행되는 루틴은 하나입니다.
이 말은
입센션 핸들러에서 각 기능에 해당하는 루틴으로 분기되어야 하고
SWI 명령을 이용하여 시스템 콜을 호출하는 루틴은
어떤 곳으로 분기될지에 대한 정보를 미리 주어야 합니다.
즉 SWI 명령 이전에 처리해야 하는 것이 있고
SWI 명령에 의해서 분기되기 위해서 분기 정보를 얻어 오도록 처리 해야 하는 것이 있습니다.
이전 산책길에서 SWI 명령이 어떻게 구성되었는지를 기억하실지 모르겠습니다.
다시 한번 기억을 더듬어 보면 SWI 명령은 기계어 코드로 다음과 같이 구성되어 있습니다.
수행 조건(4비트) + SWI 명령(4비트) + 임의값(24비트)
여기서 주의 깊게 보아야 하는 것이 바로 임의값으로 지정할수 있는 24비트 입니다.
SWI 명령을 해석하는 ARM 프로세서는
SWI 명령(4비트) 자리만 체크하고 수행 조건(4비트)이 되면 입셉션을 발생 시킵니다.
그래서 시스템 콜에서 실행해야할 시스템 처리 루틴은 이 임의값(24비트) 을 이용하게 됩니다.
여기에 함수의 배열 번호를 주는 것이죠..
기억하시나요?
처음 시스템 콜 함수를 구현할때 시스템 콜 테이블이라는 것이 있다는 것을?
예 임의값(24비트)는 바로 시스템 콜 테이블의 인덱스로 사용됩니다.
그래서 리눅스 커널 내부에는 시스템 콜 테이블을 가지고 있게 됩니다.
이 시스템 콜 테이블이 어떻게 구성되는가는 나중에 산책하고
여기서는 어떻게 시스템 콜 인덱스를 넘기고 이를 SWI 입셉션 핸들러에서 받는가를 알아 봅시다.
리눅스 커널에서는 두가지 방식으로 인덱스를 넘깁니다.
한 가지는 임의값(24비트)를 이용하는 것이고 또 하나는 R7 레지스터를 이용하는 것입니다.
첫번째는 ABI 형식으로 규정하는 시스템 호출방식이라고 하고
두번째는 EABI 형식으로 규정하는 시스템 호출 방식이라고 합니다.
R7 레지스터를 이용하는 경우에는 임의값(24비트)는 항상 0으로 지정합니다.
초기에는 임의값(24비트)만을 이용했지만
현재는 R7 레지스터를 이용하는 방법이 주로 사용되고, 임의값을 이용하는 것도 또한 지원합니다.
먼저 임의값을 이용하는 경우 입니다.
예를 들어 exit() 함수는 시스템 콜 인덱스는 1 번으로 지정되어 있습니다.
단순하게 SWI 명령에 1을 지정하기 위해서는 어셈블러에서 다음과 같이 지정하면 됩니다.
SWI 1
이 명령은 기계어 코드로 0xEF0000001 이 됩니다.
하지만 리눅스 커널에서는 이렇게 하지 않고 매직 번호를 추가 합니다.
그래서 다음과 같은 형식으로 시스템 콜을 호출 합니다.
swi __NR_SYSCALL_BASE(==0x900000)+N
여기서 N 은 시스템 콜 인덱스 번호가 되지요.
결국 open() 시스템 콜을 호출하기 위해서는
swi __NR_SYSCALL_BASE(==0x900000)+1
과 같은 형식으로 기술해야 합니다.
이 결과로 glibc 라이브러리가 컴파일 된 결과로 생성된 기계어 코드는 0xEF9000001 이 됩니다.
자 이젠 이것을 리눅스 커널에서는 어떻게 해석할까요?
이 부분은 다음 산책하는 날에 설명하겠습니다.
에공 집에 가야 할 것 같습니다. 잠시 짬 나서 썼거든요.
추석 연휴 잘 보네세요 ^^;