Part1) CH3. 목적 파일

songtofu·2022년 11월 20일
0

전문가를 위한 C

목록 보기
3/10

앞서

  • 프로젝트의 결과물 = 재배치 가능한 목적 파일, 실행 (목적) 파일, 정적 라이브러리, 공유 목적 파일
  • 재배치 가능한 목적 파일은 임시 결과물로 간주, 최종 결과물을 만드는 재료

3.1) ABI(응용프로그램 인터페이스)

  • 모든 라이브러리나 프레임워크는 사용된 기술이나 프로그램 언어와 상관없이 특정한 기능을 제공 == 응용프로그램 인터페이스(API)

  • 라이브러리를 사용하려면 API를 사용해야함.

  • API는 두 소프트웨어 컴포넌트가 서로를 사용하거나 서로 기능을 제공할 때 수용하는 규칙(=표준)

    ABI vs API
    - API: 두 소프트웨어의 컴포넌트 간 호환성을 보장해 기능적으로 계속 협력
    - ABI: 두 프로그램이 기계 수준의 며열ㅇ어 수준에서 호환 가능하도록 두 프로그램의 목적 파일을 함께 사용할 수 있게 함.

  • ABI는
    1. 대상 아키텍처의 명령어 집합
    2. 기존의 자료형과 크기 및 정렬 규칙
    3. 함수 호출 규칙
    4. 유닉스 계열 시스템에서 시스템 호출 방식 정의
    5. 사용된 목적 파일 형식
    6. C++ 컴파일러로 생성한 목적 파일의 네임 맹글링, 가상 테이블 레이아웃

    3.2) 목적 파일 형식

  • 리눅스와 다른 유닉스 계열 운영체제 = ELF

  • OS X(maxOS 및 iOS) = Mach-O

  • 마이크로소프트 윈도우 = PE

    3.3.) 재배치 가능한 목적 파일

  • 컴파일 파이프라인에서 어셈블리 단계의 결과물

  • C 언어 프로젝트의 임시 결과물로 간주, 이후 최종 결과물을 만드는 주재료

  • 재배치 가능한 목적 파일에서는 컴파일된 변환 단위와 관련해 다음 항목을 찾을 수 있다.
    1. 변환 단위에서 발견되는 함수에 대해 생성된 기계 수준의 명령어(코드)
    2. 변환 단위에서 선언된, 초기화된 전역 변숫값(데이터)
    3. 변환 단위에서 정의된 심벌 및 참조된 심벌을 모두 포함하는 심벌테이블

  • 재배치 가능한? 링커가 수행하는 과정에서 비롯됨. 링커는 재배치 가능한 목적 파일 여러개를 한데 모아서 더 큰 목적 파일을 형성. 하나의 재배치 가능한 목적 파일에서 나타나는 기계 수준의 명령어는 다른 재배치 가능한 목적 파일에서 나온 기계 수준의 명령어 다음에 위치. -> 명령어가 이동할 수 있거나 재배치 가능 하다는 점을 의미.

  • 따라서, 재배치 가능한 목적 파일에서 명령어는 주소를 갖지 않는다. 링크를 단계를 거치고 나서 명령어는 주소를 가진다.

  • readelf -hSl funcs.o 유틸리티를 사용해서 funcs.o 목적 파일의 ELF 내용을 확인 할 수 있다.

  • 재배치 가능한 목적 파일은 11개의 섹션이 있음.

  • .text 섹션은 변환 단위를 위한 모든 기계 수준의 명령어를 포함

  • .data.bss 섹션은 초기화된 전역 변숫값과 초기화되지 않은 전역 변수에 필요한 바이트의 숫자를 각각 포함.

  • .symtab섹션은 심벌 테이블을 포함

  • 재배치 가능한 목적 파일의 심벌은 어떠한 최종 혹은 절대 주소를 갖지 않으며, 주소는 링크 단계에서 결정

    3.4) 실행 가능한 목적 파일

  • 재배치 가능한 목적 파일처럼 실행 가능한 목적 파일도 기계 수준의 명령어, 초기화된 전역 변숫값, 심벌 테이블과 같은 항목을 가진다. 그러나! 정렬은 다를 수 있음.

  • ELF 실행 가능한 목적 파일에는 더 많은 섹션이 있다. 이들은 몇몇 세그먼트와 함께 있음.

  • 각 세그먼트는 많은 섹션(0~그 이상)으로 구성, 섹션은 내용에 따라 세그먼트에 놓임.

  • 기계 수준의 명령어를 포함하는 모든 섹션은 같은 세그먼트에 들어간다.

  • readelf -hSl ex3_1.out의 ELF 내용 출력을 볼 때 알아야할 사항

    1. ELF의 관점에서 목적 파일의 유형은 공유 목적 파일이라는 것을 알 수 있음. 즉, ELF에서 실행 가능한 목적 파일이란 INTERP와 같은 특정 세그먼트를 갖는 공유 목적 파일. 로더 프로그램이 이 세그먼트를 이용해 실행 가능한 목적 파일을 로드함.
    2. 4개의 세그먼트를 잘 보라. 첫 번째 INTERP는 위에서 설명. 두 번째는 TEXT세그먼트 = 기계 수준의 명령어를 갖는 섹션을 모두 포함. 세 번째는 DATA세그먼트 = 전역 변수를 초기화할 때 사용할 모든 값과 다른 초기 구조체를 포함. 네 번째 세그먼트는 동적 링크와 관련한 정보를 찾을 수 있는 섹션을 나타냄. 동적 링크와 관련한 정보로는 실해의 일부로 로드해야 하는 공유 목적 파일이 있음.
  • 여러 개의 재배치 가능한 목적 파일을 링크한다는 것은 주어진 재배치 가능한 목적 파일에서 모든 유사한 섹션을 모아서 더 큰 섹션을 형성하고, 이렇게 모은 섹션을 실행 혹은 공유 목적 파일로 만드는 일이다. 그러므로, 링크를 거쳐야 심벌이 마무리 되고 변하지 않는 주소를 가짐.

  • 실행 가능한 목적 파일에서 주소는 절대적이다. 그러나 공유 목적에서는 상대 주솟값이 절대적.

    상대 주솟값
    - 메모리 공간에서 사용자 영역이 시작되는 주소 번지를 0번지로 변경하여 사용하는 주소 지정 방식

  • readelft -s ex3_1.out 명령어를 사용해 심벌 테이블을 볼 수 있음.

  • 하나의 실행 가능한 목적 파일에 2개의 다른 심벌 테이블이 있음. 첫 번째 심벌테이블인 .dynsm은 실행 파일을 로드할 때 해결할 심벌을 포함. 두 번째 심벌 테이블인 .symtab은 동적 심벌 테이블에서 가져온, 미해결된 심벌과 함께 해결된 심벌도 모두 포함. 즉, 두 번재 심벌 테이블은 동적 테이블의 미해결 심벌도 포함한다.

  • 심벌 테이블에서 해결된 심벌은 링크 단계에서 획득한 주소에 해당하는 절대 주소를 가진다.

    3.5) 정적 라이브러리

  • C 프로젝트에서 얻을 수 있는 결과물 중 하나

  • 재배치 가능한 목적 파일에서 만들어지는 유닉스 아카이브이다.

  • 정적 라이브러리 그 자체는 목적 파일로 볼 수 없음. 목적 파일을 위한 컨테이너

  • 정적 라이브러리는 유닉스의 ar 유틸리티로 파일을 아카이브

  • 링커가 링크 단계에서 정적 라이브러리를 사용하려 할 때, 우선 재배치 가능한 목적 파일에서 정적 라이브러리를 추출하려고 시도. 다음 거기서 정의되지 않은 심벌을 찾아 해결

  • 정적 라이브러리는 하나의 아카이브에 이전의 재배치 가능한 목적 파일 모두를 포함

  • main 함수가 없으면, 정적 라이브러리를 만드는 재배치 가능한 목적 파일로 두거나 아카이브로 둘 수 있다.

  • ar t opt/~~~/~~.a 명령어를 사용해 아카이브 파일의 내용을 볼 수 있다.

  • C 언어 라이브러리 사용하려면 정적 라이브러리 파일과 함께 라이브러리가 제공하는 선언에 접근해야함. 이 선언은 라이브러리의 공용 인터페이스(일반 적으로 라이브러리의 API라고 간주)

  • 컴파일 단계(컴파일러가 자료형의 존재나 함수 시그니처 등을 알아야 하는 단계)에서는 선언 필요. 이 내용은 헤더에 있음.

  • 링크 이후에 정적 라이브러리 파일에 의존하는 것은 아무것도 없음. 모든 것은 실행 파일 그 자체의 내부에 임베드되어 있음. = 자기 자신만으로도 실행 가능

  • 작은 이진 파일을 가질 수는 있지만 공유 라이브러리를 사용해야함. = 외부의 공유 라이브러리가 없거나 찾을 수 없느 ㄴ경우에 최종 이진 파일은 완전 X 실행 될 수 X = 이진 파일의 크기와 이진 파일이 갖는 의존성 사이에 트레이드 오프 존재

    3.6) 동적 라이브러리

  • 재사용을 위한 라이브러리를 만드는 또 다른 방식

  • 그 자체가 실행 파일에 해당하지 X

  • 실행을 위한 프로세스가 로딩될 때 가져와서 로드되어야 함.

  • 정적 라이브러리가 실행 파일의 일부이므로, 링커는 주어진 재배치 가능한 파일의 모든 것을 최종 실행 파일에 넣는다. = 링커는 정의도지 않은 심벌을 감지하고, 정의가 필요하며, 이 를 주어진 재배치 가능한 목적 파일에서 찾고자하고, 그렇게 출력되는 최종 파일에 모든 것을 집어 넣는다.

  • 동적 라이브러리의 경우 정의되지 않은 심벌 가질 수 있음. 이는 링크단계에서 해결 X. 실행 파일이 로드되고 실행을 시작할 때 이 심벌을 검색
    = 정의되지 않은 동적 심벌을 찾고자 할 때 다른 종류의 링크 단계가 필요. 실행 파일을 로드하고 프로세스로 실행될 준비를 할 때, 동적 링커 혹은 간단히는 로더가 이 링크를 수행

  • 정의되지 않은 동적 심벌은 공유 목적 파일에서 로드해야함. 공유 목적 파일은 정적 라이브러리 파일의 자매 격인 파일.

  • 프로세스를 로드하고 실행할 때, 공유 목적 파일이 로드되며 프로세스가 접근할 수 있는 메모리 지역에 이 파일이 연결. 이 절차는 동적(or 로더)에 의해 수행, 동적 링커는 실행 파일을 로드하고 실행

  • ELF 실행 가능한 목적 파일과 ELF 공유 목적 파일간의 차이

    1. 심벌이 상대적인 절대 주소를 가지며 이 주소를 통해 심벌이 여러 프로세스에 동시에 로드되도록 한다. 각 명령어의 주소가 프로세스에서 다른 한편, 두 명령어 사이의 거리는 고정되어 있음. (= 주소는 오프셋에 상대적으로 고정) 재배치 가능한 목적 파일이 위치 독립적이기 때문
    2. ELF 실행 가능한 목적 파일에 관련된 세그먼트가 공유 목적 파일에는 존재하지 않는다. = 공유 목적 파일이 실행될 수 없음
  • gcc -c hello.c -fPIC -o hello.o 의 -fPIC는 위치 독립적인 코드를 나타냄.

  • 재배치 가능한 목적 파일이 위치 독립적이라면, 파일 안의 명령어가 고정 주소를 갖지 않는다는 의미. 대신 상대주소를 가짐. 다른 프로세스에서 다른 주소를 가질 수 있다. 공유 목적 파일을 사용하는 방식 때문에 이는 필수 조건.

  • 공유 목적 파일을 만들려면 컴파일러 필요. 공유 목적 파일은 단순한 아카이브이며, 공유 목ㅈ거 파일ㅇ느 그 자체로 목적 파일이다. 재배치 가능한 목적 파일을 만들려면 사용한 것과 동일한 ㄹ이커 프로그램응로 생성해야함.

  • -shared 옵션을 gcc에 전달 = 재배치 가능한 목적 파일에서 공유 목적 파일을 생성하도록 지시

  • 동적 라이브러리와 링크

  • 동적 라이브러리는 최종 실행 파일에 임베드되지 않는다. 실행할 때 라이브러리 로드.

  • 만약 지정 경로에 정적 라이브러리와 공유 목적 파일이 둘 다 존재, gcc는 공유 목적 파일을 선택해 프로그램과 링크

  • 프로그램 로더 기본 탐색 경로에서 .so파일을 찾을 수 없을 떄 오류 발생. 이를 해결하려면 환경변수 LB_LIBRARY_PATH가 올바를 경로를 가리키도록 업데이트해야함. LB_LIBRARY_PATH=/opt/geometry ./ex3_3.out로 실행 가능

    3.6.1. 공유 라이브러리의 수동 로딩

  • 로더 프로그램이 자동으로 로드하지 않는 방식. 공유 라이브러리 내부에서 찾을 수 있는 심벌을 이용하기 전, 공유 목적 파일을 수동으로 로드하는 함수를 개발자가 사용할 수 있음.

  • gcc -shared 2d.o 3d.o trigon.o -lm -i libgeometry.so 에서 -m옵션은 링커가 libm.so와 관련된 공유 목적 파일을 링크하도록 함. libgeometry.so를 수동으로 로드할 때, 이 파일의 의존성이 어느 정도는 자동으로 로드되어야 하기 때문.

  • 코드에서 dlopendlsym(= 함수 포인터 반환, 대상 함수를 불러오는데에 쓰임)이라는 함수로 공유 목적 파일을 로드하는 방법 확인

  • 필요할 때 libgeometry.so 파일을 수동으로 로드하려면
    gcc examples_chapter3_4.c -ldl -o ex3_4.out로 컴파일

  • 같은 라이브러리의 별도 실행 or 별도 버전을 위한 공유 목적 파일을 별개로 만드려 할 때 = 지연된 로딩에 해당. 공유 목적 파일을 자유롭게 로드.

  • 자동으로 로드 = 자유도 감소

profile
읽으면 머리에 안들어와서 직접 쓰는 중. 잘못된 부분 지적 대환영

0개의 댓글