기본 콘텐츠로 건너뛰기

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

이 블로그의 인기 게시물

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

C-lang-vulnerabilities

C 언어 공통 취약점 해당 글은 CERN Computer Security의 Common vulnerabilities guide for C programmers 글을 참고하여 작성하였습니다. C언어에서 발생하는 대부분의 취약점은 버퍼 오버플로우와 문자열 처리 미흡과 관련되어 있다. 이는 segmentation fault를 유발하고 입력 값을 조작할 경우 임의 코드 실행으로 이어질 수 있다. 이에 대부분의 에러와 조치 방안을 살펴보자고 한다. gets stdio gets() 함수는 버퍼 길이를 검증하지 않아 사용 시 항상 취약성을 야기한다. Vulnerable Code #include<stdio.h> int main() { char username[ 8 ]; int allow = 0 ; printf ( "Enter your username, please: " ); gets(username); //악의적인 값 삽입 if (grantAccess(username)) { allow = 1 ; } if (allow != 0 ) { //username을 오버플로우하여 덮어씀 privilegeAction(); } return 0 ; } Mitigation fgets() 함수 사용 및 동적 메모리 할당 #include <stdio.h> #include <stdlib.h> #define LENGTH 8 int main () { char * username, *nlptr; int allow = 0 ; username = malloc (LENGTH * sizeof (*username)); if (!username) return EXIT_FAILURE; printf ( "Enter your username, please:

HTML/CSS를 활용하여 카카오톡 클론 만들기

시간을 내어 HTML과 CSS를 공부한 것은 대학생 때가 마지막이었던 것으로 기억한다. 그 동안 사이드 프로젝트로 진행했던 여러 아이디어들을 결국 서비스하지 못했던 결정적인 이유는 프론트 엔드 기술 부족이었다고 생각하고 우선 HTML과 CSS 학습을 진행하였다. 프론트 엔드 기술은 많은 발전을 거듭하여 예전에 비해 큰 복잡성을 가지게 되었다. 빠른 시간 안에 숙지하지 못한 기법들에 대해서 알아보고 구현하고자 하는 아이디어에 활용할 수 있을 정도로 진행해보고자 한다. 또한 보안적 관점에서 발생할 수 있는 프론트 엔드 위협에 대해 파악할 수 있는 좋은 밑거름이 되길 기대해본다. 우선적으로 진행한 카카오 톡 디자인 클론은 노마드 아카데미의 강의를 수강하며 진행하였고 결과는 아래의 링크에서 확인할 수 있다. 소스코드 저장소 구현된 웹 페이지