여러 개의 코드와 데이터를 모아서 연결하여 메모리에 로드될 수 있고 실행될 수 있는 한개의 파일로 만드는 작업
컴파일, 메모리 로드, 실행 시에도 수행될 수 있음
C 전처리기로 main.c를 main.i로 번역한다
C 컴파일러로 main.i를 어셈블리 언어 파일인 main.s로 번역한다
어셈블러로 main.s를 바이너리 목적파일(재배치 가능)인 main.o로 번역한다
링커 프로그램(리눅스 → ld)를 실행하여 실행 가능 목적파일을 생성하기 위해 main.o와 sum.o를 연결한다.
실행파일을 실행하면 (./prog) 로더(loader)라고 불리는 운영체제 내의 함수를 호출한다.
리눅스 LD 프로그램과 같은 정적 링커들은 재배치 가능한 목적파일들과 명령줄 인자들을 입력으로 받아들여서 로드(ld -o prog /tmp/main.o /tmp/sum.o) ****될 수 있고 출력으로 완전히 링크된 실행 가능 목적파일을 생성한다.
실행파일을 만들기 위한 링커의 두가지 주요 작업
심볼 해석
static
파일 또는 함수 내에서만 사용할수 있게 제한
extern
외부의 심볼을 가져와서 사용
inline
함수 호출 대신 함수를 직접 복사해서 사용 간단한 함수를 호출할 때 성능 향상을 위해 컴파일러가 자동으로 변환
Symbol Table
컴파일러와 링커가 사용하는 함수, 변수 등의 이름 목록
예시)
| 이름 | 타입 | 위치 | 속성 |
|---|---|---|---|
| main | 함수 | .text | global |
| count | 함수 | .text | global |
| printf | 외부 함수 | (libc에서) | extern |
Weak Symbol
같은 이름의 다른 심볼이 있으면 그걸 쓰겠다 !!
재배치
이전에는 모든 함수/변수는 강한 심볼이었음. 그러다 일부 기능을 커스터마이징하여 사용하고 싶은 니즈가 발생하여 만들어짐
모든 인터럽트를 처리하는 핸들러를 커스터마이징하고 싶을 때, 핸들러가 강한 심볼이라면 새로 정의했을 때는 충돌이 발생함. 핸들러를 약한 심볼로 만들어서 만약 사용자가 이름이 같은 핸들러를 정의했다면 정적 링크 타임에 오버라이드
사용자가 정의한 함수나 변수는 특별한 조치를 취하지 않는 한 강한 심볼로 만들어짐
__attribute__((weak)) void my_func() {
// 약한 정의
}
GCC 기준으로 위처럼 만들어서 약한 심볼을 임의로 만들 수 있음