infatuation

운영체제가 있는 경우의 main() 호출과정 본문

Study/OS&Linux

운영체제가 있는 경우의 main() 호출과정

화령 2010. 11. 18. 17:04

C코드를 컴파일하면 실행파일이 생성 >> 생성된 실행 파일은 하드디스크(HDD)에 저장
실행파일 시작 >> 실행 파일의 헤더를 읽어서 실행 파일의 종류를 파악 & 사용할 핸들러를 결정함
* 핸들러 : 각 섹션에 대한 정보를 해석, 필요한 데이터들을 RAM에 로드

프로그램 코드와 상수가 있는 Text 세션 >> Text 세그먼트로 
초기화된 데이터가 있는 data 세션 >> data 세그먼트로 로드 

오브젝트 파일은 코드나 데이터의 종류 별로 영역을 나누어 관리 >> 이 영역을 섹션이라고 함
프로그램이 실행될 때는 실행 가능한 오브젝트 파일의 섹션들이 RAM에 로드 됨 이때 RAM에 로드된 각 메모리 영역을 세그먼트라고 함.

Data 세그먼트를 할당한 다음 bss세그먼트를 할당
초기화되지 않은 전역 데이터들은 실행 파일에 포함시킬 필요가 없으므로 블록 크기 정보만을 가지고 있다가 런타임에 블록 크기만큼 세그먼트를 할당하고 이 영역을 0으로 초기화함. 이 영역을 bss 세그먼트라고 한다. 

Heap & Stack 생성하고 C프로그램을 수행할 준비가 끝나면 마지막으로 C의 main()을 호출하여 프로그램을 실행함.

* 리눅스 운영체제의 경우
 : 프로그램의 실행은 프로세스를 복사하는 것에서부터 시작.
 리눅스의 모든 프로세스는 부모와 자식의 관계로 이루어져 있어서 기존의 프로세스를 복사하고, 복사된 프로세스의 기존 실행 컨텍스트를 버리고 새로운 실행 컨텍스트로 변경하여 새로운 작업을 할 수 있도록 함.

1) 쉘에서 프로그램 수행 : ./test
2) fork로 새로운 프로세스 복사
3) execve() 호출(시스템콜) -> sys_execve() 호출 >> 사용자 모드에서 커널 모드로 전환
4) do_execve() -> open_exec()가 파일 정보를 읽어 들여 적합한 binary handler를 실행
5) flush_old_exec()가 기존 프로세스의 정보를 삭제하고, 현재 프로세스를 "current"로 설정
6) 새로운 프로세스에서 사용할 메모리 레이아웃 설정. text, data, bss, stack등의 세그먼트를 선형 메로리에 매핑
7) 동적 링커 메모리에 로딩. elf 포맷이면 load_elf_interp()가 /lib/ld_linux.so.2를 메로리에 로딩함
8) start_thread() -> elf 인터프리터(elf_interpreter) 실행
9) sys_execve() 종료 >> 커널모드에서 사용자 모드로 전환
10) reschedule() // Context switch
11) _start 코드에 의해 main() 실행 

main()은 시스템의 시작점이 아니다. 시스템의 동작은 크게 초기화 작업과 프로그램 실행으로 나누어 볼 수 있다. 이 중 프로그램 실행의 시작 부분이 main()이다. 시스템이 동작하려면 클록 설정이나 메모리 설정 등 사용할 하드웨어를 초기화해야 하고, 이 작업이 끝나면 다시 C 프로그램이 동작할 수 있는 기반을 만들어 주어야 한다. 주로 프로그램에서 사용하는 데이터를 RAM에 올려주고, 필요한 메모리들을 할당해 주는 역할을 한다. 이러한 초기화 작업이 끝나면 C 프로그램이 실행될 준비가 끝난 것을 의미하므로 C 프로그램의 main()으로 분기하여 프로그램을 실행한다.