PLT & GOT

Sisyphus·2022년 7월 16일
0

System Hacking - ELF 32

목록 보기
5/10

PLT와 GOT를 이해하려면 먼저 컴파일 과정 중 하나인 링킹에 대해 알아야 합니다.


우리가 printf() 함수를 이용해서 hello를 출력하는 hello.c 파일을 작성한 후 컴파일을 하면

// hello.c
#include <stdio.h>

int main() {
	printf("hello\n");
    
    return 0;
}

4가지 과정을 거쳐 소스 코드가 실행 파일이 됩니다.

  1. Pre-processor (전처리기) : 헤더 파일을 읽어와 소스 코드에 포함시킵니다.

  2. Compiler (컴파일러) :  hello.i 파일을 어셈블리어 파일로 변환합니다.

  3. Assembler (어셈블러) : 어셈블리어 파일을 기계어로 작성된 로직과 실행에 필요한 부가 정보들을 가진 목적 파일로 변환합니다.

  4. Linker (링커) : 여러 목적 파일들과 라이브러리를 합쳐서 실행파일을 만듭니다.


3번 과정에서 어셈블러에 의해 만들어진 목적 파일은 컴퓨터가 이해할 수 있는 기계어로 작성된 로직을 가지고 있는데, 실행이 불가능합니다.

왜 그럴까요? 그 이유는 printf() 함수를 호출해서 hello를 출력해야 하는데, 이 목적 파일이 printf() 함수의 코드를 가지고 있지 않기 때문입니다.

그럼 이 목적 파일을 어떻게 실행 가능한 파일로 만들까요?

printf() 같이 많이 사용되는 함수들이 들어있는 목적 파일 묶음인 라이브러리가 있는데, 링커가 이 라이브러리를 목적 파일과 연결시켜서 목적 파일을 실행 파일로 만들어줍니다.

이렇게 목적 파일과 라이브러리 파일을 연결시키는 것을 링킹이라고 합니다.

그리고 이 라이브러리는 리눅스에서는 .so 또는 .a 라는 확장자 파일로 윈도우 에서는 dll 파일로 존재합니다.

여기서 생기는 궁금증이 그냥 한 파일에 다 때려 넣으면 되지 왜 이렇게 파일들을 분리해놓고 링커로 다시 합치나 해서 찾아봤는데, 한 파일에 모든 소스 코드를 담을 수 없고 또 코드 재사용을 하기 위해서라고 합니다.


링킹에는 2가지 종류가 있는데, Static linking과 Dynamic linking이 있습니다.

Static Linking은 실행 파일을 생성할 때 라이브러리 내용을 포함하여 파일을 생성합니다.

실행 파일 안에 모든 코드가 포함되기 때문에 라이브러리 연동 과정이 필요 없습니다. 하지만 파일 크기가 크고 동일한 라이브러리를 사용하더라도 해당 라이브러리를 사용하는 모든 프로그램들은 라이브러리의 내용을 매핑 시켜야 합니다.


Dynamic Linking은 공유 라이브러리를 사용합니다. 라이브러리를 하나의 메모리 공간에 매핑 하고 여러 프로그램에서 공유하여 사용하게 합니다.

실행 파일 안에 라이브러리 코드를 포함하지 않기 때문에, static linking 방식에 비해 파일 크기도 작고 실행 시 메모리도 적게 차지합니다. 하지만 실행 파일이 라이브러리에 의존하기 때문에, 라이브러리가 없으면 실행이 불가능합니다.


이 Dynamic Linking의 공유 라이브러리 방식을 보면 왜 PLT와 GOT가 나왔는지 알 수 있습니다.

PLT(Procedure Linkage Table) : 외부 함수를 연결해주는 테이블로 PLT를 통해 다른 라이브러리에 있는 함수를 호출해서 사용할 수 있습니다.

GOT(Global Offset Table) : PLT가 참조하는 테이블로 함수들의 실제 주소가 들어있습니다.

PLT와 GOT는 Dynamic Linking으로 생성된 실행 파일들이 외부에 있는 공유 라이브러리에서 함수 호출을 위한 주소를 알아오기 위해 사용하는 테이블입니다.


공유 라이브러리에서 함수를 호출했을때 PLT와 GOT의 동작 과정을 살펴보면

*첫 함수 호출*

  1. printf() 함수 호출
  2. PLT 참조
  3. jump GOT
  4. 첫 호출의 경우 GOT에 함수의 주소가 없기 때문에 다시 PLT로 jump
  5. dl_resolve 함수를 사용해 함수의 주소를 알아오고 GOT에 주소를 씀
  6. printf()로 jump

*두 번째 함수 호출*

  1. printf() 함수 호출
  2. PLT 참조
  3. jump GOT
  4. printf()로 jump

0개의 댓글