동적 링크된 ELF 프로그램에서 함수가 실제로 처음 호출될 때까지 주소 해석을 미루는 기법을 Lazy Binding이라고 한다.
즉, 프로그램이 시작될 때 모든 라이브러리 함수 주소를 계산하는 것이 아니라 필요한 순간에만 계산한다.
이 방식은 프로그램 실행 속도를 개선하고 메모리 사용을 줄이기 위해 사용된다.
PLT (Procedure Linkage Table)는 외부 라이브러리 함수를 호출하기 위한 코드가 들어있는 영역이다.
초기 호출 흐름은 다음과 같다.
초기 GOT 상태는 func@got = func@plt + 6 상태이고 그래서 첫 호출 시 다음과 같은 흐름이 만들어진다.
main -> func@plt -> func@got -> plt0 -> _dl_runtime_resolve -> func
두번째 호출 흐름은 다음과 같다.
main -> func@plt -> jmp [func@got] -> libc func
GOT (Global Offset Table)는 실제 함수 주소가 저장되는 테이블이다.
func@got -> libc func 주소
...
하지만 Lazy Binding에서는 프로그램 시작 시 GOT에 실제 주소가 들어있지 않다.

함수를 처음 호출할 때 plt가 먼저 호출되고 plt에서는 got를 참조하기 때문에 got로 jump하게 된다. 그리고 _dl_runtime_resolve 함수가 호출된다.
_dl_runtime_resolve(struct link_map *l, ElfW(Word) reloc_arg) ;
해당 함수의 인자는 reloc_offset과 link_map이다. 우선 reloc_offset은 아래의 구조체의 시작 주소를 얻기 위해 사용된다.
64bit에서는 reloc_arg = index
실제 relocation entry 주소는 rela = JMPREL + reloc_arg * sizeof(Elf64_Rela)
이기 때문에 오프셋이라기보다 인덱스에 가깝긴하다.
link_map 구조체는 링커가 런타임에서 라이브러리 함수들을 메모리에 매핑시킬 때 사용하는 구조체이다.
_dl_fixup(struct link_map *l, ElfW(Word) reloc_arg) ;
_dl_runtime_resolve 함수가 호출된 후 호출되는 함수는 _dl_fixup 함수이다. 해당 함수가 호출될 때 Elf32_Sym 구조체와 Elf64_Sym 구조체가 참조된다. 해당 구조체는 함수의 심볼테이블 엔트리에 해당된다.
_dl_lookup_symbol_x() 함수 호출do_lookup_x() 함수에서 검사Elf32_Sym 구조체 주소에 접근Elf32_sym->st_value는 실제 함수의 상대주소를 가진 상태-> **libc base + Elf32_Sym->value = 실제 함수 주소
resolved_addr = l->l_addr + sym->st_value
l->l_addr = libc base
_dl_runtime_resolve() -> _dl_fixup() -> _dl_lookup_symbol_x() -> do_lookup_x()