윈도우 커널 모드 포팅의 정석 2편 - 빌드(컴파일) 하기

저작권 안내
  • 책 또는 웹사이트의 내용을 복제하여 다른 곳에 게시하는 것을 금지합니다.
  • 책 또는 웹사이트의 내용을 발췌, 요약하여 강의 자료, 발표 자료, 블로그 포스팅 등으로 만드는 것을 금지합니다.

커널 모드 포팅 작업에서 가장 중요한 것은 빌드(컴파일)하기 입니다.

포팅을 결심하고나서도 컴파일 할 때의 무수한 에러와 경고 때문에, 대부분 이 단계에서 포기를 하게 됩니다.

유저 모드에서 동작하던 프로그램들은 빌드 환경이 Visual Studio 및 Platform SDK에 맞추어져 있습니다. 따라서 이 부분을 WDK(DDK) 환경에 맞게 수정해주고 에러와 경고를 줄여나가야 합니다.

그러므로 이번 단계에서는 일단 빌드만 가능하도록 수정합니다. 따라서 정상 동작은 되지 않습니다.

커널 모드 포팅의 원칙은 원본 소스코드를 최소한으로 수정하는것입니다. 그렇기 때문에 원본 소스를 직접 수정하지 않고 공통 헤더 파일과 호환 레이어를 사용하여 원본 소스코드 외부에서 모든 포팅 작업을 하게 됩니다.

공통 헤더 파일 작성

먼저 포팅을 진행할 소스트리에서 최상위 헤더 파일을 찾습니다. 그리고 이제부터 작성할 compat.h를 include 합니다. 최상위 헤더 파일이 없거나, 헤더 파일이 여러개로 나뉘어져 있을 경우, 각각의 헤더 파일에서 compat.h를 include 해줍니다. (compat.h는 Compatibility를 의미합니다.)

compat.h
#include <ntddk.h>

WDK 환경에서 빌드를 해야 하므로 가장 기본적인 ntddk.h 헤더 파일을 include 합니다. 그리고 유저 모드용 헤더 파일(windows.h 등)은 include를 모두 삭제합니다.

에러 줄여나가기 - 자료형, 매크로 상수

이제부터 공통 헤더 파일 compat.h를 이용하여 에러를 줄여나갑니다. ntddk.h만 include 하고 빌드를 하면, 각종 자료형과 매크로 상수가 정의되어 있지 않아 에러가 발생할 것입니다.

compat.h
typedef unsigned long DWORD;
typedef unsigned short WORD;

typedef struct _FILETIME {
    DWORD dwLowDateTime;
    DWORD dwHighDateTime;
} FILETIME, *PFILETIME, *LPFILETIME;

#define MAX_PATH 260

ntddk.h에는 없는 자료형과 매크로 상수를 위와 같이 정의해줍니다.

에러 줄여나가기 - 일반 함수

각종 자료형과 매크로 상수 뿐만 아니라, 함수에서도 에러가 발생할 것입니다. 일단 에러를 막는 것이 중요하므로 매크로를 이용하여 빈 껍데기 함수를 만들어줍니다.

compat.h
#define CreateFileW(a,b,c,d,e,f,g) 0
#define SetFilePointer(a,b,c,d) 0

원본 함수의 매개변수 개수와 똑같 만들어줍니다. 그리고 오른쪽 부분을 0으로 지정하면 아무일도 하지 않는 빈껍데기 함수가 됩니다.

에러 줄여나가기 - 레퍼런스를 매개변수로 받는 함수

앞의 일반 함수는 일반 변수 및 상수를 매개변수를 받아 특정 동작을 하고 끝나버리기 때문에 매크로를 이용하여도 문제가 없습니다. 하지만 변수의 레퍼런스를 매개변수로 받는 함수는 특정 값을 얻고자 할 때 사용하는 경우가 대부분입니다. 따라서 함수가 호출된 이후에도 해당 변수는 계속 사용되기 때문에, 매크로로 빈껍데기 함수를 만들어 처리해버리면 해당 변수가 초기화 되지 않았다는 에러가 발생합니다.

compat.h
/* 매개 변수는 int */
#define ExampleFunctionA(a) *a = 0

/* 매개 변수는 LARGE_INTEGER, 이후 LowPart만 사용한다고 했을 때 */
#define QueryPerformanceCounter(a) *a.LowPart = 0

/* 매개 변수는 LARGE_INTEGER, 이후 LowPart, HighPart 모두 사용한다고 했을 때 */
#define QueryPerformanceCounter(a) *a.LowPart = 0;*a.HighPart = 0;

이때는 참조 연산자를 사용하여 매개변수를 초기화 해주어야 합니다. 멤버가 많은 구조체일 때에는 이후에 사용되는 모든 멤버를 초기화 해주어야 에러가 발생하지 않습니다.

compat.h
__inline void GetSystemTimeAsFileTime(__out LPFILETIME lpSystemTimeAsFileTime)
{
}

매번 매개변수를 초기화 하지 않으려면 인라인 함수를 이용합니다. 이처럼 인라인 함수를 이용하여 함수 형태만 만들어주면 초기화 에러는 발생하지 않습니다.

위와 같은 방식으로 WDK에 존재하지 않는 자료형, 매크로 상수, 함수 등을 모두 처리하여 에러가 하나도 발생하지 않고 빌드를 성공하였다면, 이제부터 각각의 함수를 구현할 호환 레이어를 만들어야 합니다.

관련글


저작권 안내

이 웹사이트에 게시된 모든 글의 무단 복제 및 도용을 금지합니다.
  • 블로그, 게시판 등에 퍼가는 것을 금지합니다.
  • 비공개 포스트에 퍼가는 것을 금지합니다.
  • 글 내용, 그림을 발췌 및 요약하는 것을 금지합니다.
  • 링크 및 SNS 공유는 허용합니다.

Published

2009-07-12