카테고리 없음

시스템 프로그래밍(10) - Linking

gilola 2024. 12. 14. 02:01

Static linking는 build 때 함수 주소가 결정된다.

Translators에 의해 1차로 relocatable object file이 생성되고 Linker에 의해서 완전히 실행가능한 object file로 바뀌는듯

relocatable: 주소가 고정되지 않고 실행시 주소가 재배치 되는 것

 

왜 Linker 를 쓰는가?

1. Modularity (재사용성)

-> 여러 개의 작은 소스 파일로 나누어 작성

-> library는 자주 사용되는 공통 함수들을 모아둔 파일

2. Efficiency (효율성)

-> Time: 개별 compile 하여 모든 소스 파일이 recompile 할 필요 X

-> Space: 실행 파일/ 메모리에는 library 에서 사용한 함수만 포함

-> 주소 미결정 => marking => linker가 그 부분의 실제 주소로 변경

 

Linker가 하는일?

1. Symbol resolution (미결정된 부분을 채워넣음)\

-> symbole : global 변수, 함수

-> symbol의 정의는 symbol table에 저장

   -> 구조체 배열로 구성 (심볼의 이름, 크기, 위치 등)

-> linker가 각 symbol reference 를 정확히 하나의 symbol definition과 연결

2. Relocation (재배치)

-> code와 data를 병합

-> 상대적 위치에 있던 symbol들을 executable file에서 절대 memory 위치로 이동

-> symbol에 대한 모든 reference를 새로 update

 

Object file 종류 3가지

1. relocatabel object file

-> .c 하나당 .o 파일 생성

2. executable object file

-> 모든 code와 datat를 포함하는 실행 가능한 파일

3. shared object file

-> load/run-time 때 동적으로 연결될 수 있음

 

ELF(executable and linkable format)

-> header에 text와 data를 구분하는 정보를 담고 있음

-> 세가지 종류의 object file 에 대해 통합된 형식 제공

 

 

.data: 초기화 된 global변수 저장

.bss section: 초기화 되지 않은 global 변수 (weak) 저장

.rel.txt: text 재배치 정보

.rel.data: data 재배치 정보

Section Header Table: 각 섹션의 offset, size 정보

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Symbol 종류 3가지

1. Global (내보내는 symbol)

-> non-static 함수/ global 변수

-> 다른 모듈에서 참조될 수 있음

2. External (가져오는 symbol)

-> 다른 모듈에서 정의된 global symbol

3. Local (하나의 소스 파일 내에서만 사용)

-> static 함수/ global 변수

왼쪽에서 sum은 external main, array는 global val,i,s 는 local 변수이므로 symbol이 아님

Local Symbol

->local non-static 변수는 stack 에 저장

->local static 변수는 .bss 나 .data에 저장

두 x는 .data 영역에 각각 저장

Strong vs Weak

-> Strong symbol은 초기화 됨

-> weak symbol은 선언만 됨

 

Linker Rules

1. 다수의 Strong symbol 금지

2. Strong 이 Weak 보다 우선순위 높음

3. Weak만 여러개라면 임의의 하나를 고름

 

x는 4byte고 double은 8byte이므로 왼쪽 x가 선택될 때, 오른쪽 x가 수정되면 y에도 영향을 줄 수 있음

 

그래서 Global  변수는 최대한 피해야함

-> Static 써서 다른 소스 파일에 공유 x

-> 초기화를 할 것

-> extern을 쓸 것

 

relocation entry

relocation에 필요한 정보를 사전에 저장해 둔 것이다.

 

실행 가능한 obj 파일 Load

재배치가 끝난, 실행 가능한 obj 파일은 하드디스크에 존재한다.

이를 '실행한다'라는 것은, 실행에 필요한 부분을 메모리에 하나하나 꺼내오며 실행한다는 뜻이다.

Memory-mapped region for shared libraries

-> 공유 library를 실행 중인 프로세스의 가상 메모리에 매핑

 

함수를 효율적으로 packaging 하는 법

1. 모든 함수를 하나의 소스파일에 넣기

-> 공간, 시간 비효율

2. 각 함수를 별도의 소스 파일로 분리

-> 프로그래머에게 부담

 

Static Libaray

-> 연관된 재배치 가능한 obj 파일들을 하나로 묶어 관리하기. (archive)

-> ex) libc.a 나 libm.a 

-> 링커는 순서대로 참조를 확인하므로, 라이브러리를 명령 끝에 배치해야함

 

이렇게 archiver를 통해 obj 파일들을 묶어서 하나의 실행 가능한 obj 파일이 생성

Static library 장점

1. 관련 함수를 묶어서 관리 가능

2. 변경된 함수만 재컴파일하여 .o 파일을 아카이브에 교체 가능

 

Static library 단점

1. 실행 프로그램 데이터의 중복

2. library 함수를 executable file에 포함하므로 저장 공간 낭비

3. 버그 수정시 모든 실행파일에 대해 relink

 

Shared Libary

-> 동적으로 load, link 됨

-> ex) .dll, .so

 

Dynamic Linking

1. Load-time 

-> main 호출 전에 linking 완료

->  실행 파일이 처음 로드 될 때 lib를 동적 연결

-> linking error에 취약

2. Run-time

-> 프로그램 실행 중 필요할 때 lib를 동적 연결

-> dlopen() 사용

 

Dynamic Linking 장점

1. 공유 메모리

-> 여러 프로세스가 동일한 공유 lib 코드를 동시에 사용

2. 유연성

-> lib를 수정해도 애플리케이션을 다시 compile하지 않아도 됨

 

1차로 link 하고 load 한 후 2차로 dynamic link

* linking API를 통해 link 할 수도 있음

 

 

 

** 추가 자료

Library Interpositioning

-> 임의로 함수 호출을 가로챌 수 있도록 하는 링크 기술

-> 보안, 디버깅, 모니터링 및 프로파일링에서 사용

 -> 프로그램을 중단시키거나 소스 코드를 수정하지 않고 malloc 및 free 메모리 블록의 주소와 크기를 추적

 

Interpostioning 방법 3가지

1. Compile time

-> malloc/free에 대한 호출을 매크로 확장을 통해 mymalloc/myfree 호출로 변환

2. Link time

-> 링커 트릭을 사용하여 특수한 이름 해석 수행

-> malloc => __wrap_malloc

-> __real_malloc => malloc

3. Load/Run time

-> 동적 링크를 사용하여 라이브러리의 malloc/free를 다른 이름으로 로드하는 커스텀 malloc/free 버전 구현