minhui study

week3(2) - 메모리 구조와 레지스터 종류 본문

컴퓨터 구조/Swing study

week3(2) - 메모리 구조와 레지스터 종류

minhui 2020. 5. 20. 18:19

< 메모리 구조 >

 

프로그램이 실행되기 위해서는 먼저 프로그램이 메모리에 로드되어야 한다. 또한, 프로그램에서 사용되는 변수들을 저장할 메모리도 필요하다. 따라서 컴퓨터의 운영체제는 프로그램의 실행을 위해 다양한 메모리 공간을 재공하고 있는데 프로그램이 운영체제로부터 할당받는 대표적인 메모리 공간은 다음과 같다.

 

http://tcpschool.com/c/c_memory_structure

1. 코드(code) 영역

: 실행할 프로그램의 코드가 저장되는 영역으로 텍스트 영역이라고도 부른다.

  

  - 프로그램이 시작하고 끝날 때까지 메모리에 계속 남아있는다.

  - 당연히 컴파일 된 기계어가 들어가게 된다.

  - CPU는 코드 영역에 저장된 명령어를 하나씩 가져가서 처리하게 된다.

 

 

2. 데이터(data) 영역

: 프로그램의 전역 변수와 정적(static) 변수, 문자열 상수가 저장되는 영역이다.

 

  - 프로그램의 시작과 함께 할당되며, 프로그램이 종료되면 소멸한다.

 

 

3. 스택(stack) 영역

: 함수의 호출과 관계되는 지역 변수와 매개변수가 저장되는 영역이다.

 

  - 함수의 호출과 함께 할당되며 함수의 호출이 완료되면 소멸한다. 이렇게 스택 영역에 저장되는 함수의 호출 정보를 스택 프레임(stack frame)이라고 한다.

  - 스택 영역은 push동작으로 데이터를 저장하고 pop동작으로 데이터를 인출한다. 이러한 스택은 후입선출(LIFO, Last-in- First-Out) 방식에 따라 동작하므로 가장 늦게 저장된 데이터가 가장 먼저 인출된다.

  - 메모리의 높은 주소에서 낮은 주소의 방향으로 할당된다.

  - 컴파일 시에 크기가 결정된다.

 

※ 스택 프레임(Stack frame)

  : 스택 영역에 차례대로 저장되는 함수의 호출 정보를 스택 프레임이라고 하는데 이것 덕분에 함수의 호출이 모두 끝난 뒤에 해당 함수가 호출되기 이전 상태로 되돌아갈 수 있다.

 

 -> 스택 프레임의 동작 방식

int main(void){
	func1(); // func1() 호출
    return 0;
}

void func1(){
	func2(); // func2() 호출
}

void func2(){}

http://tcpschool.com/c/c_memory_stackframe
http://tcpschool.com/c/c_memory_stackframe

 

 

 

 

4. 힙(heap) 영역

  : 사용자가 직접 관리할 수 있고 해야만하는 메모리 영역

 

  - 힙 영역은 사용자에 의해 메모리 공간이 동적으로 할당되고 해제된다.

  - 메모리의 낮은 주소에서 높은 주소의 방향으로 할당된다.

  - malloc() 또는 new연산자를 통해 할당하고 free() 또는 delete 연산자를 통해서 해제가 가능하다.

  - 런타임 시에 크기가 결정된며 이 공간에 메모리 할당하는 것을 동적 할당이라고 부른다.

 

   * malloc() 함수

     : malloc()함수는 인수로 할당받고자 하는 메모리의 크기를 바이트 단위로 전달받는데 주소값을 반환하기 때문에 힙 영역에 할당된 메모리 공간으로 접근하려면 포인터를 사용해야 한다..

   

 

   * free() 함수

     : free() 함수는 힙 영역에 할당받은 메모리 공간을 다시 운영체제로 반환해 주는 함수이다. 데이터 영역이나 스택 영역에 할당되는 메모리의 크기는 컴파일 타임에 결정되어 프로그램이 실행되는 내내 고정되는데 비해 메모리의 동적 할당으로 힙 영역에 생성되는 메모리의 크기는 런 타임 내내 변화된다.

따라서 free() 함수를 사용하여 다 사용한 메모리를 해제해 주지 않으면 메모리가 부족해지는 현상이 발생할 수 있는데 이처럼 사용이 끝난 메모리를 해제하지 않아서 메모리가 부족해지는 현상을 메모리 누수라고 한다.

 

 

Stack vs Heap

   : Stack 영역이 클수록 Heap 영역이 작아지고 Heap 영역이 클수록 Stack영역이 작아진다.

     스택 할당 속도와 힙 할당 속도를 비교해보면 스택이 훨씬 빠르다. 

     스택은 이미 할당 되어있는 공간을 사용하는 것이고 힙은 사용자가 따로 할당해서 사용하는 공간이다.

  

Overflow

   : Stack의 지역변수는 사용되고 소멸하기 때문에 데이터 용량의 불확실성을 가진다. 따라서 Stack 영역에서의 주소값은 밑에서부터 채워지며 그 다음 주소는 선언된 순서대로 정해진다. 

반면 Heap 영역에서의 주소값은 위에서부터 채워 내려지기 때문에 두 메모리 영역의 주소가 겹치게 되는 Overflow가 발생할 수도 있게 된다. 

https://jinshine.github.io/2018/05/17/%EC%BB%B4%ED%93%A8%ED%84%B0%20%EA%B8%B0%EC%B4%88/%EB%A9%94%EB%AA%A8%EB%A6%AC%EA%B5%AC%EC%A1%B0/

   -> Heap Overflow 

      : Heap이 위에서부터 주소값을 채워져 내려오다가 Stack영역을 침범하는 경우

 

   -> Stack Overflow

      : Stack영역이 Heap을 침범하는 경우

      : 해당 스택 영역을 넘어가도 데이터가 저장될 수 있으면 보안상의 크나큰 취약점을 가지게 되므로 실행 중인 프로그램에서 스택 오버플로우가 발생하면, 에러를 발생시키고 곧바로 강제 종료시킨다.

ㅐ당http://tcpschool.com/c/c_memory_stackframe

 

  

기억장소 이름 들어오는 데이터 관리방식
스택 영역 지역 변수 동적
힙 영역 동적할당된 메모리 동적
데이터 영역 정적변수와 상수 정적
코드 영역 함수 정적

 

 

 

< 레지스터의 종류 >

 

범용 레지스터(General-Purpose Register)

   : 컴퓨터의 CPU 내에 있으며 연산처리, 연산결과, 복귀주소 등 작은 데이터를 기억하는 레지스터이다.

   : 범용 레지스터에는 8개의 레지스터가 존재하고 있다. 

https://securityfactory.tistory.com/182

 

    (1) EAX 레지스터(Accumulator Register)

       - 주로 산술 연산과 리턴 값을 전달하기 위해 사용되며 상대적으로 사용되어 값이 자주 변하기 때문에 값을 보존하는 용도로 사용하지 않는다. 

       - 산술 연산으로는 곱셈이나 나눗셈, 덧셈, 뺄셈 등 대부부의 경우 EAX에 해당 값이 들어있는 경우가 많다.

       - 

 

    (2) ECX 레지스터 (Counter Register)

       - 반복문으로 인해 나타난 루프에서 반복의 횟수를 제어할 때에 주로 사용이 된며, EAX와 같이 많은 연산에 사용될 수도 있다.

 

     (3) EDX 레지스터 (Data Register)

      - EAX와 함께 연산 작업에 주로 사용되며, 특히 나눗셈의 경우 소수를 EDX를 넣어서 연산하며 연산 결과 몫은 EAX에 나머지는 EDX에 입력된다.

 

    (4) EBX 레지스터(Base Index Register)

        - 베이스 인덱스를 지정하는 용도로 사용되지만, 다른 레지스터 또한 베이스 인덱스를 지정하는데 자주 사용된다. 따라서 EBX는 특정한 역할을 갖기보다는 주로 변하지 않는 값을 저장할 때 사용된다. ex) 메모리 주소

 

    (5) ESI 레지스터 (Source Index Register) 

        - 데이터 복사나 조작 시 Source Data의 주소가 저장된다. ESI 레지스터가 가리키는 주소의 데이터를 EDI레지스터가 가리키는 주소로 복사하는 용도로 많이 사용한다.

 

   (6) EDI 레지스터(Destination Index)

       - 복사 작업 시 Destination의 주소가 저장된다. 주로 ESI 레지스터가 가리키는 주소의 데이터가 복사된다. 

 

    (7) EIP 레지스터 (Instruction Pointer)

       - EIP에는 다음에 실행해야 할 명령어가 존재하는 메모리 주소가 저장된다.

       - 현재 명령어를 실행 완료한 후 EIP레지스터에 저장되어 있는 주소에 위치한 명령어를 실행하게 된다. 

* EAX, EBX, ECX, EDX의 주사용 용도는 데이터를 저장하고, ESP, EBP, ESI, EDI의 주사용 용도는 주소를 저장한다.

 

 

포인터 레지스터(Pointer Register)

   : 포인터 레지스터에는 32비트 EIP, ESP, EBP가 있고 오른쪽의 16비트 부분은 각각 IP, SP, BP이다.

   

   (1) SP 레지스터 (Stack)

      - 32비트인 ESP의 오른쪽 16비트 부분이다. SS 레지스터와 연관될 때 하나의 스택 프레임의 끝 지점 주소가 저장된다. PUSH, POP 명령어에 따라 ESP의 값이 4byte씩 변하므로 유동적이다.

 

   (2) BP 레지스터 (Base)

     - 32비트인 EBP의 오른쪽 16비트 부분이다. 하나의 스택 프레임의 시작 지점 주소가 저장된다. 현재 사용되는 스택 프레임이 소멸되지 않는 동안 EBP의 값은 변하지 않으므로 기준점이 된다.

 

* 하나의 스택 프레임에 있어서 ESP는 스택의 끝 위치를 나타내며 EBP의 경우 스택의 시작 위치를 나타낸다.

* EBP의 경우 스택 프레임의 시작 위치 값을 갖고 있기 때문에 값이 잘 변하지 않지만, ESP의 경우 스택에 PUSH와 POP 명령어 등을 사용하기 때문에 유동적으로 값이 자주 변화한다.

 

   (3) IP 레지스터 (Instruction)

  - 32비트인 EIP의 오른쪽 16비트 부분이다. 명령어 포인터 레지스터로, 16비트 IP 레지스터는 다음에 실행될 명령어의 오프셋 주소를 포함한다. 현재 실행중인 코드 세그먼트에 속한 현재 명령어를 가리킨다는 점에서 이 레지스터는 CS 레지스터와 연관된다.

 

 

세그먼트 레지스터(Segment Register)

    : 총 6개(CS, SS, DS, ES, FS, GS)이고 각 크기는 16비트이다.

* 세그먼트는 프로그램에 정의된 특정 영역으로, 코드, 데이터, 스택을 포함한다.

https://securityfactory.tistory.com/182

    (1) CS (Code Segment)

        - 코드 세그먼트를 가리키는 레지스터로, 프로그램의 코드 세그먼트의 시작 주소를 포함한다.

        - 이 세그먼트 주소에 명령어 포인터(IP) 레지스터의 오프셋 값을 더하면, 실행하기 위해 메모리로부터 가져와야 할 명령어의 주소가 된다.

 

    (2) SS (Stack Segment)

        - 메모리 상에 스택의 구현을 가능하게 한다. 프로그램은 주소와 데이터의 임시 저장 목적으로 스택을 사용한다. 

 

    (3) DS (Data Segment)

      - 프로그램에서 정의된 데이터, 상수, 작업 영역을 포함한다. 데이터 세그먼트의 주소를 포함한다.

 

    (4)  ES (Extra Segment)

        - 보조 세그먼트 레지스터로, 데이터 수신측의 시작 부분을 포함한다. 또한 스트링 명령에 보조적으로 사용된다.

 

    (5) FS, GS

      - ES처럼 데이터를 가리키는 역할을 하며, 보조적으로 쓰인다.

 

 

플래그 레지스터(Flag Register)

  : 플래그 레지스터의 이름은 EFLAGS이며 32bit 크기이다.

  : 각 레지스터 bit마다 의미를 가지고 있고 1 또는 0의 값을 가지며 일부 bit는 시스템에서 직접 세팅하고 일부 bit는 프로그램에서 사용된 명령의 수행 결과에 따라 세팅된다.

 

https://ejrtmtm2.wordpress.com/2013/04/10/80x86-%EC%8B%9C%EC%8A%A4%ED%85%9C-cpu%EC%99%80-%EB%A0%88%EC%A7%80%EC%8A%A4%ED%84%B0-13%EB%85%84-3%EC%9B%94-22%EC%9D%BC-%EA%B0%95%EC%9D%98%EB%82%B4%EC%9A%A9/

  1) 상태 플래그

     - CF (Carry) : 연산할 때 올림수나 빌림수가 있는 경우에 1로 set되고, 아니면 0으로 리셋된다(clear).

     - PF (Parity) : 연산 결과 1비트들의 개수를 나타낸다. 그 개수가 짝수인 경우 짝수 패리티라 부르며 홀수인 경우 홀수 패리티라 한다. 

     - OF (Overflow) : 연산을 부호가 달린 숫자로 했을 때, 오버플로 혹인 언더플로가 발생한 경우에 1로 세트되고 그 이외일 때에 0으로 리셋된다.

     - AF (Auxiliary) : 8(16)비트 연산에서, 하위 4(8)비트로부터 상위 4(8)비트로 자리올림 혹은 빌림이 발생한 경우 1로 세트되고 그 이외의 경우 0으로 리셋된다. 

     - ZF (Zero) : 연산한 결과가 0으로 되었을 때에 1로 세트되고, 그 이외에 0으로 리셋된다.

     - SF (Sign) : 연산한 결과 최상의 비트가 1이 되었을 때(즉, 보수 표현으로 음수가 되었을 때) 1로 세트되고, 그 이외일 때에 0으로 리셋된다.

 

  2) 제어 플래그

      - DF (Direction) : 스트링 조작을 할 때에 이 플래그가 0이면 번지를 나타내는 레지스터값이 자동적으로 증가하고 1이면 레지스터값은 자동적으로 감소한다.

 

  3) 시스템 플래그

      - TF (Trap) : 이 플래그가 0일 때 CPU는 보통대로 명령을 실행한다.

                        : 이 플래그가 1일 때 CPU는 한 명령을 실행할 때마다 자동적으로 내부 인터럽트를 발생하고 인터럽트 처리 루틴으로 들어간다. 

      - IF (Interrupt) : 이 플래그가 0일때 INTR단자로부터의 외부 인터럽트 요구는 무시되고 1일 때에는 외부 인터럽트 요구를 받아들일 수 있게 된다. 

 

 

 

 

 



문제

더보기

1. 다음 중 스택 영역에 대한 설명으로 잘못된 것을 모두 고르시오

① 함수의 호출과 함께 할당되며 함수의 호출이 완료되면 소멸한다.

② 함수의 호출과 관계되는 전역 변수와 매개변수가 저장되는 영역이다.

③ 런타임 시에 크기가 결정된다.

④ 메모리의 높은 주소에서 낮은 주소의 방향으로 할당된다.

 

 

 

2. 다음 문장에서 빈 칸을 채우시오 
-> (        )는 힙 영역에 할당받은 메모리 공간을 다시 운영체제로 반환해 주는 함수로 이 함수를 사용하여 다 사용한 메모리를 해제해 주지 않으면 메모리가 부족해지는 현상이 발생할 수 있는데 이처럼 사용이 끝난 메모리를 해제하지 않아서 메모리가 부족해지는 현상을 (          )라고 한다.

 

 

 

3. 다음 중 포인터 레지스터가 아닌 것을 고르시오

 

① SP  ② BP  ③ IP  ④ CS

 

 

 

 

4. 다음 중 범용 레지스터에 대한 설명 중 틀린 것을 고르시오

 

① 범용 레지스터는 컴퓨터의 CPU 내에 있으며 연산처리, 연산결과, 복귀주소 등 작은 데이터를 기억하는 레지스터이다.
② EAX, EBX, ECX, EDX의 주사용 용도는 데이터를 저장하고, ESP, EBP, ESI, EDI의 주사용 용도는 주소를 저장한다.
③ ESP의 경우 스택 프레임의 시작 위치 값을 갖고 있기 때문에 값이 잘 변하지 않지만, EBP의 경우 스택에 PUSH와 POP 명령어 등을 사용하기 때문에 유동적으로 값이 자주 변화한다.
④ ECX레지스터는 반복문으로 인해 나타난 루프에서 반복의 횟수를 제어할 때에 주로 사용이 된며, EAX와 같이 많은 연산에 사용될 수도 있다.

 

 

 

5. 플래그 레지스터에서 TF가 0일 때 CPU는 한 명령을 실행할 때마다 자동적으로 내부 인터럽트를 발생하고 인터럽트 처리 루틴으로 들어간다. ( O / X )

 

 

 

답안

더보기

1. ②,

② : 스택 영역은 함수의 호출과 관계되는 전역변수가 아닌 지역변수와 매개변수가 저장되는 영역이다.

③ : 런타임 시가 아닌 컴파일 시에 크기가 결정된다.

 

 

2. free()함수, 메모리 누수

 ->  free() 함수는 힙 영역에 할당받은 메모리 공간을 다시 운영체제로 반환해 주는 함수이다. 데이터 영역이나 스택 영역에 할당되는 메모리의 크기는 컴파일 타임에 결정되어 프로그램이 실행되는 내내 고정되는데 비해 메모리의 동적 할당으로 힙 영역에 생성되는 메모리의 크기는 런 타임 내내 변화된다.

따라서 free() 함수를 사용하여 다 사용한 메모리를 해제해 주지 않으면 메모리가 부족해지는 현상이 발생할 수 있는데 이처럼 사용이 끝난 메모리를 해제하지 않아서 메모리가 부족해지는 현상을 메모리 누수라고 한다.

 

 

3. ④

  -> SP(Stack) BP(Base) IP(Instruction)는 포인터 레지스터이지만  CS는 코드 세그먼트를 가리키는 레지스터로 프로그램의 코드 세그먼트의 시작 주소를 포함하는 세그먼트 레지스터의 종류 중 하나이다.

 

 

4.

 -> EBP의 경우 스택 프레임의 시작 위치 값을 갖고 있기 때문에 값이 잘 변하지 않지만, ESP의 경우 스택에 PUSH와 POP 명령어 등을 사용하기 때문에 유동적으로 값이 자주 변화한다. 

  - SP 레지스터는 스택 프레임의 끝 지점 주소가 저장된다. PUSH, POP 명령어에 따라 ESP의 값이 4byte씩 변하므로 유동적이다. 

   - BP 레지스터는 스택 프레임의 시작 지점 주소가 저장된다. 현재 사용되는 스택 프레임이 소멸되지 않는 동안 EBP의 값은 변하지 않으므로 기준점이 된다.

 

 

5. X

 -> 플래그 레지스터에서 TF는 0일 때 CPU는 보통대로 명령을 실행하고 1일 때 CPU가 한 명령을 실행할 때마다 자동적으로 내부 인터럽트를 발생하고 인터럽트 처리 루틴으로 들어간다. 

 

 

 

 

출처 및 참고 사이트 : https://kali-km.tistory.com/entry/CPU-레지스터 [Kali-KM_Security Study]

Comments