링커
여러 개의 코드와 데이터를 모아서 이를 연결해 메모리에 로드될 수 있고, 실행될 수 있는 한 개의 file을 만들어 내는 역할을 수행
목적
- 큰 프로그램을 작성하는데 도움이 됨
- 위험한 프로그래밍 에러를 피할 수 있음
- 변수 영역 규칙이 구현되었는지 이해하는데 도움이 됨
- 공유 라이브러리에 대해 이해할 수 있음
컴파일러 드라이버
- 대부분의 컴파일 시스템은 사용자를 대신해
언어 전처리기
,컴파일러
,어셈블러
,링커
를 필요에 따라 호출하게 만들어졌음(ex. GCC 드라이버 등..) - 컴파일을 모두 마친 실행 파일을 prog이라고 한다면, 쉘에
./prog
라는 명령어를 통해 해당 파일을 실행 - 쉘이 운영체제 내의
로더
를 호출시키고,로더
는 실행파일 prog의 코드와 데이터를 메모리로 복사하고, 제어를 시작부분으로 전환
*로더 : 완성된 실행파일을 실행했을 때, 해당 프로그램 내용을 메모리에 적재시키는 일을 수행
컴파일 과정
컴파일 과정은 4가지 단계(전처리 과정 - 컴파일 과정 - 어셈블리 과정 - 링킹 과정
이 4가지 단계를 묶어서 컴파일 과정, 빌드 과정이라고 부르기도 하고 컴파일 과정과 링킹 과정을 따로 나눠서 부르기도 함
보통 빌드 과정은 컴파일 과정보다 넓은 의미(빌드=컴파일+링킹)로 사용
1. 전처리 과정(Pre-processing)
- 전처리기(Preprocessor)를 통해 소스 코드 파일(*.c)을 전처리된 소스 코드 파일(*.i)로 변환하는 과정
- 대표적인 작업 3가지
- 주석 제거 : 소스 코드에서 주석을 전부 제거
- 헤더 파일 삽입 : #include 지시문을 만나면 해당하는 헤더 파일을 찾아 헤더 파일에 있는 모든 내용을 복사해서 소스 코드에 삽입함
- 매크로 치환 및 적용 : #define 지시문에 정의된 매크로를 저장하고 같은 문자열을 만나면 #define 된 내용으로 치환
2. 컴파일(Compilation) 과정
- 컴파일러(Compiler)를 통해 전처리된 소스 코드 파일(*.i)을 어셈블리어 파일(*.s)로 변환하는 과정
- 이 과정에서 우리가 일반적으로 컴파일하면 생각하는 언어의 문법 검사가 이루어짐
- Static한 영역(Data, BSS 영역)들의 메모리 할당을 수행
3. 어셈블리(Assembly) 과정
- 어셈블러(Assembler)를 통해 어셈블리어 파일(*.s)을 오브젝트 파일(*.o)로 변환하는 과정
<목적 파일(Object File)>
어셈블리 코드는 이제 더 이상 사람이 알아볼 수 없는 기계어로 변환되는데 이를 오브젝트 코드라 부름
오브젝트 코드로 구성된 파일을 오브젝트 파일(Object File)이라 부르며 이 오브젝트 파일은 특정한 파일 포맷을 가짐
※ 오브젝트 파일 포맷의 종류는 Windows의 경우 PE(Portable Executable), Linux의 경우 ELF(Executable and Linking Format)로 나눠진다.
- Relocatable Object File(재배치 가능 목적 파일) : 다른 재배치 가능 목적 파일과 결합
- Executable Object File(실행 가능한 목적 파일) : 메모리에 직접 복사가 가능하고 실행이 가능
- Shared Object File: 로드타임 또는 런타임시 동적으로 링크되고, 메모리에 로드될 수 있음
오브젝트 파일 포맷(Object File Format)
- 오브젝트 파일 헤더(Object File Header) : 오브젝트 파일의 기초 정보를 가지고 있는 헤더
- 텍스트 섹션(Text Section) : 기계어로 변환된 코드가 들어 있는 부분
- 데이터 섹션(Data Section) : 데이터(전역 변수, 정적 변수)가 들어 있는 부분
- 심볼 테이블 섹션(Symbol Table Section) : 소스 코드에서 참조되는 심볼들의 이름과 주소가 정의 되어 있는 부분.
- 재배치 정보 섹션(Relocation Information Section) : 링킹 전까지 심볼의 위치를 확정할 수 없으므로 심볼의 위치가 확정 나면 바꿔야 할 내용을 적어놓은 부분
- 디버깅 정보 섹션(Debugging Information Secion) : 디버깅에 필요한 정보가 있는 부분
4. 링킹(Linking) 과정
- 링커(Linker)를 통해 오브젝트 파일(*.o)들을 묶어 실행 파일로 만드는 과정
- 오브젝트 파일들과 프로그램에서 사용하는 라이브러리 파일들을 링크해 하나의 실행 파일을 만듦
<정적 연결>
정적 링커는 Relocatable Object File을 Executable Object File로 변환
- 1단계 : 심볼 해석(Symbol resolution)
- Relocatable Object File의 각각의 심볼 참조를 정확히 하나의 심볼 정의에 연결하는 것
- 목적 파일에 같은 이름의 심볼이 존재하고 있을 때, 어떤 심볼을 사용할 것인지 결정
- 2단계 : 재배치(Relocation)
- 심볼 정의에 알맞은 메모리 위치로 재배치
- 목적 파일에 있는 데이터의 주소나 코드의 메모리 참조주소를 알맞게 재배치함
먼저 ELF header는 word size와 byte ordering(little endian, big endian) 등의 규격을 명시한다. 링커가 오브젝트 파일을 parsing하고 해석할 때 필요한 정보들이다. 맨 마지막에는 section header file이 오는데, 이는 각 section의 위치와 크기에 대한 정보들을 담고 있다. 두 header 사이에 오는 섹션들을 간단히 설명하면 다음과 같다.
- .text : 프로그램의 기계어 코드
- .rodata : read-only data. printf의 format string (%d %d %s와 같은 것), switch의 jump table과 같은 부분들.
- .data : 초기화된 global 변수와 static 변수
- .bss : 초기화되지 않았거나 0으로 초기화된 global/static 변수들로, 실제 공간을 차지하지는 않는 일종의 placeholder
- .symtab : 함수와 global 변수에 대한 symbol table
- .rel.text : rel은 relocation을 의미하며, 링커가 오브젝트들을 합치는 작업을 수행할 때 수정되어야 할 참조 위치들의 목록. 외부 함수나 global variable을 참조하는 코드는 모두 수정이 필요함
- .rel.data : 해당 파일의 모듈이 참조하거나 정의하는 global 변수들의 relocation 정보로, 다른 global 변수/함수의 주소를 저장하는 global 변수들이 여기에 해당됨
- .debug : 디버깅을 위한 옵션을 줄 때 생성되는 부분
- .line : 원본 C 파일과 .text의 기계어 코드의 줄 번호 사이의 매핑
- .strtab : string table. .symtab의 심볼 이름과 section header의 섹션 이름을 여기에 저장
역할
링커의 역할은 크게 심볼 해석과 재배치로 나눔
심볼 해석(Symbol Resolution)
심볼 해석은 각 오브젝트 파일에 있는 심볼 참조를 어떤 심볼 정의에 연관시킬지 결정하는 과정
여러 개의 오브젝트 파일에 같은 이름의 함수 또는 변수가 정의되어 있을 때 어떤 파일의 어떤 함수를 사용할지 결정
재배치(Relocation)
재배치는 오브젝트 파일에 있는 데이터의 주소나 코드의 메모리 참조 주소를 알맞게 배치하는 과정이
링커가 컴파일러가 생성한 오브젝트 파일을 모아서 하나의 실행 파일을 만들 때, 각 오브젝트 파일에 있는 데이터의 주소나 코드의 메모리 참조 주소가 링커에 의해 합쳐진 실행 파일에서의 주소와 다르게 때문에 그것을 알맞게 수정해줘야 함
이를 위해 오브젝트 파일 안에 재배치 정보 섹션(Relocation Information Section)이 존재
링킹 과정에서 같은 세션끼리 합쳐진 후 재배치가 일어남
링킹을 하기 전 오브젝트 파일을 재배치 가능한 오브젝트 파일(Relocatable Object File)이라 부르고 링킹을 통해 만들어지는 오브젝트 파일을 실행 가능한 오브젝트 파일(Executable Object File)이라 부름
이 장에서 global과 static과 같은 용어가 계속 나오게 된다.
여기에서 global이라 함은 local variable(함수나 코드 블럭 내에서만 참조할 수 있는 변수)의 반댓말인 전역변수(global variable)와는 조금 다른 개념으로, 모든 파일에서 참조할 수 있는 변수를 의미한다.
반대로 static variable은 해당 파일에서만 참조할 수 있는 변수이다.
'크래프톤 정글 - TIL' 카테고리의 다른 글
크래프톤 정글 5기 TIL - Day 39 ~ 41 (0) | 2024.04.29 |
---|---|
크래프톤 정글 5기 TIL - Day 35 ~ 38(CS:APP) (0) | 2024.04.23 |
크래프톤 정글 5기 TIL - Day 33(RB Tree 코드 구현) (0) | 2024.04.23 |
크래프톤 정글 5기 TIL - Day 32 (0) | 2024.04.22 |
크래프톤 정글 5기 TIL - Day 31(RB 트리 - 삽입, 삭제) (1) | 2024.04.19 |