패스트캠퍼스

[패스트캠퍼스 수강 후기] 올인원 패키지 : 컴퓨터 공학 전공 필수👉C언어인강 100% 환급 챌린지 38회차 미션

돌맹이시터 2020. 11. 25. 22:11

 

 

환급미션 38일째...

 

 

 

 

운영체제 - 프로세스와 스케쥴러의 이해 - 10. 프로세스 구조

운영체제 - 프로세스와 스케쥴러의 이해 - 11. 프로세스 구조와 컴퓨터 구조

 

 

 

 

 

- 프로세스와 컨텍스트 스위칭

 

 

* 컨텍스트 스위칭

A라는 프로세스가 실행되다가, 스케쥴러에 의해 B라는 프로세스로 교체

이 때, 바꿔주는 매커니즘을 '컨텍스트 스위칭'이라고 한다.

 

*

현업에서 실제로 실행파일의 구조를 알아내야 할 때가 있다.

디버깅을 통해 문제점을 찾아낸다던지.. 할 일이 많다.

이런 일들을 위해 프로세스 구조를 알아야 한다.

 

 

 

- 프로세스 구조 

 

 

파이썬으로 작성된 예제

사실 파이썬은 인터프리터 언어이기 때문에 컴파일러가 필요 없고, 실행파일을 만들지 않는다.

컴파일한다고 가정하고(0/1로 구성되는 기계어로 변환), 프로세스를 살펴보기로 한다.

 

 

프로세스 구조는 몇 가지 영역으로 나눌 수 있는데

그 중 핵심적인 4가지 영역으로 나누어진다.

 

1. code

컴파일된 소스코드가 저장

 

2. data

c=0

변수 선언 : 메모리 특정공간을 만들어서 변수가 그 주소를 가리키게 하고, 데이터를 읽고/쓰기도 한다.

그 공간을 data 영역에 저장한다.

 

3. stack

함수 안에 별도의 변수 지정가능 (함수가 끝나면 사라짐)

함수를 실행할 때 동적으로 처리해야 할 필요성이 생기는데, 이 때 그 공간을 stack에서 제공한다.

함수를 실행하고 나서, 그 다음에 실행할 주소를 return address라고 하는데 (0050h)

함수가 실행된 후에 함수를 실행하기 위해 사용한 인자들을 없애고,

return address에 해당하는 코드로 가서 다음 코드를 실행하게 된다.

이렇게 동적으로 처리하는 영역을 stack이라 한다.

 

4. heap

c언어에서 malloc() 이라는 함수가 하는 역할은 동적으로 특정 메모리 공간을 생성하는 것이다.

이 때 동적으로 생성되는 공간을 heap이 제공한다.

 

 

 

c언어로 작성된 예제

 

c언어는 항상 함수가 실행된다 (main함수)

 

위에서 본 파이썬의 경우와 마찬가지로 

c언어로 작성한 코드를 컴파일한 상황을 가정하여

프로세스의 구조를 살펴볼 것이다.

 

 

1. code

작성된 코드가 컴파일되면 code 영역으로 들어간다.

 

2. data

코드에 별도로 선언된 변수는 없다. (함수 안에 int temp가 있긴 하지만 함수 내의 변수이기 때문에 따로 저장되지 않는다)

따라서 data 영역이 비어있는 상태이다.

 

3. stack

meaningless 함수 영역을 살펴보면, 아무런 일도 하지 않고 선언만 한다.

main 함수의 return address를 넣어야 하는데, 그 영역은 사실 코드의 바깥에 있어야 한다.

임의로 0006h라고 가정, 이 return address는 stack 영역에 저장된다.

또한

메인 함수에서 인자를 두 개 받는다. (argc, argv)

함수(main) 안에서 또 다른 함수(meaningless)를 실행했고, 이 함수의 실행이 끝나면 다시 이전함수로 돌아가야 한다. (main)

( 자료구조에서 이러한 방식을 표현한 자료구조가 바로 'stack'이다. )

-> return address : 0005h 를 stack에 넣는다.

data = 1

(meaningless) -> temp = data = 1

 

stack 맨 끝에 있는 것부터 하나씩 없앤다.

return address: 0005h를 확인하면,

0005h에서 PC=0005h로 바꾼 후에 stack에 있는 return address: 0005h를 없앤다.

return 0 (0005h)을 실행하면 메인함수가 끝난다.

stack에 있는 메인함수의 인자를 또 끝에서부터 없앤다.

return address: 0006h에 도달하면 

PC=0006h로 바꾼 후에 stack에 있는 return address:0006h를 없앤다.

 

이렇게 종료되면

main함수 이후에 프로그램을 종료하는 특별한 코드 (default code)로 넘어가게 된다. (다음에 자세히)

 

 

 

* 프로세스 구조 정리

 

 

text(code) : code

data : 변수/초기화된 데이터

stack : 임시 데이터(함수 호출, 로컬 변수 등)

heap : 코드에서 동적으로 만들어지는 데이터

 

(0~max : 프로세스 주소값)

 

 

* 주요한 레지스터 두 가지가 어떻게 프로세스 구조와 엮여서 동작되는지 

PC(program counter) + SP(stack pointer) : stack frame의 최상단 주소를 가리킴

 

파이썬 코드로 작성된 예시

실제로는 오른쪽 아래에 있는 것처럼

c=0

 return a+b

def func(a,b)

의 순서대로 주소가 부여되어야 하지만 

이해를 돕기 위해 왼쪽 프로세스 구조처럼 코드를 순서대로 보이게 구성하게 되었다고 한다.

 


PC 초기값은 0000h

SP (stack pointer) 아직 아무 값도 없기 때문에 1000h

EBP (레지스터의 하나, 함수를 트래킹할 때 사용, 1000h : 나중에 다시 다룰 것)

 

코드가 실행되면..

선언 부분은 특별한 일 없이 지나가고

0003h에서 본격적으로 함수가 실행된다. 

c=func(1,2)라는 코드가 사실 기계어로는 두 줄 정도로 나누어지기 때문에 위의 그림과 같이

func(), c=func()로 구분지어서 주소를 할당했다.

 

맨 처음에 하는 일은 EBP에 들어있는 초기 SP에 있는 값을 stack 최상단에 적게 된다.

인자를 쓰기 전에, 인자 사용 이후 돌아올 주소를 먼저 적는다. (return address=0004h)

함수의 인자가 순서대로 들어간다.

(만약 함수에서 지역변수를 사용하게 된다면 이후에 지역변수가 다음 줄에 들어간다)

여기까지 왔을 때 SP=0FFCh

 

(만약 이 시점에서, 함수 func 안에서 또다른 함수가 실행된다면 EBP는 현재 SP값인 0FFCh가 된다. EBP=0FFCh

또한 프로세스 내의 stack에도 0FFCh가 들어가게 된다.)

만약 어느 시점에서 프로그램 오류가 발생한다면,

EBP에는 항상 현재 호출된 함수의 최상단 SP를 갖게 된다.

따라서 EBP로 인해 어떤 부분에 문제가 있었는지를 확인하기에 용이하게 된다.

 

 

 

예제로 사용된 코드의 함수에서

결국 a+b를 실행했을 때의 반환값은 EAX에 들어가게 된다. (EAX=3)

함수가 종료되면, 함수의 인자값은 끝에서부터 하나씩 없어지고

return address=0004h에 도달하면 

0004h로 돌아가서 PC=0004h 

이전 예제에서와 마찬가지로 ret을 삭제하고

초기 SP도 삭제된다.  

PC값인 0004h에 있는 코드를 비로소 실행하게 된다.

 

 

 

0004h에 있는 코드에서,

c의 결과값은 EAX의 값이 되고

DATA 영역에서 c=3으로 바뀌게 되고

다시 PC는 0005h가 되고,

0005h에 있는 코드를 실행하게 된다

 

 

 

 

 

 

 

 

오늘의 수업내용은

이후에 디버깅을 할 때 유용하게 사용된다고 한다. 

특히 c, cpp언어로 작성된 프로그램에서 알아두는 것이 좋다고 한다.

 

 

 

 

 

 

 

 

올인원 패키지 : 컴퓨터 공학 전공 필수👉https://bit.ly/3i4sCVE