힙 메모리 할당과 시스템 호출
malloc
은 OS에서 메모리를 얻기 위해 brk
또는 mmap
syscall을 사용하여 메모리를 확보한다.
brk
brk: brk
는 프로그램 중단 위치를 증가시켜 커널에서 메모리를 얻는다. 처음 시작(start_brk
) 및 힙 세그먼트 끝(brk
)은 동일한 위치를 가리킨다.
- ASLR이 꺼지면
start_brk
및brk
는 data/bss 세그먼트 (end_data
)`끝을 가리킨다. - ASLR이 켜지면
start_brk
및brk
는 data/bss 세그먼트 (end_data
)끝에 임의의brk
오프셋을 더한 것과 같다.
위의 프로세스 가상 메모리 레이아웃 그림은 start_brk
가 힙 세그먼트의 시작이고 brk
(프로그램 중단)이 힙 세그먼트의 끝임을 보여준다.
예시
/* sbrk and brk example */
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main()
{
void *curr_brk, *tmp_brk = NULL;
printf("Welcome to sbrk example:%d\n", getpid());
/* sbrk(0) gives current program break location */
tmp_brk = curr_brk = sbrk(0);
printf("Program Break Location1:%p\n", curr_brk);
getchar();
/* brk(addr) increments/decrements program break location */
brk(curr_brk+4096);
curr_brk = sbrk(0);
printf("Program Break Location2:%p\n", curr_brk);
getchar();
brk(tmp_brk);
curr_brk = sbrk(0);
printf("Program Break Location3:%p\n", curr_brk);
getchar();
return 0;
}
이제 컴파일 후 프로그램을 실행하여 살펴보자.
# gcc -o brk ./brk.c
# ./brk
Welcome to sbrk example:19109
Program Break Location1:0x804a000
터미널 창을 하나 더 실행하여 프로세스 메모리 공간을 살펴보자.
# cat /proc/19109/maps
08048000-08049000 r-xp 00000000 08:01 1032560 /home/iamroot/workspace/heap/brk
08049000-0804a000 rw-p 00000000 08:01 1032560 /home/iamroot/workspace/heap/brk
b7e98000-b7e99000 rw-p b7e98000 00:00 0
b7e99000-b7fd4000 r-xp 00000000 08:01 886016 /lib/tls/i686/cmov/libc-2.5.so
b7fd4000-b7fd5000 r--p 0013b000 08:01 886016 /lib/tls/i686/cmov/libc-2.5.so
b7fd5000-b7fd7000 rw-p 0013c000 08:01 886016 /lib/tls/i686/cmov/libc-2.5.so
b7fd7000-b7fda000 rw-p b7fd7000 00:00 0
b7fe3000-b7fe7000 rw-p b7fe3000 00:00 0
b7fe7000-b8000000 r-xp 00000000 08:01 851989 /lib/ld-2.5.so
b8000000-b8002000 rw-p 00019000 08:01 851989 /lib/ld-2.5.so
bffeb000-c0000000 rw-p bffeb000 00:00 0 [stack]
ffffe000-fffff000 r-xp 00000000 00:00 0 [vdso]
- Program break 증가 전:
start_brk
=brk
=end_data
= 0x804a000
[Enter 입력]
Program Break Location2:0x804b000
# cat /proc/19109/maps
08048000-08049000 r-xp 00000000 08:01 1032560 /home/iamroot/workspace/heap/brk
08049000-0804a000 rw-p 00000000 08:01 1032560 /home/iamroot/workspace/heap/brk
0804a000-0804b000 rw-p 00000000 00:00 0 [heap]
b7e98000-b7e99000 rw-p b7e98000 00:00 0
b7e99000-b7fd4000 r-xp 00000000 08:01 886016 /lib/tls/i686/cmov/libc-2.5.so
b7fd4000-b7fd5000 r--p 0013b000 08:01 886016 /lib/tls/i686/cmov/libc-2.5.so
b7fd5000-b7fd7000 rw-p 0013c000 08:01 886016 /lib/tls/i686/cmov/libc-2.5.so
b7fd7000-b7fda000 rw-p b7fd7000 00:00 0
b7fe3000-b7fe7000 rw-p b7fe3000 00:00 0
b7fe7000-b8000000 r-xp 00000000 08:01 851989 /lib/ld-2.5.so
b8000000-b8002000 rw-p 00019000 08:01 851989 /lib/ld-2.5.so
bffeb000-c0000000 rw-p bffeb000 00:00 0 [stack]
ffffe000-fffff000 r-xp 00000000 00:00 0 [vdso]
- Program break 증가 후:
start_brk
=end_data
= 0x804a000,brk
= 0x804b000- 0804a000-0804b000은 세그먼트의 가상 주소 범위이다.
- rw-p는 Flags (읽기, 쓰기, 비실행, 비공개)이다.
- 00000000 은 파일 오프셋이다.
- 00:00 은 Major / Minor device number 이다.
- 0 은 아이 노드 번호이다.
mmap
mmap: malloc
은 mmap
을 사용하여 private anonymous mapping 세그먼트를 생성한다. 주된 목적은 새 메모리(0으로 채워짐)를 할당하는 것으로, 이 새 메모리는 프로세스를 호출하여 독점적으로 사용된다.
/* Private anonymous mapping example using mmap syscall */
#include <stdio.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
void static inline errExit(const char* msg)
{
printf("%s failed. Exiting the process\n", msg);
exit(-1);
}
int main()
{
int ret = -1;
printf("Welcome to private anonymous mapping example::PID:%d\n", getpid());
printf("Before mmap\n");
getchar();
char* addr = NULL;
addr = mmap(NULL, (size_t)132*1024, PROT_READ|PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (addr == MAP_FAILED)
errExit("mmap");
printf("After mmap\n");
getchar();
/* Unmap mapped region. */
ret = munmap(addr, (size_t)132*1024);
if(ret == -1)
errExit("munmap");
printf("After munmap\n");
getchar();
return 0;
}
# ./mmap
Welcome to private anonymous mapping example::PID:20139
Before mmap
- mmap 이전: 공유 라이브러리
libc.so
와ld-linux.so
에 속한 메모리 매핑 세그먼트만 볼 수 있다.
# cat /proc/20139/maps
08048000-08049000 r-xp 00000000 08:01 1032542 /home/iamroot/workspace/heap/mmap
08049000-0804a000 rw-p 00000000 08:01 1032542 /home/iamroot/workspace/heap/mmap
b7e98000-b7e99000 rw-p b7e98000 00:00 0
b7e99000-b7fd4000 r-xp 00000000 08:01 886016 /lib/tls/i686/cmov/libc-2.5.so
b7fd4000-b7fd5000 r--p 0013b000 08:01 886016 /lib/tls/i686/cmov/libc-2.5.so
b7fd5000-b7fd7000 rw-p 0013c000 08:01 886016 /lib/tls/i686/cmov/libc-2.5.so
b7fd7000-b7fda000 rw-p b7fd7000 00:00 0
b7fe3000-b7fe7000 rw-p b7fe3000 00:00 0
b7fe7000-b8000000 r-xp 00000000 08:01 851989 /lib/ld-2.5.so
b8000000-b8002000 rw-p 00019000 08:01 851989 /lib/ld-2.5.so
bffeb000-c0000000 rw-p bffeb000 00:00 0 [stack]
ffffe000-fffff000 r-xp 00000000 00:00 0 [vdso]
[Enter 입력]
After mmap
mmap
이후: 매핑 세그먼트가 (b7e77000 ~ b7e98000)이 이미 존재하던 매핑 세그먼트(b7e98000 ~ b7e99000)와 결합된 것을 볼 수 있다.
# cat /proc/20139/maps
08048000-08049000 r-xp 00000000 08:01 1032542 /home/iamroot/workspace/heap/mmap
08049000-0804a000 rw-p 00000000 08:01 1032542 /home/iamroot/workspace/heap/mmap
b7e77000-b7e99000 rw-p 00000000 00:00 0
b7e99000-b7fd4000 r-xp 00000000 08:01 886016 /lib/tls/i686/cmov/libc-2.5.so
b7fd4000-b7fd5000 r--p 0013b000 08:01 886016 /lib/tls/i686/cmov/libc-2.5.so
b7fd5000-b7fd7000 rw-p 0013c000 08:01 886016 /lib/tls/i686/cmov/libc-2.5.so
b7fd7000-b7fda000 rw-p b7fd7000 00:00 0
b7fe3000-b7fe7000 rw-p b7fe3000 00:00 0
b7fe7000-b8000000 r-xp 00000000 08:01 851989 /lib/ld-2.5.so
b8000000-b8002000 rw-p 00019000 08:01 851989 /lib/ld-2.5.so
bffeb000-c0000000 rw-p bffeb000 00:00 0 [stack]
ffffe000-fffff000 r-xp 00000000 00:00 0 [vdso]
- b7e77000-b7e99000은 세그먼트의 가상 주소 범위이다.
- rw-p는 Flags (읽기, 쓰기, 비실행, 비공개)이다.
- 00000000 은 파일 오프셋이다.
- 00:00 은 Major / Minor device number 이다.
- 0 은 아이 노드 번호이다.
[Enter 입력]
After munmap
munmap
이후: 매핑되었던 메모리가 해제되었음을 볼 수 있다.
# cat /proc/20139/maps
08048000-08049000 r-xp 00000000 08:01 1032542 /home/iamroot/workspace/heap/mmap
08049000-0804a000 rw-p 00000000 08:01 1032542 /home/iamroot/workspace/heap/mmap
b7e98000-b7e99000 rw-p b7e98000 00:00 0
b7e99000-b7fd4000 r-xp 00000000 08:01 886016 /lib/tls/i686/cmov/libc-2.5.so
b7fd4000-b7fd5000 r--p 0013b000 08:01 886016 /lib/tls/i686/cmov/libc-2.5.so
b7fd5000-b7fd7000 rw-p 0013c000 08:01 886016 /lib/tls/i686/cmov/libc-2.5.so
b7fd7000-b7fda000 rw-p b7fd7000 00:00 0
b7fe3000-b7fe7000 rw-p b7fe3000 00:00 0
b7fe7000-b8000000 r-xp 00000000 08:01 851989 /lib/ld-2.5.so
b8000000-b8002000 rw-p 00019000 08:01 851989 /lib/ld-2.5.so
bffeb000-c0000000 rw-p bffeb000 00:00 0 [stack]
ffffe000-fffff000 r-xp 00000000 00:00 0 [vdso]