기본 콘텐츠로 건너뛰기

Memory-Layout-of-C

C 프로그램 메모리 구조

C 프로그램 메모리 구조는 일반적으로 다음의 섹션으로 나타낸다.
- Text segment
- Initialized data segment
- Uninitialized data segment
- Stack
- Heap

high address+----------------------+
            |                      |command+line arguments
            |                      |and environment variables
            +----------------------+
            |  stack               |
            |         +            |
            |         |            |
            |         v            |
            |                      |
            |         ^            |
            |         |            |
            |         +            |
            |  heap                |
            +----------------------+
            |  uninitialized data  |initialized to
            |  (bss)               |zero bt exec
            +----------------------+
            |  initialized data    |read from
            +----------------------+program file
            |  text                |by exec
 low address+----------------------+

Text segment

Text Segmnt는 Code Segment나 간단히 Text라고 불리는 섹션으로 실행 명령어로 구성된다. 메모리 영역에서 Text segment는 Heap이나 Stack의 아래에 위치하여 heap, stack overflow 및 overwriting을 막는다. 보통 텍스트 에디터, 컴퍼일러, 쉘와 같이 빈번히 실행되는 프로그램은 Text segment에 한번만 복사하여 단일 복사본을 공유한다. 또한 Text segment는 읽기 전용 제공되어 프로그램의 명령어 수정을 막는다.

Initialized data segment

Initialized data segment는 보통 Data Segment로 불린다. Data segment는 프로그램의 가상 메모리 역역에 위치하여 프로그래머가 초기화한 전역 변수나 정적 변수를 포함한다. 프로그램이 실행되는 동안 변수 값이 변경되므로 Data segment는 읽기 전용이 아니다. 이 섹션은 초기화된 읽기 전용 영역과 초기화된 읽기/쓰기 영역으로 분류할 수 있는데, 예를 들어 C에서 char s[] = "hello world"로 정의된 전역 문자열과 외부(전역)의 int debug = 1 같은 명령문은 초기화된 읽기/쓰기 영역에 저장된다. 그리고 const char * string = "hello world"와 같은 C 명령문은 “hello world” 문자열 그대로를 초기화된 읽기 전용 영역에 저장하고 문자 포인터 변수 문자열 값을 초기화된 읽기/쓰기 영역에 저장한다.

Ex. static int i = 10과 globalint i = 10은 Data segment에 저장된다.

Uninitialized data segment

Uninitialized data segment는 오래된 어셈블러 연산자 “block started by symbol”의 이름을 따서 bss segment라고 불린다. 이 세그먼트의 데이터는 프로그램이 실행되기 전에 커널에 의해 산술 값 0으로 초기화된다. Uninitialized data는 Data segment 끝에서 시작하며 소스코드 상에서 초기화되지 않았거나, 0으로 초기화한 모든 전역 변수와 정적 변수를 포함한다.

Ex. static int i;나 globalint j;는 BSS segment에 포함된다.

Stack

Stack 영역은 Heap 영역과 인접해있으며 반대 방향으로 확장된다. 여유 메모리 공간이 고갈된다면 Stack 포인터와 Heap 포인터가 만나게 된다. (현대의 큰 주소 공간과 가상 메모리 기법을 사용하여 거의 모든 곳에 배치할 수 있지만, 일반적으로 반대 방향으로 성장한다.)
Stack 영역은 LIFO 구조로 일반적으로 높은 주소 영역에 위치해있다. PC x86 컴퓨터 시스템 구성에서 0주소를 향해 확장된다. (반대 방향으로 확장하는 시스템 구성도 존재한다.) Stack 포인터 레지스터는 스택의 꼭대기에서 나아가며, 값이 스택에 PUSH 될 때 마다 조정된다. 함수 호출에 의해 PUSH된 값의 집합을 Stack Frame이라고 하며 Stack Frame에는 최소한 return address가 포함된다.
Stack은 자동으로 함수 호출 시 정보와 변수가 자동 저장되는 곳이다. 함수가 호출될 때마다 호출자의 환경에 대한 정보와 컴퓨터 레지스터와 같은 특정 정보가 Stack에 저장된다. 새롭게 호출된 함수는 Stack에 자동 변수와 임시 변수를 위한 공간을 할당한다. 이는 재귀 함수가 작동되는 방식으로 재귀 함수가 자신을 호출할 때 마다 새 스택 프레임이 사용되므로 한 세트의 변수는 다른 함수 인스턴스의 변수와 간섭을 일으키지 않는다.

Heap

Heap은 주로 동적으로 메모리 할당한다. Heap은 BSS segment 끝에서 시작하여 높은 주소 방향으로 확장된다. Heap 영역은 malloc, realloc, free에 의해 관리되며, brk 및 sbrk 시스템 호출을 사용하여 크기를 조정할 수 있다. (malloc, realloc, free를 이행하기 위해서 반드시 brk 및 sbrk와 단일 Heap 역역의 사용이 동반되지는 않는다. 가상 메모리의 프로세스 가상 주소 공간이 인접하지 않게 예약하기 위해 mmap을 사용할 수 있다.)Heap 영역은 프로세스의 모든 공유 라이브러리와 동적으로 로드된 모듈에 의해 공유된다.

Example

size 명령어를 이용하여 text, data, bss segment의 크기(byte)를 살펴보자.

  • 간단한 C 프로그램을 살펴보자.
#include <stdio.h>

int main(void)
{
    return 0;
}
[narendra@CentOS]$ gcc memory-layout.c -o memory-layout
[narendra@CentOS]$ size memory-layout
text       data        bss        dec        hex    filename
960        248          8       1216        4c0    memory-layout
  • 프로그램에 전역 변수를 추가하고 bss 크기를 확인하자.
#include <stdio.h>

int global; /* Uninitialized variable stored in bss*/

int main(void)
{
    return 0;
}
[narendra@CentOS]$ gcc memory-layout.c -o memory-layout
[narendra@CentOS]$ size memory-layout
text       data        bss        dec        hex    filename
 960        248         12       1220        4c4    memory-layout
  • 정적 변수 하나를 추가하고 bss에 저장되는 것을 확인하자.
#include <stdio.h>

int global; /* Uninitialized variable stored in bss*/

int main(void)
{
    static int i; /* Uninitialized static variable stored in bss */
    return 0;
}
[narendra@CentOS]$ gcc memory-layout.c -o memory-layout
[narendra@CentOS]$ size memory-layout
text       data        bss        dec        hex    filename
 960        248         16       1224        4c8    memory-layout
  • 초기화한 정적 변수가 Data segment에 저장되는 것을 확인하자.
#include <stdio.h>

int global; /* Uninitialized variable stored in bss*/

int main(void)
{
    static int i = 100; /* Initialized static variable stored in DS*/
    return 0;
}
[narendra@CentOS]$ gcc memory-layout.c -o memory-layout
[narendra@CentOS]$ size memory-layout
text       data        bss        dec        hex    filename
960         252         12       1224        4c8    memory-layout
  • 초기화된 전역 변수가 Data segment에 저장되는 것을 확인하자.
#include <stdio.h>

int global = 10; /* initialized global variable stored in DS*/

int main(void)
{
    static int i = 100; /* Initialized static variable stored in DS*/
    return 0;
}
[narendra@CentOS]$ gcc memory-layout.c -o memory-layout
[narendra@CentOS]$ size memory-layout
text       data        bss        dec        hex    filename
960         256          8       1224        4c8    memory-layout

이 블로그의 인기 게시물

Remove-Server-Header

응답 메시지 내 서버 버전 정보 제거 1. Apache 1) 조치 방법 “/etc/htpd/conf/httpd.conf” 파일 안에서 1. ServerTokens OS → ServerTokens Prod 2. ServerSignature On → ServerSignature Off 로 변경한 후 아파치를 재시작하면 헤더 값의 아파치 버전 정보 및 OS 정보를 제거할 수 있다. 2) 참고 URL http://zetawiki.com/wiki/CentOS_ 아파치_보안권장설정_ServerTokens_Prod,_ServerSignature_Off 2. IIS 1) 조치 방법 IIS 6.0 urlscan_setup 실행. 설치. \windows\system32\inetsrv\urlscan\urlscan.ini 파일을 열어 다음 수정(RemoveServerHeader=0 을 RemoveServerHeader=1 로 변경) 서비스에서 IIS Admin Service 재시작. IIS 7.0 IIS 관리자를 열고 관리하려는 수준으로 이동합니다. 기능 보기에서 HTTP 응답 헤더를 두 번 클릭합니다. HTTP 응답 헤더 페이지에서 제거할 헤더를 선택합니다. 작업 창에서 제거를 클릭하고 예를 클릭합니다. 2) 참고 URL IIS 6.0 : http://gonnie.tistory.com/entry/iis6- 응답헤더-감추기 IIS 7.0 : https://technet.microsoft.com/ko-kr/library/cc733102(v=ws.10).aspx 3. jetty 1) 조치 방법 “jetty.xml” 파일에서 jetty.send.server.version=false 설정 2) 참고 URL http://attenuated-perspicacity.blogspot.kr/2009/09/jetty-61x-hardening.html 4. Nginx

X-Frame-Options-Test

X-Frame-Options 테스트하기 X-Frame-Options 페이지 구성 시 삽입된 프레임의 출처를 검증하여 허용하지 않는 페이지 URL일 경우 해당 프레임을 포함하지 않는 확장 응답 헤더이다. 보안 목적으로 사용되는 확장 헤더로 아직 적용되지 않은 사이트들이 많지만 앞으로 점차 적용될 것으로 보인다. X-Frame OptionsDENY, SAMEORIGIN, ALLOW-FROM 옵션을 이용하여 세부 정책을 설정한다. 옵션 설명 DENY Frame 비허용 SAMEORIGIN 동일한 ORIGIN에 해당하는 Frame만 허용 ALLOW-FROM 지정된 ORIGIN에 해당하는 Frame만 허용 크롬 4.1 , IE 8 , 오페라 10.5 , 사파리 4.0 , 파이어폭스 3.6.9 이상에서는 DENY , SAMEORIGIN 이 적용되며, ALLOW-FROM 은 각 브라우저 마다 지원 현황이 다르다. https://developer.mozilla.org/ko/docs/Web/HTTP/Headers/X-Frame-Options 해당 확장헤더는 브라우저에서 처리하는 응답 헤더이므로 미지원 브라우저 사용 시 설정과 무관하게 페이지 내 포함된 모든 Frame을 출력한다. (검증 테스트: Opera 5.0.0) 테스트 코드 DENY <!DOCTYPE html> < html lang = "en" > < head > < meta http-equiv = "X-Frame-Options" content = "deny" /> < title > Deny option Test </ title > </ head > < bod

데일 카네기 인간관계론 정리