2010. 5. 13. 20:46

메모리에 할당이 되지만 값을 변경할 수 없는 메모리 영역?


다음은 어떤 데브피아 유저가 질문한 내용에 제가 답변한 글입니다.

-------------------------------------------------------------------------------------

제가 보고 있는 c 언어 책의 포인터와 문자열 부분에서 ...

char *p = "abcde";

"abcde" 는 메모리 어딘가에 문자열 리터럴로 보관되어 있다.

그런데, 메모리에 할당하기는 하지만 값을 변경할 수 없는 메모리 영역에 보관된다고 하는데 ...

어떤 영역인가요 ?

제가 메모리 영역에 대해서 잘 몰라서 질문을 드립니다.

-------------------------------------------------------------------------------------

.rdata라는 섹션에 저장됩니다. PE File View 혹은 PE File Explorer라는 툴(실행 파일 분석툴)을

사용하여 해당 파일을 열어 보시면 .rdata라는 섹션에 저장되어 있습니다. 실행 파일은 여러 개의

섹션(영역)과 그 섹션에 대한 정보를 가지는 구조로 이루어져 있습니다. 또한 각각의 섹션은 초기화,

읽기, 쓰기, 데이터, 텍스트 등의 고유한 속성에 대한 정보를 가지고 있습니다.  실행 파일이 실행될

때, 파일의 이미지가 메모리에 동일하게 맵핑됩니다. .rdata 섹션의 속성은 READ ONLY, DATA로

설정되어 있기 때문에 해당 영역에 쓰려고 할 때, 커널은 속성을 체크하고 위배되면 엑세스 위반을

일으키게 됩니다. 물론, .rdata 섹션의 속성을 쓰기로 변경하면 쓰기도 가능합니다. 이렇게 읽기

전용 데이터 섹션을 설정한 이유는 동일한 상수를 여러 곳에서 참조하기 때문이지요. 이것은 아주

당연한 이유입니다. 한곳에서 수정이 가해지면 해당 리터럴 상수를 참조하고 있는 다른 곳에서도

영향을 주기 때문입니다. Win32 운영체제는 실행 파일을 .rdata, .data, .idata, .text, .rsrc 등의

여러가지 섹션으로 코드와 데이터를 나누어 관리하고 있습니다. 이렇게 섹션을 나누어 관리하는

이유는 로더가 각 영역을 커널에서 정한 레이아웃에서 엑세스하는 데이터 및 코드를 쉽게 맵핑하고

사용하기 위함입니다. 그리고 컴파일러는 리터럴 상수를 경우에 따라 프로세스를 생성시 매번

할당하는 것이 아니라, data 섹션이 아닌 text 섹션에 직접 쓰기도 합니다. 이것은 할당 및 엑세스

속도를 빠르게 하기 위함입니다. 여기서 정확한 표현은 Segment보다는 Section으로 보는 것이

옳습니다.
그리고 위에서 님이 말씀하신 것처럼 동일한 위치를 가리키는 이유는 단순히 컴파일러

입장에서 최적화를
위한 것입니다. 동일한 상수를 .rdata 영역에 여러번 할당하는 것이 낭비고 어차피
 
변경 불가능하고
참조만 되어지는 대상이기 때문에 두 개의 포인터가 하나의 리터럴 상수를 가리켜도

전혀 문제될 것이 없습니다.
두번째로 질문하신 내용에 대한 답변을 드리겠습니다.

디버기 프로세스가 되지 않고 파일 접근이 아닌 이상, 해당 프로세스에서 실제 그 영역 속성의 변경은

불가능하지만, 페이지 속성 변경 및 CopyOnWrite 메커니즘으로 .rdata에 쓸 수가 있습니다.

DWORD dwReadData = 0;

char *pString = "Hello";

VirtualProtect( pString, 4096, PAGE_READWRITE, &dwReadData );

*pString = 'P';


Written By Simhyeon, Choe