안녕하세요. 오늘은 process에 대해서 알아보는 시간을 가질까 합니다. 저번 포스팅에선 운영체제 내용을 이해하는데 필요한 기초적인 컴퓨터과목 내용을 소개하는 시간을 가졌는데요.
2021.11.08 - [학부공부/운영체제] - 09. 운영체제와 컴퓨터 구조(2)
지금까지는 기초를 다졌다고 생각하시면 되고 이제부터 본격적인 내용이 시작된다고 보시면 됩니다. 프로세스는 computer에서 가장 기본적인 abstraction이라고 할 수 있습니다. Operating System 분야의 scope를 따진다면 프로세스 관리부터 시작하여 메모리, 파일, I/O 시스템 관리, 네트워킹, 보안까지 정도일 것입니다. 그럼 시작하겠습니다.
10.01. Program and Process
자료구조 과목을 배우신 분들이라면 아래의 그림이 익숙하실 수도 있겠습니다. 프로그램과 프로세스의 관계를 잘 나타내주는데요.
여기서 Source Code가 Program이라고 생각하시면 되고 Executable은 실행파일인데요. binary로 이루어진 그것입니다. 보안을 하시는 분들이라면 분석툴로 분석해보셨을 수도 있겠군요. Process는 Loader에 의해 Executable이 물리메모리로 올라온 것입니다. 주소관점에서 Object file은 relative address입니다. 각각의 a.c, b.c ...가 compile을 거쳐 a.o, b.o ... 가 되면서 address가 각각 정의되죠. Executable은 absolute address입니다. Linking하면서 주소가 합쳐지죠. 라이브러리는 그냥 표시되어 있습니다. 조금 더 자세하게 각각 알아볼까요?
Source Code : .c file
소스 코드는 프로그램이 수행하고자 하는 작업이 프로그래밍 언어로 표현되어 있습니다. 프로그래밍 언어로 표현되어 있기 때문에 프로그램이죠 뭐.
Compiler
컴파일러는 인간 친화적인 프로그래밍 언어로 작성된 소스 코드를 CPU가 이해할 수 있는 기계어로 표현된 Object file로 변환합니다.
Object file : .o file
Visual Studio에서 프로젝트를 생성해보신 분들이라면 익숙하실 수도 있겠군요. DEV-C++와 같이 가벼운 개발환경을 사용하지 않으신 분들이라면 더더욱 익숙하실 겁니다. 컴파일러에서도 소개드렸다시피 기계어로 구성된 파일이고 그 자체로는수행이 이루어지지 못합니다. 즉, 프로세스로 변환되기 위한 정보가 추가적으로 필요한 것이죠. 한 가지 더 기억하셔야 할 점은 소스코드 하나에 오브젝트 파일 하나가 생성된다는 점입니다.
Linker : Linkage editor
링커는 말 그대로 무언가 연결시켜주는 역할을 합니다. 관련된 오브젝트 파일과 라이브러리를 연결하여 메모리로 load 될 수 있는 하나의 실행파일을 작성하죠.
Executable file : .exe file
실행파일은 특정한 환경에서 수행될 수 있는 파일입니다. 여기서 특정한 환경이란 OS가 되겠죠. 그래서 과제를 하시거나 프로젝트를 진행하실 때, 환경을 꼭 기재하는 것입니다. 여러분이 최종적으로 실행하는 실행파일이 특정한 환경에서만 수행될 수 있기 때문이죠. 프로세스 변환 직전이기 때문에 대부분의 정보를 담고 있습니다. Header(헤더는 이름에서도 알 수 있지만 앞부분에 있고 형식(COFF, a.out)이 정해져 있습니다), 무엇을 할지 읊어놓은 text, 필요한 data를 포함합니다. 여러분이 Shell에서 compile해보셨다면
make
명령어를 사용해 보셨을 텐데요. 이때 target CPU를 정할 수 있습니다. 그럼 CPU에 맞춤 instruction으로 바뀌는 거죠.
make maunual에 대한 한국어 reference를 읽어보고 싶은 분들께는 http://korea.gnu.org/manual/를 추천드립니다.
10.02. Dynamic Linking & Static Linking
앞서 Linking에 대해서 간단하게 설명드렸었는데요. 이번에는 Dynamic Linking과 Static Linking에 대해 알아보겠습니다.
Linker(Interesting topic to study)
Static linking은 compile하고 linking할 때 라이브러리가 따라 오는 것입니다. 라이브러리는 address reserve가 안되는데 static linking에서는 모두 reserve됩니다. 그리고 실제로 execution할 때 symbol의 address를 볼 수 있도록 executable 뒤에 symbol table이 붙죠. 디버깅을 못하게 하려면 strip(executable을 만들 때 symbol table 제거)하면 됩니다.
Dynamic linking은 executable size가 큰 Static linking에 비해서 size가 작은데요. 동적으로 메모리에서 필요한 것만 호출하자고 만든 것입니다. 즉, executable에 lib를 포함하지 않고 메모리에서 binding한다(RTS : run time system에 의해 접근)고 정리할 수 있겠네요.
Runtime System : RTS
Dynamic linking을 설명할 때 RTS에 대한 간단한 언급이 있었는데요. RTS는 함수 호출 시 파라미터를 전달하거나 프로세스 메모리를 구성하는 것 등을 RTS가합니다. 모든 언어는 자신만의 RTS를 가지고 있죠.(Node.js : Javascript, ...) Runtime 환경을 제공한다고 생각하시면 됩니다. 예를 들면 C언어에서는 상위함수가 main()인데 누군가가 main()을 호출하죠. 그 누군가가 RTS입니다. 위에서 파라미터를 전달한다고 했는데요. argc, argv 인자를 넘겨주겠군요.
10.03. Process
자 그럼 프로그램에서 어떻게 프로세스가 만들어지는지 좀 더 알아보겠습니다. 참고자료에서 아주 좋은 그림이 있더군요.
일단 몇 개 block에 대해 설명하자면 Program image in disk는 프로그램 executable 형식(a.out)이라고 보시면 됩니다. text(text segment)는 그냥 코딩한 것이 어셈블리로 번역된 것입니다.(네. 그냥 프로그램입니다.) Data는 global data 프로그램에 들어갑니다. bss를 처음 보실수도 있는데 이것은 initialize되지 않은 global 변수 입니다.(프로그램의 데이터는 값이 초기화되어 있지만 bss는 초기화되어 있지 않고 크기만 header에 기록되어 있습니다. 보통 data segment는 data + bss를 의미합니다.) Heap은 C 프로그램에서 malloc, calloc과 같은 함수와 같이 동적으로 할당되는 메모리를 위한 공간입니다. text와 data는 프로그램에서 오고 bss와 Heap은 그냥 위치만 잡아준다고 생각하면 편합니다. Stack은 가장 상위주소 또는 하위주소로 시작합니다.
bss(Interesting topic to study)
예를 들어 카카오톡을 생각해 볼까요?
header에서 text size catch > 메모리 확보 > 프로그램의 text 복사 > header에서 data size catch > data에 필요한 메모리 확보 > disk의 data 복사
정도의 순서겠군요.
그래서 프로세스가 뭐냐고 질문하실 때가 되었습니다. 프로세스는 abstraction이라고 말씀드렸죠. 그럼 이제 무엇을 위한 abstraction인지 소개하겠습니다.
Execution unit, Protection domain
Exectuion unit이라는 것은 CPU에서 무언가가 돌아갈 때의 단위 즉, 스케쥴링 될 수 있는 단위입니다. 또한 protection domain을 위한 abstraction인데요. 프로세스와 프로세스는 서로 다른 보호되어 침범하지 못하는 도메인을 생성한다는 것입니다.(서로 호출을 못한다는 것이죠. 예를 들면 다른 프로세스로 jump나 call을 못하는 것을 OS가 보장한다는 것입니다.)
그래서 프로그램과 프로세스의 차이는?
Disk에 저장된 프로그램으로부터 변환되어 메모리에서 만들어지는 프로세스. 프로그램을 정적인 entitiy라 한다면 프로세스는 동적인 entitiy라 할 수 있습니다. Computer의 power를 off한다면 프로세슨느 없어지죠. Rebooting하더라도 프로세스는 찾을 수 없습니다. 프로그램은 파일 시스템의 속성에 따라 다르지만 디스크에서 찾을 수 있죠. : Power persistence
Protection domain
Execution unit은 쉽게 받아들이고 이해되는 개념입니다. Protection domain은 조금 낮설 수 있어 자세히 설명하고 넘어가겠습니다. Protection domain으로 인해 주소를 알더라도 다른 프로세스로 점프를 못합니다.(해킹은 이런 것을 교란시키죠. Text segment나 data에 code를 심어놓고 text를 수행하는 것을 빠져나와서 data의 hacking code를 실행하는 것이 하나의 해킹 방법일 수도 있고요. Hacking code를 Heap에 살짝 심어놓고 나올 수도 있겠네요. 보안 분야를 공부하시는 분들이 더 잘 아실겁니다. 혹시 이 글을 보고 계시다면 댓글 좀 부탁드립니다.)
우리는 Protection domain을 모르더라도 사실 coding할 때 고려해주고 있습니다. C 프로그램에서 동적할당을 하면 free를 해주죠. 왜 그럴까요?
Array는 runtime이 정리를 해줍니다. 하지만 malloc은 어디에 위치하는지 프로세스마다 다르기 때문에 외부(RTS)에서 알 수 없습니다.(Heap 영역은 process exit하면 OS가 그 존재를 모른다는 말입니다.) 그래서 free를 안하고 나오면 그냥 남아 있습니다. 과거 시스템이 죽어버리는 경우 중 하나로 메모리 leak이 있었죠.
그래서 프로세스를 만드는 과정에서 취약점(이러한 취약점은 abstraction의 문제라기 보다는 구현상의 약점이라고 보는게 맞을 듯 합니다.)이 존재합니다. 그럼 이것을 해결하는 것도 있겠죠. 예를 들면 Java의 경우 garbage collector가 존재합니다. Go언어는 이런 것을 지원해서 과거에 만들어진 C언어에 비해 더 safe하다고 표현합니다.
Garbage collector(Interesting topic to study)
그럼 malloc을 추적하면 되지 않을까?
추적해서 그것을 기록하면 되지 않을까 생각하실 수도 있습니다. 이 질문은 결국 메모리 주소가 뭐냐는 질문으로 귀결되는데요. 각각의 프로세스 안에서만 valid하고 exit하면 알 길이 없습니다. 또한 design관점에서도 운영체제는 대게 프로세스가 어떤 메모리를 할당했는지 개입하고 싶어하지 않습니다. OS관점에서 또다른 job을 양산하는 것이고 attack point가 될 수 있기 때문에 프로그램에 맡기는 것입니다.(실제로 하기도 어려울 것 같군요.)
오늘은 프로세스에 대해서 알아보는 시간을 가졌습니다. 이전 포스팅에서는 사실 프로그램과 프로세스를 혼용하여 서술하는 경우가 많았는데요. 이번 포스팅으로 프로세스에 대한 개념을 잡았으니 앞으로는 조금 엄밀하게 표현하도록 하겠습니다. 질문은 언제든지 환영합니다. 저보다 smart하시고 생각의 깊이가 깊으신 분들의 의견도 언제나 환영입니다. 아니 환영하기보단 기다리고 원한다고 표현하는 것이 더 맞을지 모르겠네요. 다음 시간에는 Context switch, Process creation등에 대해 알아볼 것입니다.
'학부공부 > OS_운영체제' 카테고리의 다른 글
12. Process(2) (0) | 2021.11.15 |
---|---|
11. bss [Interesting topic to study] (0) | 2021.11.12 |
09. 운영체제와 컴퓨터 구조(2) (0) | 2021.11.08 |
08. 운영체제와 컴퓨터 구조(1) (0) | 2021.11.08 |
07. Hypervisor [Interesting topic to study] (0) | 2021.11.02 |
댓글