컴퓨터 시스템: 프로그래머의 관점(3ed)p733 라고
7.9 실행 가능한 타겟 파일 로딩
실행 가능한 개체 파일인 prog를 실행하려면 Linux 셸의 명령줄에 해당 이름을 입력하면 됩니다.
리눅스> ./prog
prog
내장된 셸 명령과 일치하지 않기 때문에 셸prog
에서는 실행 가능한 개체 파일이라고 가정합니다. 이 파일은 다음과 같은 메모리 상주 운영 체제 코드를 호출하여 생성됩니다.짐을 싣는 사람. 모든 Linux 프로그램은 이 함수를 호출하여 로더를 호출할 수 있으며execve
, 이에 대해서는 섹션 8.4.6에서 자세히 다룰 것입니다.
p736에서: 동적 연결 중
7.10 공유 라이브러리와의 동적 연결
라이브러리를 생성한 후 이를 그림 7.7의 예제 프로그램에 연결합니다.
linux> gcc -o prog2l main2.c ./libvector.so
prog2l
이는 런타임에 링크 될 수 있는 형태로 실행 가능한 개체 파일을 생성합니다 .libvector.so
기본 아이디어는 실행 파일이 생성될 때 일부 링크를 정적으로 수행한 다음 프로그램이 로드될 때 링크 프로세스를 동적으로 완료하는 것입니다. 깨닫는 것이 중요하다libVector.so의 코드나 데이터 중 어떤 부분도 실제로 실행 파일에 복사되지 않습니다.prog2l
이 지점에서. 대신에,링커는 일부 재배치 및 기호 테이블 정보를 복사합니다.libvector.so
이렇게 하면 로드 시 코드 및 데이터에 대한 참조를 확인할 수 있습니다.로더가 실행 파일을 로드하고 실행할 때
prog2l
섹션 7.9에 설명된 기술을 사용하여 부분적으로 링크된 실행 파일을 로드합니다.prog2l
다음으로, 그 자체가 공유 객체인 동적 링커의 경로 이름을 포함하는 섹션prog2l
이 포함되어 있음을 확인합니다.interp
(예:ld-linux.so
Linux 시스템에서). 로더는 평소처럼 애플리케이션에 제어를 전달하는 대신 동적 링커를 로드하고 실행합니다. 동적 링커그런 다음 완료작업 연결다음 재배치를 수행하여:
- 텍스트와 데이터를
libc.so
메모리 세그먼트로 재배치- 텍스트와 데이터를
libvector.so
다른 메모리 세그먼트로 재배치prog2l
및에 의해 정의된 기호 에 대한 참조를 재배치합니다 .libc.so
libvector.so
위의 동적링크 상황은 "정적 로딩, 동적링크" 상황이다.스티븐 키트의 답변:
정적 로딩, 동적 연결:링커/usr/bin/ld를 다시 사용하지만 공유 라이브러리(.so)를 사용합니다.짐을 싣는 사람64비트 x86 기반 Debian 9의 /lib64/ld-linux-x86-64.so.2(현재 /lib/x86_64-linux-gnu/ld-2.24.so에 매핑됨)와 같은 바이너리용 인터프리터입니다. 주요 실행 파일도 로드하는 커널에 의해;
차이점은 CSAPP에서는 로더가 (뒤에 있는 커널 코드) execve()
반면 링커는 ld-linux.so
(컴파일 타임에 링크가 발생하지 않지만 ld
실제 링크는 로드 타임에 발생함 ld-linux.so
)이라고 말하는 것 같습니다.
링커란 무엇이며 동적 링킹의 로더는 무엇입니까?
감사해요.
답변1
강조할 핵심 사항은 다음과 같습니다.
동적 링커그런 다음 완료작업 연결
중요한 단어를 놓쳤어요"마치다”. 링커는 ld
연결 작업을 시작하여 빌드 시 가능한 한 많은 작업을 수행하고 이를 완료하는 데 필요한 데이터 구조를 준비합니다.
그런 다음 로더는 프로그램과 필수 라이브러리를 로드하는 연결 작업(기호 일치 및 필요한 재배치 수행)을 완료할 수 있습니다.
CSAPP 용어에서 동적 로더는 커널의 ELF 로더이고 동적 링커는 ld-linux.so
.
GNU C 라이브러리 자체 문서 ld.so
는 다음과 같습니다.동적 링커/로더. ld.so
(또는 ld-linux.so
) 자체는 링크뿐만 아니라 로딩도 많이 수행하므로 두 용어를 모두 적용하는 것이 정확할 것입니다. 커널은 실행 파일 자체와 해당 인터프리터(동적 링커/로더)를 로드하고 인터프리터는 필요한 다른 모든 것을 로드합니다. 도서관.
바라보다프로그램 실행 방법: ELF 바이너리이 모든 것이 Linux 시스템에서 어떻게 작동하는지 자세히 알아보세요.
답변2
동적 링커는 call 입니다 ld.so
. 아래에서 구성을 찾을 수 있습니다 /etc/ld.so*
. 대부분의 구성은 .so를 검색하는 경로와 관련이 있습니다.
ld
실행 파일의 연결을 완료하기 전에 모든 기능이 공유 라이브러리에 있는지 확인해야 합니다(음...기술적으로는 수행할 필요는 없지만 수행합니다. 즉, From에서 시작하는 경우) 컴퓨터마다 .so가 다를 수 있고 새로운 기능이 있을 수 있지만 이전 기능이 손실되고 바이너리가 실행되지 않습니다.
링커()는 공유 라이브러리가 필요한 바이너리를 생성할 때 ld
섹션에 특정 개수의 기호와 해당 주소를 예약합니다. .text
이는 동적 링커( ld.so
)가 런타임 시 연결을 완료하는 데 사용하는 것입니다. 해당 .so 파일에서 기호를 검색하고 코드에서 필요할 때마다 해당 주소를 저장합니다(함수의 경우 일반적으로 jump
명령 목록이므로 각 함수를 한 번만 연결할 수 있습니다).
물론 바이너리를 제거하면특수 기호삭제되지 마십시오.
로드될 라이브러리 목록을 보려면 ldd
실행 파일에 대해 실행할 수 있습니다. 특히 기호(전체 경로)를 확인하기 위해 어떤 .so가 선택되었는지 보여줍니다. 환경 변수를 사용하여 검색 경로를 변경할 수 있습니다 LD_LIBRARY_PATH
. 이를 통해 다른 또는 제거된 .so 파일에 대해 테스트할 수 있습니다(cmake, automake도 --rpath
해당 파일을 사용합니다. 동일하며 경로는 바이너리에 직접 저장됩니다).
정확히 어느 부분이 파일을 로드하고 실행하는지 잘 모르겠습니다. execve()
이 모든 논리는 직접 구현되지 않을 수도 있습니다 . 그러나 실행 파일을 실행하는 방법을 아는 가장 낮은 수준의 함수에 확실히 가깝습니다.
실제로 동적 연결은매우 간단하다표준 링커와 비교한 프로세스:
- 로드.so
- .so에서 기호 검색
- 기호 주소 저장
완벽한. 그렇기 때문에 너무 빠릅니다.
노트:use 를 사용하면 더욱 역동성을 얻을 수 있지만 dlopen()
그 부분을 말하는 것 같지는 않습니다.