Linux/Linux_technic

/proc/pid/maps : 파일 프로세스의 메모리 공간

sosal 2011. 1. 29. 22:34
반응형
/*
 http://sosal.tistory.com/
 * made by so_Sal
 */

- 프로그램 안에서, Code segment, data segment,
                          stack segment, heap segment, .bss 등을 살펴보겠습니다.

"유닉스 계열은 모든 것이 파일, 프로세스 이다. " 라는 말을 무수히 들어보셨을 것입니다.
그렇다면 중요한 정보들이 어디에 파일로 저장되어 자리하고 있는지 알게된다면
쉽게 정보들을 찾을 수 있을 것 같습니다.

proc : process의 줄임말이며, 이곳에 프로세스의 정보들이 저장됩니다.
사용자 프로세스의 정보들을 이곳에서 얻을 수 있으며 심지어 조작도 가능하다는 점에서
/proc 파일시스템은 굉장히 유용합니다.




위 그림에서 보는바와 같이 (pstree 명령어) 모든 프로세스의 부모 프로세스는 1 (init) 프로세스입니다.
하지만 이녀석이라고 특별하지는 않습니다. ls 명령어를 쳐보니 역시 다른 프로세스와 마찬가지로
프로세스 정보들을 가지고 있는 파일들이 주루룩 뜨네요.

proc 디렉토리에서 ls 결과입니다.


/proc/self : 현재 실행되고 있는 프로세스의 정보가 담겨있는 디렉토리



그럼 프로그램을 만들어, maps에 어떤 정보들이 저장되는지 확인 해 볼까요?



실행하면, maps 주소까지 보여줍니다.


<실행결과>
Address of function main is :  0x8048414 // code segment
Address of gloval value is : 0x8049708  // data segment
Address of local value is : 0xbfcd4180  // stack

<maps>
메모리 위치         | 권한 | offset | device | inode / path
08048000-08049000 r-xp 00000000 fd:00 3999505    /home/sosal/Desktop/trash/sleep
08049000-0804a000 rw-p 00000000 fd:00 3999505    /home/sosal/Desktop/trash/sleep
b7ef3000-b7ef5000 rw-p b7ef3000 00:00 0
b7f01000-b7f02000 rw-p b7f01000 00:00 0
bfcc1000-bfcd6000 rw-p bffea000 00:00 0          [stack]

main함수의 주소가 <maps>의 첫번째 주소 사이에 위치한 사실을 알 수 있습니다.
이 사실은 GDB와 같은 디버거를 사용하여 프로그램을 디버깅 하는경우 중요합니다.
// Code segment 영역으로, r-xp 읽기, 실행 권한이 주어져있음. (실행명령어 저장장소)

두번째, gloval value의 주소가 <maps>의 두번째 주소에 위치한 사실을 알 수 있습니다..
이곳은 data segment로, rw-p 읽기 쓰기 권한이 주어져있습니다.. (데이터 저장장소)
전역변수 이외에도 스택변수, 힙변수가 있는데 이 데이터들은 다른곳에 저장됩니다..

스택변수로 local_value는 [stack] 이라는 경로에 저장되는데,
스택은 높은주소에서 낮은주소로 내려가게됩니다..
즉, 이번 주소가 0xbfcd4180 이었다면, 다음 4바이트 변수의 주소는 0xbfcd417c 일것입니다.

다음의 소스에서 bss와 Heap segment를 살펴보겠습니다.


실행결과

Heap segment는 힙 변수를 저장합니다.
new(), malloc()와 같은 API를 통해 동적으로 할당한 메모리들이 힙 변수입니다.
malloc, new 등의 API는 brk() 세스템 호출을 통해
세그먼트 끝을 연장하여 요청받은 메모리를 할당합니다.
이 세그먼트에는 bss 섹션도 들어있는데, 초기화되지 않는 전역변수들이 저장되는곳입니다.
하지만 위 프로그램 결과에서는 bss가 힙 세그먼트에 저장되어있지 않고, 데이터 세그먼트에 있는데
전역변수의 수가 작은탓에 데이터세그먼트 끝에 사용하지 않는 공간이 생겼기 때문에
OS가 낭비되는 공간을 줄이는 과정에서 생긴 결과입니다.

readelffh bss 섹션위치를 살펴봐도, bss전역변수가 .bss 위치에 있다는것을 알 수 있습니다.


brk 포인터는 현재 설정된 데이터 세그먼트 최하위 주소이며, 인수 0을주고 sbrk() 를 호출하여 얻습니다.
(brk도 bss 전역변수와 같이 데이터 세그먼트에 저장될 수 있다.)

malloc 호출 이후에, heapseg 항목이 생긴걸로 봐서,
동적으로 세그먼트 끝을 연장했다는 사실을 알 수 있습니다.
malloc(1024) -> sbrk 포인터가 0x1000 크기만큼 증가함

참고도서 : 리눅스 문제분석과 해결 | 에이콘