5. 심볼들과 심볼 해석

모든 재배치 가능한 오브젝트 파일들은 심볼 테이블과 그와 관련된 심볼들을 가지고 있다. 링커의 관점에서 볼 때 심볼들을 다음과 같이 분류할 수 있다.

링커는 심볼의 참조를 해석할 때, 입력으로 주어지는 재배치 가능한 오브젝트 파일의 심볼 테이블로부터 꼭 하나만 존재하는 심볼의 정의를 참조하여 심볼 참조를 해석한다. 지역 심볼(local symbol)은 그에 대한 다중 정의(multiple definitions)를 심볼 테이블이 가질 수 없으므로 쉽게 해석된다. 그러나 전역 심볼의 해석은 약간의 트릭이 요구된다. 컴파일 타임때, 컴파일러는 전역 심볼들을 strong 혹은 weak한 것으로 만드는데, 함수들과 초기화된 전역 변수들은 strong하게, 초기화되지 않은 변수들은 weak하게 만든다. 그러면 링커는 아래의 룰을 적용하여 심볼들을 해석하게 된다.

  1. 다중 strong 심볼들은 허가되지 않는다.

  2. 하나의 strong 심볼과 여러개의 weak 심볼들이 있으면, strong 심볼을 선택한다.

  3. 여러개의 weak 심볼들이 있으면, 그것들중 아무거나 선택한다.

예로, 다음과 같은 두 프로그램의 링킹은 링크-타임 에러를 낸다.

/* foo.c */

int foo() {
	return 0;
}
/* bar.c */

int foo() {
	return 1;
}

int main() {
	foo();
}

foo (전역 함수로써 strong 심볼이다)가 두 번 정의 되었으므로, 링커는 아래와 같은 에러 메세지를 낸다.

gcc foo.c bar.c

/tmp/ccM1DKre.o: In function 'foo':

/tmp/ccM1DKre.o(.text+0x0): multiple definition of 'foo'

/tmp/ccIhvEMn.o(.text+0x0): first defined here

collect2: ld returned 1 exit status

collec2는 GCC에 의해 호출되는 링커 ld의 wrapper이다.