본문 바로가기

운영체제/Program Linking

운영체제 - 컴파일러(compiler), 링커(linker)

운영체제 - 컴파일러(compiler), 링커(linker)



컴파일러는 .c 파일을 각각 컴파일(compile)하여 오브젝트 파일(.o)를 만든다.

링커는 오브젝트 파일(.o)을 한데 묶어 .exe파일을 만든다.

만들어진 .exe를 실행시키면 운영체제의 로더(loader)에 의해 메모리에 적재된다.

 

<링커의 역할>


각각의 오브젝트 파일(.o)은 프로그램의 데이터의 특징에 따라 각각의 section으로 구분된다.

Text section

- 프로그램의 코드가 저장된다.

Data section

- 프로그램의 초기화된 전역 변수가 저장된다.

ZI(=BSS) section

- 프로그램의 초기화되지 않은 전역 변수가 저장된다.

<추가>

Symbol Table

- 프로그램에서 사용하는 symbol들에 대한 정보를 저장하는 자료구조

Relocation Table

- 외부 심볼(external symbol)에 대한 처리를 위한 자료구조


Q. 전역변수는 왜 초기화의 여부에 따라 Data section과 ZI section으로 나뉠까?

1
2
int number = 1;
int arr[1000000];
cs

전역변수 number는 address + value(4B)의 크기로 .exe파일 내에 존재한다.

그런데, 전역변수 arr를 위해 4MB의 크기가 .exe파일 내에 존재햐 할까?

초기화 되지 않은 전역변수를 .exe파일 내에 저장하는 것은 디스크 공간의 낭비이고 불필요하다.  그에 따라, .exe파일이 실행되어 메인 메모리로 로드될 떄, 초기화 하는 것이다.


컴파일 과정은 one-path로는 불가능한데, 그 이유는 외부 심볼에 대한 address를 확정할 수 없기 떄문이다. 컴파일러는 각각의 개별 .c파일에 대해 symbol table을 만드는 데, 외부 .c파일에 선언된 extern 변수에 대한 메모리 주소는 알 지 못하는 것.(cross referencing)

그에 따라, two-path 컴파일 과정(컴파일러+링커)을 통해 relocation table 자료구조를 이용, 외부 심볼(external symbol)에 대한 주소지정을 하는 것이다.


내부 심볼(internal symbol)에 대해서는 위와 같이, 각 심볼에 대한 offset을 먼저 결정하고 각 section의 base address에 offset을 더한 값으로 최종 주소(address)를 결정한다. 그런데, 외부 심볼에 대해서는 주소를 결정할 수 없다.


<외부 심볼(external symbol)의 주소 결정>

외부 심볼은 첫 번째 path때 주소가 0x0번지로 설정, relocation table에 등록되었다가 (cross referencing)

링커의 두 번째 path에서 최종적인 주소(address)가 결정된다.


링커(linker)

- 링커는 앞서 설명한 symbol table을 결정하는 것 말고도 메모리 레이아웃(memory layout)을 결정한다.

- 즉, Text section의 베이스 주소, Data section의 베이스 주소, ZI section의 베이스 주소를 결정한다.

- 이러한 section 베이스 주소는 링커 스크립크(linker script)를 수정함으로써 변경할 수 있다.(특히, 임베디드 시스템에서 많이 수정된다.)


PC Relative address

심볼에 대한 주소를 결정할 때, 절대값보다 프로그래 카운터(PC, program counter) + offset으로 주소를 결정하는 PC Relative address방법이 있다.

이 방법은 각 section의 메모리 레이아웃과 무관하게 주솟값을 결정할 수 있는 장점이 있다.


최종적으로, 링커에 의해 .exe파일이 만들어 진다.


.exe파일은 운영체제의 로더에 의해 메인 메모리로 로드 될 때에는 아래와 같은 메모리 레이아웃을 갖는다.

compile time에서의 메모리 레이아웃, section

Text section : 코드

Data section : 초기화된 전역변수

ZI section : 초기화되지 않은 전역변수

Text + Data + ZI section의 합으로 .exe파일의 크기를 결정했다.


run time에서의 메모리 레이아웃, segment

Code segment : 코드

Data segment : 초기화된 전역변수 + 초기화되지않은 전역변수(ZI)

Stack segment : function frame + 지역변수

Heap segment : dynamic allocation


Code, Data segment는 컴파일 타임에 그 크기가 결정된다는 특징에 의해 static storage allocation이라 불린다.

Stack, Heap segment는 런타임에 그 크기가 결정된다는 특징에 의해 dynamic storage allocation이라 불린다.