링크: 심볼 해석 알고리즘

edward·2025년 10월 17일

심볼 해석(symbol resolution) 단계에서,
링커는 명령줄에 나타난 순서대로
재배치 가능한 오브젝트 파일들과 정적 라이브러리(archive)를 왼쪽에서 오른쪽으로 스캔한다.

(컴파일러 드라이버는 .c 파일 이름을 내부적으로 .o 파일로 변환하여 링커에 전달한다.)


이 과정에서 링커는 세 개의 집합을 유지한다:

  • E: 실행 파일에 포함될 재배치 가능한 오브젝트 파일들의 집합
  • U: 아직 정의되지 않은, 즉 해결되지 않은 심볼들의 집합
  • D: 이미 정의된 심볼들의 집합

초기에는 E, U, D 모두 비어 있다.


링커의 동작 알고리즘

  1. 명령줄의 각 입력 파일 f에 대해,
    링커는 f가 오브젝트 파일인지 아카이브(라이브러리)인지 확인한다.

    • 만약 f가 오브젝트 파일이면:
      링커는 f를 E에 추가하고,
      f의 심볼 정의 및 참조 정보를 기반으로 U와 D를 갱신한 뒤,
      다음 입력 파일로 넘어간다.
  2. 만약 f가 라이브러리(archive) 라면:
    링커는 U에 있는 아직 해결되지 않은 심볼들이
    라이브러리 안의 어떤 멤버 오브젝트 파일의 정의와 일치하는지 검사한다.

    • 만약 어떤 멤버 m이 U에 있는 심볼을 해결한다면,
      링커는 m을 E에 추가하고,
      U와 D를 갱신한다.

    이 과정은 U와 D가 더 이상 변하지 않을 때까지 반복된다.
    그 이후, 참조되지 않은 나머지 멤버 오브젝트 파일들은 무시된다.

  3. 링커가 명령줄의 모든 입력 파일을 처리한 뒤에도
    U가 비어 있지 않으면,
    링커는 오류 메시지를 출력하고 종료한다.

    반대로, 모든 참조가 해결되면
    E 안의 오브젝트 파일들을 병합하고 재배치하여
    최종 실행 파일을 만든다.


⚠️ 명령줄 순서의 중요성

이 알고리즘의 단점은,
명령줄에 나열된 파일의 순서가 매우 중요하다는 것이다.

만약 어떤 라이브러리가 자신이 필요한 오브젝트 파일보다 앞에 위치한다면,
그 라이브러리의 심볼 정의는 무시되고
참조가 해결되지 않은 채로 남는다.


예시

linux> gcc -static ./libvector.a main2.c
/tmp/cc9XH6Rp.o: In function ‘main’:
/tmp/cc9XH6Rp.o(.text+0x18): undefined reference to ‘addvec’

무슨 일이 일어난 걸까?

  • 링커가 libvector.a를 처리할 때는 아직 main2.c가 처리되지 않았기 때문에
    U 집합이 비어 있음 → addvec 참조가 존재하지 않음.
  • 따라서 libvector.a의 어떤 오브젝트 파일도 E에 추가되지 않음.
  • 이후 main2.c를 처리할 때 addvec 참조가 생기지만,
    이미 libvector.a는 지나간 상태라 링커는 이를 해결하지 못함.

→ 결과적으로 undefined reference to 'addvec' 오류가 발생한다.


✅ 올바른 순서

라이브러리는 명령줄의 끝에 위치해야 한다.
이렇게 하면 링커가 모든 오브젝트 파일의 참조를 먼저 수집한 뒤,
그 참조를 해결하기 위해 라이브러리를 뒤에서부터 읽을 수 있다.


여러 라이브러리의 순서

linux> gcc foo.c libx.a libz.a liby.a

만약 foo.c가 libx.a와 libz.a의 함수를 호출하고,
이 두 라이브러리가 또 liby.a의 함수를 호출한다면,
libx.a와 libz.a는 반드시 liby.a 앞에 있어야 한다.

그렇지 않으면, liby.a에서 정의된 심볼을 찾지 못하게 된다.


반복 사용 (라이브러리 재참조)

필요하다면 명령줄에서 같은 라이브러리를 여러 번 명시할 수도 있다.

예를 들어:

linux> gcc foo.c libx.a liby.a libx.a

이 경우,

  • foo.c가 libx.a의 함수를 호출하고,
  • libx.a가 liby.a의 함수를 호출하며,
  • 다시 liby.a가 libx.a의 함수를 호출하는 경우에도
    모든 참조가 올바르게 해결된다.

대안적 방법

두 라이브러리(libx.a, liby.a)가 서로를 참조하는 경우라면,
두 라이브러리를 하나의 아카이브로 합치는 것도 좋은 해결책이 될 수 있다.

profile
there ain't no shortcuts

0개의 댓글