우선 Lazy binding에 대해서 알아보자.
Lazy binding이란?
리눅스 ELF 바이너리에서 라이브러리 함수의 시작주소를 구하지 않다가, 함수를 처음 호출할 때 해당 주소를 구하는 것이다. 우선 링커에 대해 알아보자
링커란?
오브젝트 파일을 하나의 실행파일로 결합해주는 도구이다.
링크의 과정
예를 들어서 printf 함수를 사용한다고 하자.
- include <stdio.h>를 선언하고 printf를 사용
- 컴파일
- 일련의 과정을 거쳐 오브젝트 파일이 생성, 하지만 오브젝트파일은 아직 printf가 무엇인지 모름
- 라이브러리의 printf의 구현 코드를 컴파일 한 오브젝트 파일을 기존 오브젝트 파일에 연결시킴
- 실행파일 생성
링크를 하는 방법에는 Static과 Dynamic 방식이 있다.
Static
- gcc 옵션중 static 옵션을 적용하면 Static Link 방식으로 컴파일 된다.
- 실행 파일 안에 모든 코드가 포함되기 때문에 라이브러리 연동이 필요없고 한 번 생성한 파일에 대해서 필요한 라이브러리를 따로 관리하지 않아도 된다
- 모든 코드가 포함되니 그만큼 파일 크기가 커지는 단점이 있고 모든 프로그램들이 동일한 라이브러리를 사용하더라도 각자 라이브러리 내용을 메모리에 매핑시켜야 한다.
- 라이브러리가 프로그램 내부에 있으니 함수의 주소를 알아오는 과정이 필요없다.
Dynamic
- 기본적으로 옵션을 안주면 Dynamic 방식이다.
- 공유라이브러리를 사용한다.
- 라이브러리를 하나의 메모리 공간에 매핑하고 여러 프로그램에서 공유하여 사용한다.
- 실행파일 안에 라이브러리 코드를 포함하지 않으니 Static Link 방식에 비해 파일 크기가 훨씬 작아지고 실행후에도 적은 메모리를 차지한다.
- 라이브러리를 따로 업데이트 가능하다.
- 실행파일이 라이브러리에 의존해야 하기 때문에 라이브러리가 없으면 실행할 수 없다.
- 라이브러리가 프로그램 외부에 있어 함수의 주소를 알아오는 과정이 필요하다.
이렇게 dynamic linking을 통한 라이브러리가 공유 라이브러리이다.
그러면 Lazy binding 과 반대되는 now binding이라는 것도 있는데 이는 무엇일까?
now binding이란
Lazy binding과 다르게 프로그램이 실행될 때 해당 프로그램에서 사용하는 모든 함수들의 주소를 읽어와 got영역에 저장하는 것이다.
static linking에 쓰인다. -> 개소리다. static linking은 바이너리에 이미 라이브러리가 포함되어있어서 binding이란 것 자체가 필요없다.
now binding은 Full Relro 보호기법에서 적용된다. Full Relro을 적용하면 got 에 쓰기 영역이 없기 때문에 바이너리 실행시 now binding을 하여 got에 주소를 전부 넣고 got에 쓰기 권한을 없에는 것이다.
dynamic 방식은 stack과 heap 사이에 공유 라이브러리가 매핑되어있는 것을 볼 수 있다.
static 방식은 공유 라이브러리가 없고 code영역에 라이브러리가 있다.
<틀린 부분이 있다면 비난과 욕설을 해주세요>