Notice
Recent Posts
Recent Comments
«   2025/02   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28
Tags
more
Archives
Today
Total
관리 메뉴

seven05

[CSAPP] 7.Linking 링킹 (7.1,7.4,7.9) 본문

SW JUNGLE 9기/CSAPP

[CSAPP] 7.Linking 링킹 (7.1,7.4,7.9)

박상비누 2024. 9. 4. 23:39

(7단원 전체를 볼수있으면 당연히 좋지만 시간이 모자라는 관계로 일단은 코치님이 강조하신 부분들만 볼수밖에없었다.

다음에 시간이 생기면 다시 추가로 공부해보자!)

 

링킹이란?: 링킹(Linking)이란 프로그램 코드 및 데이터의 조각들을 결합하여 메모리에 로드되어 실행될 수 있는 하나의 실행 파일을 만드는 과정

링커(Linker)는 링킹을 수행하는 프로그램,  각 모듈의 독립적인 컴파일을 가능하게 함

 

링킹을 공부해야하는이유?

  1. 큰 규모의 프로그램을 개발하면서 링킹과 관련된 에러를 많이 만나기때문
  2. 프로그래밍 언어의 스코프규칙이 어떻게 구현되는지 이해(지역변수와 전역변수의 차이 static의 의미)
  3. 공유 라이브러리를 활용할줄 알아야하기때문
  4. 링킹과 관련된 많은 시스템 개념들을 이해하기위해

링킹 종류

  1. 컴파일 타임에 이뤄지는 정적 링킹(Static Linking)
  2. 로드 타임 시 이뤄지는 공유 라이브러리의 동적 링킹(Dynamic Linking of Shared Libraries at Load Time)
  3. 런타임 시 이뤄지는 공유 라이브러리의 동적 링킹(Dynamic Linking of Shared Libraries at Run Time)

 

7.1 컴파일러 드라이버

예제 프로그램. main.c 와 sum.c로 구성

컴파일러 드라이버란 전처리기(preprocessor), 컴파일러, 어셈블러, 그리고 링커를 요구사항에 따라 차례대로 실행시켜주는 프로그램이다. 대표적으로 gcc 가 이에 해당한다.

Linux> gcc -Og -o prog main.c sum.c 

라고 입력한다고 가정해보자. gcc는 4번의 단계에 걸쳐서 실행가능한 객체(executable object)를 생성한다.

  1.  C 전처리기 cpp(C Preprocessor)를 돌린다. 이는 C 소스파일 main.c 를 ASCII 중간파일인 main.i로 번역
    cpp [other arguments] main.c /tmp/main.i
  2. C 컴파일러(cc1)를 돌려서 main.i를 ASCII 언어파일인 main.s로 번역
    cc1 /tmp/main.i -Og [other arguments] -o /tmp/main.s
  3. 어셈블러(as)를 돌려서 main.s를 재배치 가능한 목적파일인 main.o로 번역한다.
    as [other arguments] -o /tmp/main.o /tmp/main.s
    (sum.o도 위와 같은 과정을 반복해서 만들어준다.)
  4. 마지막으로 링커프로그램(ld)를 실행해서 실행가능한 목적파일 prog를 생성하기위해 main.o와 sum.o를 연결한다.
    ld -o prog [system object files and args] /tmp/main.o /tmp/sum.o

7.4 재배치 가능한 목적파일

(이 부분은 사진 한장과 함께 기능별로 구간이 나눠져있어서 이해를 한다기보다는 아 그렇구나의 느낌에 가깝다.)

위의 그림은 ELF포맷을 따르는 재배치 가능한 오브젝트 파일의 내부구조를 나타낸다.

  • ELF 헤더: word size나 byte 순서와 같은 시스템의 속성정보를 저장,링커가 이파일을 읽어서 분석할 때 알아야하는 정보들 저장 (헤더의 크기, 파일 유형, 타겟머신-유형 x86-64 등등)
  • .text: 컴파일된 프로그램의 기계어 코드들
  • .rodata: 문자열같은 상수나 switch 점프 테이블 같은 읽기전용값 저장
  • .data: 0이 아닌 값으로 초기화되는 전역 변수 및 static 변수(non-static 지역 변수는 스택에 저장됨)
  • .bss: (Block Started by Symbol) 0으로 초기화되거나 초기화 되지 않는 전역 변수 및 static 변수들이 저장. 프로그램이 실행되기 전까지는 메모리를 차지하지 않는다 ( 어차피 전부 0으로 초기화될 것이기 때문에 미리 공간을 차지하고 있을 필요가 없다.)
  • .symtab: 이 모듈에서 정의 or 참조 하는 모든 심볼들의 정보를 저장(함수, 전역변수, static 변수)
  • .rel.text: (relocation) 링킹 시 재배치가 필요한 .text 섹션 내 메모리 로케이션들의 정보 저장 (외부 함수를 호출하거나 전역변수를 참조하는 명령어들은 재배치가 필요하기때문)
  • .rel.data: (relocation) 링킹 시 재배치가 필요한 .data 섹션 내 메모리 주소 정보를 저장(bss의 데이터들은 어차피 0으로 초기화 되므로 재배치 작업이 필요가 없다.)
  • .debug: 정의 or 참조 하는 전역변수, C 소스 파일 등 디버깅에 필요한 정보들 저장 (-g 옵션에만 포함)
  • .line: 원본 C 소스 파일의 라인들과 .text 섹션에 존재하는 기계어 코드들의 맵핑 정보가 저장(-g 옵션에만 포함)
  • .strtab: .symtab 과 .debug 에 존재하는 문자열들을 저장
  • Section Header Table: 각 섹션의 크기와 위치 정보 저장

7.9 실행 가능 목적파일의 로딩

Linux x86-64 런타임 메모리 이미지 실제로는 alignment requirement에 의해서 각 부분 사이에 갭이 존재 ASLR(address space layout randomization) 또한 고려되지 않은 그림

Linux> ./prog -> 로더(loader) 실행 (로더는 메모리에 언제나 상주) ->  디스크에 있는 실행 파일로부터 프로그램의 코드와 데이터를 메모리에 복사 -> Entry Point에 해당하는 첫 번째 명령어의 주소로 점프함으로써 해당 프로그램을 실행

이러한 과정을 로딩(loading)이라 한다.

코드 세그먼트, 데이터 세그먼트, 런타임 힙(heap)(malloc을 할때마다 주소가 큰 방향으로 확장), 공유 라이브러리 영역, 유저 스택(유저가 접근가능한 가장큰 주소에서 부터 작은 방향으로 확장), 커널의 코드와 데이터를 위한 영역 순서대로 메모리 주소가 커지는 방향으로 예약된다

 

참조: CSAPP, [CSAPP] Linking (tistory.com), [CS:APP] Chapter 7. Linking (velog.io)