링킹

여러 개의 코드와 데이터를 모아서 연결하여 메모리에 로드될 수 있고 실행될 수 있는 한개의 파일로 만드는 작업

컴파일, 메모리 로드, 실행 시에도 수행될 수 있음

컴파일러 드라이버

과정

  1. C 전처리기로 main.c를 main.i로 번역한다

    1. include된 헤더 파일의 내용과 define으로 정의된 변수들은 모두 대체된다

    예시

  2. C 컴파일러로 main.i를 어셈블리 언어 파일인 main.s로 번역한다

    어셈블리어 예시

  3. 어셈블러로 main.s를 바이너리 목적파일(재배치 가능)인 main.o로 번역한다

    1. 1 ~ 3의 동일한 과정으로 sum.o를 만든다
  4. 링커 프로그램(리눅스 → ld)를 실행하여 실행 가능 목적파일을 생성하기 위해 main.o와 sum.o를 연결한다.

  5. 실행파일을 실행하면 (./prog) 로더(loader)라고 불리는 운영체제 내의 함수를 호출한다.

    1. 코드와 데이터를 메모리로 복사하고, 제어를 프로그램의 시작 부분으로 전환

정적연결

리눅스 LD 프로그램과 같은 정적 링커들은 재배치 가능한 목적파일들명령줄 인자들을 입력으로 받아들여서 로드(ld -o prog /tmp/main.o /tmp/sum.o) ****될 수 있고 출력으로 완전히 링크된 실행 가능 목적파일을 생성한다.

실행파일을 만들기 위한 링커의 두가지 주요 작업

  1. 심볼 해석

    1. 심볼은 함수, 전역변수 또는 정적변수를 가리킨다
    2. 외부에 따로 정의된 이 심볼들을 연결해주는 역할을 한다
    3. 심볼 정의(키워드?)
      1. static

        파일 또는 함수 내에서만 사용할수 있게 제한

      2. extern

        외부의 심볼을 가져와서 사용

      3. inline

        함수 호출 대신 함수를 직접 복사해서 사용 간단한 함수를 호출할 때 성능 향상을 위해 컴파일러가 자동으로 변환

      4. Symbol Table

        컴파일러와 링커가 사용하는 함수, 변수 등의 이름 목록

        예시)

        이름 타입 위치 속성
        main 함수 .text global
        count 함수 .text global
        printf 외부 함수 (libc에서) extern
      5. Weak Symbol

        같은 이름의 다른 심볼이 있으면 그걸 쓰겠다 !!

  2. 재배치

    Weak Symbol

    이전에는 모든 함수/변수는 강한 심볼이었음. 그러다 일부 기능을 커스터마이징하여 사용하고 싶은 니즈가 발생하여 만들어짐

    모든 인터럽트를 처리하는 핸들러를 커스터마이징하고 싶을 때, 핸들러가 강한 심볼이라면 새로 정의했을 때는 충돌이 발생함. 핸들러를 약한 심볼로 만들어서 만약 사용자가 이름이 같은 핸들러를 정의했다면 정적 링크 타임에 오버라이드

    사용자가 정의한 함수나 변수는 특별한 조치를 취하지 않는 한 강한 심볼로 만들어짐

    __attribute__((weak)) void my_func() {
        // 약한 정의
    }
    
    

    GCC 기준으로 위처럼 만들어서 약한 심볼을 임의로 만들 수 있음

목적파일

재배치 가능 목적파일