

컴파일러가 Symbol Table을 만든다.
컴파일러가 각각의 소스파일을 컴파일해서 오브젝트 파일을 만든다. 거기서 정의된 함수 이름 글로별 변수들을 심볼테이블에 저장한다.
링커는 크게 두 가지 일을 한다.
초기 값을 가지지 않은 글로별 변수는 weak이다.
weak은 중복을 허락한다.
이 때문에 어느 정도 규모가 있는 프로젝트에서는 이것이 문제가 될 수 있다.
컴파일 타임에 컴파일러들은 모든 글로벌 심볼들을 strong이나 weak으로 분류한다. 이 정보는 심볼 테이블에 다 인코딩 되어 있다.
1번: 2개의 strong symbol이 존재 한다.
int x
p1() {}
--------------
p1() {}
2번: x가 같은 초기화되지 않은 int를 가리킨다. 이것이 원하는 결과는 절대 아닐 것이다.
int x;
p1() {}
----------
int x;
p2() {}
3번: x중에서 임의의 하나로 통일한다. 이러면 원치 않은 현상이 생긴다. y는 오버라이팅 될 수 있다.
int x;
int y;
p1() {}
-----------------------
double x;
p2() {}
4번: int로 선언되었고 초기화된 x로 오버라이딩된다. y에 대해 오버라이팅 된다.
int x=7;
int y=5;
p1() {}
------------------------
double x;
p2() {}
5번: 문제가 없다.
int x=7;
p1() {}
----------------------
int x;
p2() {}
결과적으로 위와 같은 방식의 코딩은 좋은 습관이 아니다.
가장 악몽적인 상황은 구조체가 weak이 되어서 링커가 아무거나 참조 해버리는 경우이다.
symbol resolution이 끝나면 relocation 한다.
컴파일러가 생성한 모든 파일들을 연결해서 메모리에 쌓는다.
같은 타입의 섹션들을 모아 세그먼트들을 만든다.
이후 위치가 정해지기 때문에 심볼들에게 제대로된 위치를 할당한다.
int e=7;
int main() {
int r = a();
exit(0);
}
----------------------------------------
extern int e;
int *ep=&e;
int x=15;
int y;
int a() {
return *ep+x+y

함수에 대한 정의는 difinition 함수에 대한 콜은 reference가 된다.
symbol resolution에서 이 둘이 연결된다.
내부 파일에 있는 것은 로컬 외부 파일에 있는 것은 external이 된다.