#Software Engineering Aspects
#Static Libraries
정적 라이브러리(static library) 또는 정적 링크 라이브러리(static-linked library)는 컴파일 시 호출자에서 해결되고 컴파일러, 링커 또는 바인더에 의해 대상 응용 프로그램으로 복사 되어 객체 파일과 독립 실행 파일을 생성하는 일련의 루틴, 외부 함수 및 변수이다.
- 일반적으로 사용되는 함수를 개체 .o 모듈로 미리 컴파일하고, 그 .o 모듈을 .static 라이브러리라고 불리는 archive로 패키징한다.
- .a archive는 간단한 순차 archive를 생성하는 ar(1) 명령에 의해 유지 관리된다.
- 중요: .o 모듈은 archive에 포함되거나 전혀 포함되지 않기 때문에 C 라이브러리(libc) 또는 Math 라이브러리(libm)와 같은 일반적인 라이브러리는 수천 개의 .o 파일을 포함한다.
- 링커는 링크 프로세스에 포함할 .o 모듈을 어떻게 선택할까?
- 라이브러리 간의 dependency, 즉 라이브러리 B의 모듈 2.o에 정의된 라이브러리 A에 외부 참조 R이 있는 경우, 라이브러리 간의 종속성은 어떻게 처리될까?
#A closer look at the linking process (sans libraries)
- 링커는 command-line에 지정된 순서대로 .o 모듈을 처리한다
- 이미 처리된 일부 모듈에 의해 정의된 전역 기호 집합 D를 유지한다.
- 이미 처리된 일부 모듈에서reference했지만 아직 정의가 나타나지 않은 전역 기호 집합 U를 유지한다.
- 처리된 각 .o 모듈에 대해, 이미 D에 있지 않은 경우 U에 새로운 외부 reference를 추가한다.
- D에 추가하고 U에서 이 .o 모듈에 의해 정의된 전역 기호를 제거한다(D에 이미 있는 경우 "multiply defined" 오류 보고).
- 마지막에 U에 기호가 남아 있는 경우 "undefined symbol" 오류를 보고함.
- 이 설명은 전역 기호에만 적용됨. 로컬 기호 참조는 항상 해당 로컬 기호 정의에서 확인된다
#Extending the linking process to static libraries
- 규칙: 라이브러리를 처리할 때 링커는 현재 U 집합에 있는 기호를 정의하는 경우에만 이 라이브러리의 .o 모듈을 포함한다
- 위에서 "현재"는 command line에 지정된 처리 순서에서 위치를 나타낸다.
- 라이브러리의 다른 .o 모듈에서 참조하는 기호를 정의하는 동일한 라이브러리의 .o 파일이 포함된다.
- 장점:
- 필요한 .o 파일만 포함
- 먼저 나열될 라이브러리의 정의를 지정하여 라이브러리 기호를 재정의할 수 있다
- 단점:
- 링크 동작은 command-line에 .o 파일과 라이브러리가 나열되는 정확한 순서에 따라 달라진다
- 라이브러리를 특정 순서(클래식 -lXm -lXt -lX11)로 나열하거나 상호 dependency가 있는 경우 여러 번 나열하거나 특수 링커 그룹화 옵션(--start-group/--end-group)을 사용해야 할 수 있다
- 오류가 발생하기 쉽고 혼동하기 쉽다
- 링커 맵은 링커가 기호를 확인하는 방법을 추적하는 데 좋다.
#Drawbacks of Static Libraries
- 많은 프로그램에서 기능을 사용하는 경우 코드 복제
- 예: c 라이브러리
- 파일 시스템에 대용량 실행 파일을 저장하기 위한 비용
- 이러한 실행 파일을 로드하는 각 프로세스에 대해 더 많은 메모리가 필요한 비용. 동일한 라이브러리를 사용하더라도 프로세스 간에 이 메모리를 공유할 수 없음
- 모든 업데이트를 수행하려면 해당 코드를 사용하는 각 실행 파일의 재컴파일(및 재배포)이 필요하다.
- 시스템 라이브러리에 업데이트를 푸시하는 데 비용이 많이 든다
- 그 반대는 정적으로 연결된 바이너리가 모든 dependency을 포함하고 있으며, 기본 OS가 API/ABI라는 시스템을 지원하는 한 작동한다(Linux는 여전히 1990년대에 구축된 바이너리를 실행함).
#Shared Libraries
- 공유 개체(.so) 또는 Windows에서 dynamic-link libraries(DLL)로 불림
- shared library는 런타임에 프로세스의 가상 주소 공간에 로드된다
- 이는 동적 링커/클라이언트(LD linux.so/ld-linux-x86-64.so(Linux의 경우)와 빌드 도구의 협력을 통해 구현된다.
- 실행 파일에 로드 시 해결될 외부 참조(U)가 여전히 포함되어 있다
- recursive: 동적으로 연결된 라이브러리가 dependency를 가질 수 있다
- 또한 플러그 인 기반 시스템이나 응용 프로그램에서 처럼 런타임에 공유 개체를 로드 하려는 프로그램을 위해 dlopen을 통해 직접 액세스할 수 있다
- flexible API
- 이러한 공유 객체의 메모리는 서로 다른 가상 주소에 위치하더라도 여러 프로세스에 의해 공유될 수 있다(메모리는 읽기 전용이어야 하며 콘텐츠가 매핑된 위치에 종속되지 않아야 함).
- 프로그램과 라이브러리가 정적으로 연결된 것처럼 동일한 의미론(semantics)을 유지한다
#Implementation of Shared Libraries
- Position-Independent code(라이브러리 내 참조를 처리함)
- 64비트 x86: PC 상대 주소 지정 모드 / PC-relative addressing mode ($rip)
- 32비트 x86: $eip의 값를 얻기 위해 "PC 구체화" 트릭 필요
- Indirection (라이브러리 간 참조 또는 실행 파일에서 라이브러리로의 참조에 필요)
- 라이브러리가 변수 x에 대해 전역 함수를 정의하는 경우, f 및 &x 주소는 라이브러리가 로드될 때까지 알 수 없다
- Solution: 간접 함수 호출(PLT(Procedure Linking Table)의 entries을 통해)
- trampolines을 통한 주문형 로딩: 첫 번째 액세스 트리거가 동적 링커로 점프한다
- 후속 점프는 로드된 기능으로 직행한다
- 일반적으로 공유 라이브러리는 런타임에 한계 비용(marginal cost)을 발생시킨다.
'Computer Science > Computer Systems' 카테고리의 다른 글
[Lecture 10] 멀티쓰레딩 IV - Condition Variables & Monitors (1) | 2022.10.09 |
---|---|
[Lecture 8] 멀티쓰레딩 II - Basic Locking / Managing Shared State (0) | 2022.10.08 |
[Lecture 6] Linking and Loading - Part II (0) | 2022.09.22 |
[Lecture 6] Linking and Loading - Part I (0) | 2022.09.22 |
[P1] The Customizable Shell (0) | 2022.09.20 |