윈도우 커널 모드 포팅의 정석 5편 - 메모리 함수 구현

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

이번에는 가장 기본적인 메모리 할당 함수를 구현해보도록 하겠습니다.

유저 모드에서는 보통 CRT 함수인 malloc을 많이 사용합니다. 또한 HeapAlloc, LocalAlloc 등의 함수들도 사용됩니다.

커널 모드에서는 이 함수들을 ExAllocatePoolWithTag 함수로 대체할 수 있습니다. 단 한가지 주의해야 할 점은 유저 모드에서는 IRQL 이라는 개념이 없기 때문에 메모리 함수 호출에 아무런 제약이 없습니다. 하지만 커널 모드에서는 IRQL에 따라서 할당할 수 있는 메모리 종류에 제약이 있습니다.

malloc
void *malloc(size_t _Size)
{
    POOL_TYPE poolType;
    void *mem;

    if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
        poolType = NonPagedPool;
    else
        poolType = PagedPool;

    mem = ExAllocatePoolWithTag(poolType, _Size, 'llam');

    return mem;
}

IRQL이 DISPATCH_LEVEL 이상일 때에는 NonPagedPool로 할당합니다. DISPATCH_LEVEL 미만일 때에는 PagedPool로 할당합니다. 유저 모드에서 포팅한 커널 모드 루틴의 경우 대부분 PASSIVE_LEVEL에서 동작할 것이지만, 스핀락을 사용하여 동기화를 하는 부분이 있다면 DISPATCH_LEVEL이 됩니다. 이런 경우를 고려해야 합니다.

free
void free(void *_Memory)
{
    ExFreePool(_Memory);
}

free등의 메모리 해제 함수는 ExFreePool 함수를 이용하면 됩니다.

realloc
void *realloc(void *_Memory, size_t _NewSize)
{
    POOL_TYPE poolType;
    void *mem;

    if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
        poolType = NonPagedPool;
    else
        poolType = PagedPool;

    mem = ExAllocatePoolWithTag(poolType, _NewSize, 'laer');

    if (_Memory != NULL)
    {
        RtlCopyMemory(mem, _Memory, _NewSize);
        ExFreePool(_Memory);
    }

    return mem;
}

realloc 계열 함수도 위 처럼 구현할 수 있습니다. realloc 함수는 할당된 메모리의 크기를 조절하는 함수입니다. 실제 realloc 구현에서는 연속된 빈 메모리 블럭이 있을 때 다시 메모리를 할당하지 않고 크기를 늘리게 됩니다. 연속된 빈 메모리 공간이 없을 때에는 다른 곳에 메모리를 할당하고, 내용을 복사한 후 원본 메모리는 해제하게 됩니다.

실제 realloc과 동일하게 구현하려면 상당히 복잡해지므로, 새로운 메모리를 할당하고 내용을 복사한 뒤 원본 메모리를 해제하는 방식으로 처리합니다. realloc 함수는 많이 사용되지 않기 때문에 이런 방식으로 처리해도 큰 문제는 없습니다.

calloc
void *calloc(size_t _NumOfElements, size_t _SizeOfElements)
{
    POOL_TYPE poolType;
    void *mem;

    if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
        poolType = NonPagedPool;
    else
        poolType = PagedPool;

    mem = ExAllocatePoolWithTag(poolType, _NumOfElements * _SizeOfElements, 'llac');

    RtlZeroMemory(mem, _NumOfElements * _SizeOfElements);

    return mem;
}

calloc은 할당한 메모리를 0으로 초기화 합니다. 실제 calloc 구현과 다소 차이가 있을 수 있습니다. 하지만 포팅을 할때에는 내부 구현어떻게 되었든 해당 함수의 결과 값이 동일하게 나오느냐가 중요합니다. 포팅이 끝난 후 성능 문제가 발생한다면 그때 가서 최적화를 하는 방법으로 진행합니다.

관련글


저작권 안내

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

Published

2009-07-22