CS/Operating System

14. GNU Linker

공부중인학생 2023. 12. 18. 03:52

 

GNU Linker란?

  • C언어 코딩을 했을 때 컴파일 되는 가장 마지막 단계를 담당
  • 컴파일할 때 사용하는 gcc -o test main.c 이런 명령어에서 gcc가 CNU C Compiler

C 프로그래밍 파일의 경우 여러 soruce code 파일로 하나의 프로그램을 만들 수 있습니다. 이는 여러 개발자가 하나의 프로그램을 만들기 위해서 공동 작업을 할 때 서로 독립적으로 일하기 위한 결과로 볼 수 있습니다. 위 사진에서는 c파일, 소스코드 파일을 한꺼번에 컴파일하지만 별도로도 컴파일될 수 있습니다.

 

소스코드 파일을 독립적으로 컴파일하면 독립적인 오브젝트 파일이 생성되는데 이 .o 파일들을 묶어서 executable file, 위 사진에는 test라는 이름의 파일이 나오게 됩니다. 이런 executable file을 하나의 파일로 만드는 것이 바로 링커가 하는 일입니다.  

 

gcc 컴파일러 내부에서는 4개의 독립적인 응용프로그램이 실행이 됩니다. 첫 번째가 C preprocessor로 include, define, if, def 등을 transform 시켜 또 다른 C 코드를 만듭니다. 두 번째는 컴파일러로 이 C코드를 어셈블리 코드로 만드는 작업을 합니다.  세 번째는 어셈블러 코드를 오브젝트 코드로 변경시키는 작업을 하고 마지막으로 링커가 모든 오브젝트 코드를 묶어서 exe 파일을 만듭니다.

 

 

 

링커에 의해서 만들어진 exe 파일을 실행하면 로더에 의해서 메모리에 적재되어 프로세스가 수행을 할 수 있게 됩니다.  여기서 로더의 역할을 OS가 해줍니다. unix os에서 로더의 역할을 해주는 것은 exec system call입니다. 

 

exe 파일도 오브젝트 파일로 볼 수 있습니다. 하지만 exe 파일은 자체적으로 수행이 가능하지만 오브젝트 파일의 경우 다른 오브젝트 파일에서 정의된 전역 변수나 함수에 대해서 어떤 주소가 부여될지 모르기 때문에 함수나 전역변수를 주소로 변경하는 작업을 할 수 없습니다. (정보가 부족하기 때문에 수행이 불가능)

 

 

이런 변수나 함수를 주소로 변경하는 작업을 symbol address resolution이라고 하며, 이렇게 다른 소스파일에서 정의된 함수 이름이나 변수 이름을 사용하는 것을 external reference 또는 cross reference라고 부릅니다. 오브젝트 파일 하나에는 해결되지 않은 external reference가 있기 때문에 코드를 수행할 수 없습니다. (이 문제를 링커가 해결한 경우 exe 파일이 됩니다.)

 

오브젝트 파일에는 instruction과 global variable, symbol table, relocation table이 들어있습니다. 

 

 

Linking

 

 

링킹에 대해서 알아보기 위해서는 각 오브젝트 파일에 어떤 정보가 들어있는지 알아볼 필요가 있습니다. 오브젝트 파일은 section이라는 unit으로 구성되어 있습니다. 이 section에는 instruction section, data section, relocation table, symbol table이 존재합니다. 

 

 

 

instruction 정보를 담고 있는 section의 경우 text section이라고 부릅니다. global variable을 담고 있는 section들이 있는데 하나는 data section이고 다른 하나는 BSS section이라고 부릅니다. 이렇게 구분하는 이유는 data section에는 초기값을 갖는 global variable, BSS section에는 초기값을 가지지 않는 global variable에 대한 정보를 저장하기 때문입니다.

 

이는 디스크 효율을 위해서 구별하여 저장합니다. 만약 백만개의 원소를 가지고 있는 array가 존재할 때 초기값이 없는 경우에는 바로 할당할 필요가 없기 때문에 사용할 때만 할당하면 됩니다. 즉 초기값이 있을 때는 디스크 상에 백만 개를 할당해야 하지만 없는 경우에는 타입 정보만 저장하는 것이 효율적이기 때문입니다. (실행되기 전에는 값이 없기 때문에 디스크에 저장하는 형태가 그냥 백만 개 할당될 예정이다라고 저장되는 것)

 

exe 파일이 로드될 때 text. data, bss section들만 메모리를 차지합니다. 실행 되면서 디스크에 있는 section들이 메모리로 올라오는데 이때는 data section과 bss section을 구분하지 않고 하나로 합치게 됩니다. 

 

 

ex)

 

 

왼쪽의 C코드는 글로벌 변수 x, y, z, m이 존재합니다. 이 중 m은 uninitialized global variable이고 나머지 3개는 초기값이 정해진 global variable입니다. 함수는 func와 main이 존재합니다. 그래서 이 코드를 컴파일하면 3개의 section이 만들어지게 됩니다. (symbol table, relocation table은 이번 예제에서는 사용하지 않겠습니다.)

 

func와 main을 컴파일해서 나온 instruction sequence들이 text section에 저장됩니다. func의 instuction의 경우 0번지부터 저장이 되고 main의 instruction의 경우 10번지부터 저장이 됩니다. bss section의 0번지에는 m 글로벌 변수, data section에는 x, y, z 글로벌 변수가 들어가게 됩니다.

 

 

 

우리가 c코드로 작성된 a.c, b.c 파일들을 컴파일하면 a.o, b.o의 오브젝트 파일을 얻습니다. 여기서 링커는 각 오브젝트 파일에서 같은 타입의 section들을 모아서 하나의 큰 덩어리로 만듭니다. 그다음 오브젝트 파일에 존재하지 않는 external symbol에 대한 주소를 결정하여 변경해 주는 작업을 진행합니다.

 

이런 주소를 absolute address 라고하며 이 absolute address가 결정되면 symbol이 쓰이는 위치에 absolute address를 끼워 넣는 작업을 진행합니다. (symbol = 변수 이름 등으로 생각하시면 됩니다.)

 

 

 

링커가 큰 section들을 만들 때 사용자가 section들의 위치를 조정할 수 있는데 이것을 linker script라고 합니다. 로더가 exe 파일을 다 로딩한다면 마지막에 프로그램 카운터의 초기 주소로 메인 함수의 시작 주소를 넣어두게 됩니다. 

 

 

 

링커가 링킹을 하기 위해서 해결해야되는 2가지 문제가 존재합니다. 첫 번째는 모든 심벌에 address를 부여한다는 것과 각 section에 흩어져 있는 external reference, cross reference의 주소를 결정하고 다 교체하는 작업을 해야 합니다.

 

 

 

심벌들을 absolute address로 변경하는 작업을 할 때 링커는 위 사진과 같은 symbol table을 사용합니다. 앞에 예제에서 사용한 2개의 function과 3개의 initialized global variable, 1개의 uninitialized global variable를 적용해 보겠습니다. 위 테이블에서 심벌들이 어떤 section에 있고 offset이 얼마나 되는지를 기록합니다.

 

 

 

링커는 각 오브젝트 파일들의 section을 합쳐서 큰 section을 구성할 때 작은 section들의 베이스 주소가 결정되게 됩니다. local function, variable의 경우 링커가 이런 작업을 해주지 않아도 됩니다.

 

 

 

링커가 링킹을 할 때 해결되지 않는 cross reference가 나오게 될 때를 봐보겠습니다. 우선 printf가 cross reference인데 주소를 모른다면 마크를 해두고 printf 자리에 0x0을 넣고 call printf의 instruction 주소를 relocation table에 넣습니다. 나중에 이 주소를 읽고 위치를 찾아가서 0x0 대신에 printf의 absolute address를 넣습니다.

'CS > Operating System' 카테고리의 다른 글

16. Segmentation  (1) 2024.01.10
15. Dynamic allocation in Linux  (0) 2023.12.24
13. 힙(Heap)  (1) 2023.12.18
12. Deadlock solution  (0) 2023.12.12
11. Deadlock  (1) 2023.12.10