strace
출력 에서 실행 파일이 호출한 라이브러리의 경로는 에 있습니다 open()
. 이는 동적으로 링크된 실행 파일에서 사용하는 시스템 호출입니까? 무엇에 대해 dlopen()
? open()
아마도 이것은 프로그램 실행에 중요한 역할을 하는 호출은 아닐 것 같습니다.
답변1
dlopen
시스템 호출이 아니라 라이브러리 함수libdl 라이브러리. 에는 시스템 호출만 나타납니다 strace
.
Linux 및 기타 여러 플랫폼(특히 실행 파일에 ELF 형식을 사용하는 플랫폼)에서는 dlopen
대상 라이브러리를 사용 open()
하고 이를 메모리에 매핑하여 이를 수행합니다 mmap()
. mmap()
여기에 실제로 중요한 부분이 있습니다. 라이브러리를 프로세스의 주소 공간에 병합하여 CPU가 해당 코드를 실행할 수 있도록 하는 것입니다. 하지만 이 작업을 open()
수행하려면 먼저 파일을 구해야 합니다 mmap()
!
답변2
dlopen은 공유 라이브러리라고 생각하는 것과 아무 관련이 없습니다. 공유 객체를 로드하는 방법에는 두 가지가 있습니다.
- 특정 공유 라이브러리의 함수를 사용하고 싶다고 컴파일 타임 링커(ld, 일반적으로 컴파일러를 통해 호출됨)에 알립니다. 이 접근 방식을 사용하면 컴파일 타임 링커를 실행할 때 라이브러리의 이름을 알아야 하지만 마치 프로그램에 정적으로 링크된 것처럼 라이브러리의 함수를 호출할 수 있습니다. 애플리케이션이 실행되면
main
함수를 호출하기 전에 동적 런타임 링커(ld.so)가 호출되고 애플리케이션이 라이브러리의 함수를 찾을 수 있도록 애플리케이션의 프로세스 공간을 설정합니다. 여기에는open()
lubrary,mmap()
ing 및 일부 조회 테이블 설정이 포함됩니다. - 컴파일 타임 링커에게 를 연결하고 싶다고 알리면
libdl
(첫 번째 방법을 사용하여) 그 링커에서dlopen()
및dlsym()
함수를 호출할 수 있습니다. dlopen을 사용하면 dlsym과 함께 사용하여 특정 함수에 대한 함수 포인터를 받을 수 있는 라이브러리에 대한 핸들을 얻을 수 있습니다. 이 접근 방식은 프로그래머에게 첫 번째 접근 방식보다 훨씬 더 복잡하며(링커가 자동으로 설정하도록 하는 대신 수동으로 설정해야 하기 때문에), 또한 더 취약합니다(컴파일된 결과를 얻지 못하기 때문에). - 첫 번째 방법에서 얻은 올바른 인수 유형을 사용하여 함수를 호출하고 있는지 확인할 시간입니다. 그러나 장점은 로드할 공유 객체(또는 전혀 로드할지 여부)를 런타임에 결정할 수 있다는 것입니다. 이것은 플러그인 유형 기능을 위한 인터페이스입니다. 마지막으로, dlopen 인터페이스는 그 메커니즘이 동적 링커(따라서libltdl
이러한 차이점을 추상화하려고 시도하는 libtool)의 정확한 구현에 의존하기 때문에 다른 방법보다 이식성이 떨어집니다 .
답변3
ltrace -S
최소한의 예제를 분석하면 mmap
glibc 2.23에서 사용된다는 것을 알 수 있습니다.
glibc 2.23, Ubuntu 16.04에서는 다음을 latrace -S
사용하여 최소 프로그램에서 실행됩니다 dlopen
.
ltrace -S ./dlopen.out
보여주다:
dlopen("libcirosantilli_ab.so", 1 <unfinished ...>
SYS_open("./x86_64/libcirosantilli_ab.so", 524288, 06267650550) = -2
SYS_open("./libcirosantilli_ab.so", 524288, 06267650550) = 3
SYS_read(3, "\177ELF\002\001\001", 832) = 832
SYS_brk(0) = 0x244c000
SYS_brk(0x246d000) = 0x246d000
SYS_fstat(3, 0x7fff42f9ce30) = 0
SYS_getcwd("/home/ciro/bak/git/cpp-cheat"..., 128) = 54
SYS_mmap(0, 0x201028, 5, 2050) = 0x7f1c323fe000
SYS_mprotect(0x7f1c323ff000, 2093056, 0) = 0
SYS_mmap(0x7f1c325fe000, 8192, 3, 2066) = 0x7f1c325fe000
SYS_close(3) = 0
SYS_mprotect(0x7f1c325fe000, 4096, 1) = 0
그래서 + 가 dlopen
호출되는 것을 즉시 볼 수 있습니다 .open
mmap
이 훌륭한 ltrace
도구는 라이브러리 호출과 시스템 호출을 추적할 수 있으므로 이 시나리오에서 무슨 일이 일어나고 있는지 확인하는 데 적합합니다.
신중한 분석에 따르면 open
파일 설명자 3
(stdin, out 및 err 다음의 사용 가능한 설명자)를 반환하는 것으로 나타났습니다.
read
그런 다음 해당 파일 설명자를 사용하지만TODO 에 대한 인수는 mmap
4개로 제한되어 있으며 다섯 번째 인수이기 때문에 어떤 fd가 거기에서 사용되는지 알 수 없습니다.. strace
예상대로 이것이 확인되었고 3
우주의 질서가 회복되었습니다.
용감한 사람이라면 glibc 코드를 탐색할 수도 있지만 빠른 grep 후에도 찾을 수 없었고 mmap
게으릅니다.
이것으로 테스트GitHub의 빌드 상용구를 사용한 최소 예.
답변4
strace
시스템 호출(예: 커널에서 직접 구현된 함수)을 보고합니다. 동적 라이브러리는 커널 함수가 아닙니다. dlopen
커널이 아닌 C 라이브러리의 일부입니다. 라이브러리 파일을 읽을 수 있도록 열기 위해 dlopen
구현이 호출됩니다(시스템 호출).open