
프로그램을 컴파일할 때 자주 사용하는 함수들은 라이브러리(library)에 따로 구현하여 사용한다. 이때 함수들을 사용하기 위해 오브젝트 파일과 해당 라이브러리를 연결해주는 과정이 필요하다. 이 과정을 링킹(Linking)이라고 한다.
링크를 하는 방식에는 Static과 Dynamic이 있다.
- Static Link : 실행 파일 안에 모든 코드가 포함되기 때문에 라이브러리 연동 과정이 따로 필요 없고, 한 번 생성한 파일에 대해서 필요한 라이브러리를 따로 관리하지 않아도 된다. 따라서 해당 함수를 호출할 때, 라이브러리를 참조하는 것이 아니라, 자신의 함수를 호출하는 것처럼 호출한다.
- Dynamic Link : 실행 파일 안에 라이브러리 코드를 포함하지 않으므로, 함수를 호출하면 라이브러리에서 해당 함수의 주소를 찾아서 사용한다.
Dynamic Link 방식으로 컴파일했을 때 PLT와 GOT를 사용하게 된다.

PLT(Procedure Linkage Table)와 GOT(Global Offset Table)은 라이브러리에서 동적 링크된 심볼의 주소를 찾을 때 사용하는 테이블이다.
Dynamic Link 방식으로 프로그램이 만들어지면 함수를 호출할 때 PLT를 참조하게 된다. PLT에서는 GOT로 점프하게 되는데, GOT에 라이브러리에 존재하는 실제 함수의 주소가 쓰여있기 때문에 해당 함수를 호출할 수 있게 된다. 해당 과정을 통틀어 _runtime resolve_라고 한다.
아래 코드를 통해 위 과정에 대해서 알아보자.
// Name: got.c
// Compile: gcc -o got got.c -no-pie
#include <stdio.h>
int main() {
puts("Resolving address of 'puts'.");
puts("Get address from GOT");
}
먼저 got.c를 컴파일하고 실행한 직후에, `got` 명령어를 통해 GOT를 확인한다.

`puts`의 GOT 엔트리인 `0x404018`에는 아직 `puts`의 주소를 찾기 전이므로, 함수 주소 대신 `.plt` 섹션 어딘가의 주소인 `0x401030`이 적혀있다.
이제 `puts@plt`를 호출하는 함수 내부로 들어가서 확인한다.

PLT에서는 먼저 `puts`의 GOT 엔트리에 쓰인 값인 `0x401030`으로 실행 흐름을 옮긴다. 그 후 `_dl_runtime_resolve_xsavec`가 호출되는 것을 확인할 수 있다. 해당 함수에서 `puts`의 주소가 구해지고, GOT 엔트리에 주소를 쓴다.

위에서 보는 것과 같이, `_dl_runtime_resolve_xsavec` 함수가 끝난 뒤 다시 GOT를 확인해보면 libc 내 실제 `puts` 주소인 `0x7ffff7e0ce50`이 쓰여 있는 것을 확인할 수 있다.

이후에 다시 한번 `puts`를 호출하면 `puts`의 GOT에는 실제 `puts`의 주소인 `0x7ffff7e0ce50`가 쓰여있어서 바로 `puts`가 실행된다.