Skip to content

7. Linking {CSAPP}


  • traditional static linking at compile time
  • Dynamic linking of shared libraries at load time
  • Dynamic linking of shared libraries at runtime

링커가 중요한 역할을 맡게 된 데에는 모노리식으로는 감당하기 어려운 크기의 프로젝트들이 생겨나기 시작했고, 모듈이라는 개념과 독립적인 컴파일을 분리시키기 시작한 데에 있다. 그래서 모듈 하나를 수정하면 몽땅 다 컴파일 하는 것이 아니라 해당 모듈만 컴파일 하고, 링크만 잘 하는 식으로 이루어진다.

WHY 링킹을 배워야 하는가?

  • 다중 모듈로 이루어진 큰 프로그램을 작성하고 빌드하기 위해서임.
  • 잘못된 전역변수나 함수 따위를 참조하는 위험한 프로그래밍 에러를 피하기 위해서임.
  • 전역변수와 지역변수의 차이점, static 변수나 함수를 정의하는 이유에 대해 알 수 있기 때문!
  • 중요한 다른 시스템 컨셉을 이해하기 위해서임 로더, 가상메모리, 페이징, 메모리 매핑 어우 하나같이 다들 굵직하구만
  • 공유 라이브러리를 적극적으로 활용하기 위해서임.

발표자료 {7. Linking} {CSAPP}

DUMP#

  • ⭐️ 7.1. Compiler Drivers
  • 7.2. Static Linking
    • ld에 의해서 필요한 모든 객체파일들이 하나의 실행파일로 담기는 형태를 말한다.
    • symbol resolution, 목적파일들은 'symbol'이란 이름의 레퍼런스로 정의된다. 그 안에 함수, 전역변수, 정적변수 등에 대한 정의가 들어있다.
    • relocation 컴파일러와 어셈블러가 뽑아낸 산물은 주소값이 0번지부터 시작한다. 링커는 이 여러 목적파일들의 위치를 재정의한다.
  • 7.3. Object Files
    1. relocatable object file, 컴파일이 된 바이너리이지만 그 자체로 실행할 수는 없는 목적파일. 반드시 링커에 의해 컴파일 타임에 링크 되어야 한다.
    2. executable object file, 실행 가능한 목적파일로, 메모리에 곧장 복붙해서 실행될 수 있는 목적파일
    3. shared object file, 특별한 종류의 relocatable object file인데, 메모리에 올라가 동적으로 링크될 수 있음. 심지어 로드타임, 런타임 모두 가능.
  • ⭐️ 7.4. Relocatable Object Files (ELF File Format)
  • 7.5. Symbols and Symbol Tables
    • 같은 이름의 다른 함수에 들어있는 정적변수는 에러가 난다? 안난다? => 안나요 서로 다른 이름을 가지게 됩니다.
    • global symbols that are defined by module m and that can be referenced by other modules → nonstatic functions and global variables
    • global symbols that are referenced by module m but defined by some other module extern
    • local symbols that are defined and referenced exclusively by module m static
  • 7.6. Symbol Resolution
    • 심볼 참조작업은 먼저 모든 모듈을 돌면서 로컬 심볼이 모듈 안에서 유일한지 여부를 검사하는 것으로 시작한다.
    • 전역적으로 정의된 글로벌 심볼은 좀 더 까다로운데, 현재 모듈에 정의되어있지 않은 심볼 (선언만 되어있음)을 단순 외부에 정의되어 있다고 간주할 수밖에 없음.
    • 그러한 '정의되어있다고 간주한 심볼'들의 위치를 linker symbol table entry 에 보관한다. 컴파일러 책임은 아님. 링커의 책임임.
    • 7.6.1. 링커가 중복된 심볼 이름에 대처하는 방법
    • 7.6.2. 링커가 정적 라이브러리를 링크하는 방법
    • 7.6.3. 링커가 정적 라이브러리의 참조를 resolve 하는 방법
  • 7.7. Relocation
    • symbol resolution 작업을 마치면 relocation 작업을 수행한다. 링커 할 일도 많다.
    • 링커는 이미 연관 모듈들의 모든 .data 섹션들에 대한 정확한 사이즈를 알고있다.
    • 각각의 심볼들에게 '실행 시 위치할 주소'를 정의한다. (물론 그것이 실제 메모리 주소를 의미하는 것은 아닐 것이다.)
  • 7.8. Executable Object Files
    • 링커가 symbol resolution과 relocation 작업을 통해 relocatable object file을 executable object file로 만들었다. 👏👏👏👏👏👏
    • 그 안에는 꽤 많은 것들이 relocatable object file과 비슷하지만, 이젠 relocation 작업 덕분에 .text, .rodata, .data 영역들의 위치가 결정이 난 상태가 되었다.
    • .init 섹션이 추가가 됐는데, _init이라는 작은 함수를 프로그램 실행시 처음 호출하게 된다. .rel 섹션은 이제 더 이상 필요가 없다.
    • program header table 안에는 섹션들이 로드되어 세그먼트가 될 때의 매핑에 대한 정보가 들어간다. ELF 파일에서 섹션이었던 애들이 프로세스가 되면 세그먼트가 되는 식.
    • Pasted image 20230910104459.png
  • ⭐️ 7.9. Loading Executable Files
  • 7.10. Dynamic Linking with Shared Libraries
    • 공유 라이브러리는 메모리에 한 번만 로드되면 다른 프로세스들이 얼마든지 가져다 쓸 수 있다. (COW 안나오나?) 컴파일 시 -fpic 플래그를 달면 컴파일러가 PIC를 생성하며, -shared 플래그를 달면 링커에게 shared object file을 생성하라고 명령할 수 있다.
  • 7.11. Loading and Linking Shared Libraries from Applications
    • 리눅스는 동적 링커를 위한 간단한(?) 인터페이스를 제공한다. dlfcn.h 안에 dlopen, dlsym, dlclose, dlerror 함수.
    • 컴파일 시 -rdynamic 옵션을 넣어야 한다.
  • 7.12. Position Independent Code (PIC)

    • 메모리에 상주해 있는 라이브러리 코드를 공유하기 위해서 PIC가 존재한다.

    한 가지 접근 방식은 각 공유 라이브러리에 전용 주소 공간 청크를 선험적으로 할당하고 로더가 항상 해당 주소에서 공유 라이브러리를 로드하도록 하는 것입니다.

  • 7.13. Library Interpositioning

    • 라이브러리 교차? 공유 라이브러리 함수호출을 훔쳐다 내 코드를 호출하도록 만드는 기법을 의미함. 일종의 후크처럼 생각해도 좋겠다.
    • compile time interpositioning, link time interpositioning, run time interpositioning
  • 7.14. Tools for manipulating Object Files
    • ar 정적 라이브러리 생성툴
    • strings 목적파일 안에 들어있는 모든 문자열 리터럴들을 출력
    • strip 목적파일에서 symbol 테이블 정보를 제거
    • nm 목적파일 내 심볼 테이블 안에 정의된 모든 심볼 출력
    • size 목적파일의 각 섹션의 사이즈와 이름을 출력
    • readelf ELF 헤더로부터 목적파일을 인간이 볼 수 있게 디코딩해줌
    • objdump 목적파일의 모든 정보를 보여준다.
    • ldd 런타임에 필요한 공유 라이브러리들의 정보를 출력한다.
  • 7.15. Summary