Linking 이란 오브젝트(.obj) 코드를 executable binary code (.exe 바이너리 코드) 로 바꿔주는 녀석이다.
기본적으로 컴파일을 하면 Static Linking 이라는 것이 발생한다.
gcc 로 프로그램이 돌아가는 실행파일(.exe) 를 만들고 샆어서 인풋으로 아래처럼 2개의 c언어 파일을 넣었다면, Translator 컴파일러 에 의해 오브젝트(obj) 코드로 변환시켜준다.
이떄 main.c 와 sum.c 는 independent 하다. 즉 독립적이다. 각자 컴파일이 되는것이다. Translator 가 obj 파일을 만들기 전까지는 두 파일을 서로 independent 하다.
그런데 Linker 에 의해 실행파일(exe)를 만들때는 각 파일의 코드를 합쳐서 하나의 프로그램을 만들어야 하기때문에 이때부터는 dependent 하다.
즉 Linking 단계에서는 각 파일에 대해 로직이 돌아가고 데이터간의 dependency 를 봐야하므로 Linker(링커) 는 dependency 를 분석하고 여러 obj 파일을 하나로 합쳐주는 기능을 한다. 이게 Static Linking 이다.
=> 파일들은 최소한 기능별 단위로 쪼개는 것이 좋다. 한 파일에 여러 기능을 다 때려박아서 코드가 장황해지지 않도록말이다.
파일을 기능별로 잘 분할했다면, 특정 기능을 수정하고 싶은경우 해당 기능을 보유한 파일을 찾아가서 수정하면 된다. 다른 파일을 보지 않아도 된다. 즉 컴파일러 입장에서 보면, 다른 파일은 보지않고 특정 원하는 기능을 가진 파일에 대해서만 다시 컴파일하면 된다.
마지막에 linking 할떄는 컴파일이 다 된 놈들을 link 하는것이므로 다른 파일들을 컴파일 할 일이 없어진다.
만일 한 파일에 모든 기능을 다 넣었다면, 그 엄청난 양의 기능들을 가진 한 파일을 모두 싹다 다시 컴파일해야한다.
앞서 말한 내용이다. 특정 파일만 수정했다면 그 파일에 대해서만 다시 컴파일하면 되서, 시간 절약이 된다.
linker 가 컴파일 타이밍에 정적(static) 라이브러리를 exe 실행파일에다 가져다 붙인다. 이 방식은 비효율적이다. 라이브러리 용량이 크면 3시간도 넘게 걸릴수있다.
요즘은 이를 해결하기 위해 동적 라이브러리를 사용한다. 컴파일 타이밍에는 라이브러리의 정의(definition) 만 보고 적절하면 그냥 넘어간다.
그리고 프로그램을 실행하는 타이밍(runtime) 에, 즉 프로그램을 실행하면 어딘가 지정된 곳에 찾아가서 라이브러리를 필요한 부분만 계속 가져오는 방식이다. (비록 실행시간은 좀 더 걸려도, 컴파일 시간이 엄청 단축된다)
=> 사실 함수를 선언하고 호출하는 것인데, 이를 linker 에서는 다른말로 함수를 define(정의)하고 reference 한다고 표현하는 것이다.
( 함수 선언 = 함수 정의, 함수 호출 = 함수 reference(참조) )
그리고 각 함수, 변수등의 이름을 linker 에서는 symbol 이라고 표현한다.
(함수, 변수등의 이름 = symbol)
int *xp = &p; => xp 라는 symbol 을 정의하고, p 를 reference 하는것
=> 즉, 위 예제에서는 symbol 이 3개인 것이다. (swap, xp, p)
링커(linker) 는 모든 obj 오브젝트 파일들 돌면서 symbol 들을 모은다. 그리고 symbol 테이블을 만들고 그 symbol 들의 이름을 전부 저장한다. 이름을 저장하는 이유는 exe 파일에서 각 symbol 들이 전부 어딨는지를 저장하기 위함이다.
exe 파일은 원하는 symbol 을 사용하기 위해, symbol 테이블을 활용해서 어떤 곳으로 가야하는지 바로 알고 해당 구간으로 점프를 뛸 수 있다.
symbol 테이블은 기본적으로 c언어의 structs (구조체) 를 사용하며, 배열로써 보유하고 있는다.
symbol 테이블은 각 symbol 에 대한 이름, 크기, 그리고 위치를 보유하고 있는다.
따로 independent 하게 떨어져있던 obj 코드들을 하나로 merge 해준다.
각 obj 파일들은 각자 주소를 가지고 있을것이다. 각 주소에 떨어져있는 obj 파일들을 하나로 합쳐줘야 하니까, 각 symbol 들이 마지막에 exe 파일에서 어디에 가있어야하는지를 결정해줘야한다. 즉, obj 파일들간에 dependency 를 확인해서 파일들이 어떤 순서로 와있어야 하는지를 결정해준다.
=> 쉽게말해, obj 파일들을 하나로 합쳐준다. symbol 테이블을 활용하는데, symbol 하나당 obj 파일들이 있으므로 symbol 을 통해 어떤 순서로 코드가 실행되어야 하는지 depdency를 확인하고 obj파일들을 일렬로 실행되어야할 순서에 알맞게 정렬해준다.