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

유저 모드에서는 보통 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

22 July 2009