새소식

💻 Computer/🐧 Linux

[Linux] 리눅스의 메모리 구조 (1)

  • -

 

리눅스의 메모리 구조

메모리 구조

 

Linux의 메모리 구조에는 Code 세그먼트, Data 세그먼트, BSS 세그먼트, Heap 세그먼트, Stack 세그먼트

이렇게 5가지의 세그먼트가 있다. 각 세그먼트마다 읽기, 쓰기, 실행에 대한 권한이 부여되어 있어 취약점을 어느 정도 방지할 수 있다.

 

 

Code 세그먼트

Text 세그먼트라고도 불리며, 프로그램에서 실행 가능한 코드가 Text 세그먼트에 위치하게 된다. 코드 세그먼트는 CPU가 코드를 읽고 실행할 수 있도록 읽기 권한과 실행 권한이 부여된다.

 

하지만 쓰기 권한은 부여되지 않는다 왜일까?

누군가가 악의 적으로 실행 흐름을 바꿀 수도 있기 때문에 쓰기 권한은 부여되지 않는다고 한다

 

 

Data 세그먼트

Data 세그먼트는 컴파일 할때 코드에서 초기화된 전역 변수또는 전역 상수를 저장한다. Data 세그먼트에는 알아야 할 것이 하나 있다.

 

위에서 말했듯이 Data세그먼트는 전역 변수 또는 전역 상수를 저장하는데 여기서 살짝 헷갈리는 부분이 나온다.

그것이 (read only data; rodata)이다

 

Rodata 세그먼트는 쓰기가 불가능한 전역 상수 변수를 저장한다

 

int a = 10 //Data Segment

char b[] = "Hello wolrd" //Data Segment

const char c[] = "I Love You" //Rodata

char *ptr = "it's me rodata?" //Rodata

int main(void){...}

아마 *ptr부분이 왜 그런지 헷갈릴 것이다. 그럼 이유를 설명해 볼 테니 정신 바짝 차리길 바란다.

 

자 설명하기 전에 문자열 상수라는 것을 알아야 한다 간단한 예시를 들겠다

char *s1 = "hello world"   //문자열 상수

char s2[] = "hello world"  //배열

s1은 프로그램이 로딩될 때 정적 영역(rodata)에 "hello world"를 저장한 다음 문자열의 시작 주소를 s1포인터 변수에 대입한다. 문자열 포인터 s1에는 나중에 다른 주소 값을 대입할 수 있다, 즉 s1자체는 Data 세그먼트이다 그런데 s1의 "hello world"는 Rodata에 저장되어 있어 값을 변경할 수 없다

 

s1이 rodata영역에 있는 "hello world"의 주소를 가지고 있다

이런 느낌이 아닐까?

 

그렇다면 s2는 뭐가 다르길래?? 이러는 것일까??? 매우 다르다

s2는 이따 설명할 Heap 메모리를 할당한 후 "hello world"를  Heap 메모리에 저장했다

s2는 Heap 메모리에 있는 "hello world"의 시작 주소를 가지고 있는 것이다!!

 

그렇다면 값을 한번 바꿔보자 strcpy를 사용해 보도록 하자

 

#include <stdio.h>
#include <string.h>

char *s1 = "hello world"; //rodata
char s2[] = "hello world"; //data

int main(void){
	
	strcpy(s1, "hello");
	
	printf("%s", s1);
	
}

//console
//아무것도 뜨지 않는다

왜 위와 같은 결과가 나온 걸까? 

strcpy(s1, "hello") s1에 hello를 복사한다는 것인데 이 말은 rodata에 있는 "hello world"라는 문자열을 바꾸려고 하는 것이다 하지만 우리의 rodata는 그것을 허락하지 않기 때문에 위와 같은 상황이 나오는 것이다 

 

그럼 바꾸기 위해서는 어떻게 해야 하는 것일까? 밑의 코드를 보자

 

#include <stdio.h>
#include <string.h>

char *s1 = "hello world"; //rodata
char s2[] = "hello world"; //data

int main(void){
	
	s1 = "hello";
	
	printf("%s", s1);
	
}


//console
//hello

위의 코드는 문자열 포인터 변수 s1에게 시작할 때 Heap메모리에 저장한 "hello"의 주소 값을 대입해주는 것이다

rodata의 값을 바꾸지 않고 주소 값만 바꾸어 주었기 때문에 우리가 생각한 대로 결과가 나와 주었다

 

처음 보면 "무슨 소리야??" 하는 생각 들것이다 당연하다고 말해 주고 싶다.

나도 이 글을 쓰면서 대충 넘어갔던 부분을 확실하게 이해할 수 있었다.

글을 쓰며 이해하는 것도 방법 중에 하나인 것 같다

 

 

글이 너무 길어져 2개로 나눠야 할 것 같다 다음 편도 길어지면 또 나눠야 할지도....

 

 

정리
  Code Segment Data Segment Rodata
권한 읽기, 실행 쓰기, 읽기 읽기

 

 

참고한 사이트

https://hackyboiz.github.io/2022/01/14/poosic/linux-memory-layout/

 

hackyboiz

hack & life

hackyboiz.github.io

'💻 Computer > 🐧 Linux' 카테고리의 다른 글

[Linux] File  (2) 2022.09.26
[Linux] 리눅스의 메모리 구조 (2)  (0) 2022.09.18
[Linux] Directory Command  (0) 2022.09.04
[Linux] 기본 환경  (0) 2022.09.03
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.