심볼 해석(symbol resolution) 단계에서,
링커는 명령줄에 나타난 순서대로
재배치 가능한 오브젝트 파일들과 정적 라이브러리(archive)를 왼쪽에서 오른쪽으로 스캔한다.
(컴파일러 드라이버는 .c 파일 이름을 내부적으로 .o 파일로 변환하여 링커에 전달한다.)
이 과정에서 링커는 세 개의 집합을 유지한다:
초기에는 E, U, D 모두 비어 있다.
명령줄의 각 입력 파일 f에 대해,
링커는 f가 오브젝트 파일인지 아카이브(라이브러리)인지 확인한다.
f가 오브젝트 파일이면:f를 E에 추가하고,f의 심볼 정의 및 참조 정보를 기반으로 U와 D를 갱신한 뒤,만약 f가 라이브러리(archive) 라면:
링커는 U에 있는 아직 해결되지 않은 심볼들이
라이브러리 안의 어떤 멤버 오브젝트 파일의 정의와 일치하는지 검사한다.
m이 U에 있는 심볼을 해결한다면,m을 E에 추가하고,U와 D를 갱신한다.이 과정은 U와 D가 더 이상 변하지 않을 때까지 반복된다.
그 이후, 참조되지 않은 나머지 멤버 오브젝트 파일들은 무시된다.
링커가 명령줄의 모든 입력 파일을 처리한 뒤에도
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가 처리되지 않았기 때문에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)가 서로를 참조하는 경우라면,
두 라이브러리를 하나의 아카이브로 합치는 것도 좋은 해결책이 될 수 있다.