Linux에서 라이브러리를로드하는 데 어떤 시스템 호출이 사용됩니까?


23

에서 strace출력, 실행 파일이 호출하는 라이브러리에 대한 경로는 호출에 있습니다 open(). 동적으로 연결된 실행 파일에서 사용하는 시스템 호출입니까? 무엇에 대해 dlopen()? open()내가 생각했던 전화가 프로그램 실행에 중요한 역할을하는 것은 아닙니다.

답변:


33

dlopen시스템 호출이 아니며 libdl 라이브러리 의 라이브러리 함수입니다 . 에 시스템 호출 만 표시됩니다 strace.

Linux 및 기타 여러 플랫폼 (특히 실행 파일에 ELF 형식을 사용하는 플랫폼)에서는 dlopen대상 라이브러리를 열고를 사용하여 open()메모리에 매핑 하여 구현됩니다 mmap(). mmap()여기서 중요한 부분입니다. 라이브러리를 프로세스의 주소 공간에 통합하여 CPU가 코드를 실행할 수 있습니다. 그러나 당신은 그것을 open()할 수 mmap()있기 전에 파일에 있어야 합니다!


2
"mmap ()은 정말 중요한 부분입니다."그리고 동적 링커는 재배치, 초기화 등을 수행해야합니다 (그러나 이것은 시스템 호출 수준에서는 보이지 않습니다).
ysdx

1
라이브러리 로딩은 라이브러리 함수에 의해 수행되므로 실행 파일 자체를 추가 ld-linux하고 커널이 execve시스템 호출의 일부로 매핑 한다는 것이 적절하다고 생각합니다 .
kasperd

이 답변에 따라 mmap. 또한 각 라이브러리를 "열기"한 후 mmap 호출 전에 일부 (832) 바이트를 읽은 후 라이브러리가 유효한지 확인하는 것으로 가정합니다.
Johan

@kasperd Linux 커널은 동적 로더를 알고 있습니까? 응용 프로그램이 실행될 때 호출합니까? 아니면 응용 프로그램 자체가 그렇게합니까? 후자의 경우 다른 실행 파일이 어떻게 응용 프로그램의 메모리에 액세스 할 수 있습니까?
Melab

@Melab 예, 커널은 동적 링커를 알고 있습니다. 커널은 실행 파일의 헤더에서 동적 링커의 경로를 읽습니다. 그리고 커널은 둘 다 메모리에 매핑합니다. 커널 전송 제어가 시작되는 진입 점이 링커 또는 실행 파일 내에 있는지 여부를 모르겠습니다. 내가 그것을 구현했다면 아마도 스택의 실행 주소가 실행 파일의 진입 점을 가리키는 링커의 진입 점으로 커널 전송 제어를 할 것입니다.
kasperd

5

dlopen은 공유 라이브러리와는 아무런 관련이 없습니다. 공유 객체를로드하는 방법에는 두 가지가 있습니다.

  1. 컴파일 타임 링커 (일반적으로 컴파일러를 통해 호출되는 ld)에 특정 공유 라이브러리의 함수를 사용하도록 지시합니다. 이 방법을 사용하면 컴파일 타임 링커가 실행될 때 라이브러리 이름이 무엇인지 알아야하지만 라이브러리 함수가 프로그램에 정적으로 링크 된 것처럼 호출 할 수 있습니다. 응용 프로그램이 실행되면 main함수가 호출 되기 직전에 동적 런타임 링커 (ld.so)가 호출 되고 응용 프로그램이 라이브러리의 기능을 찾을 수 있도록 응용 프로그램의 프로세스 공간을 설정합니다. 여기에는 open()윤활유를 바르고 mmap()룩업 테이블을 설정하는 것이 포함됩니다 .
  2. 컴파일 타임 링커에게 링크하고 싶다고 말하면 libdl(첫 번째 방법을 사용하여) dlopen()and를 호출 할 수 있습니다.dlsym()기능. dlopen을 사용하면 라이브러리에 대한 핸들을 얻습니다. 그런 다음 dlsym과 함께 사용하여 특정 함수에 대한 함수 포인터를받을 수 있습니다. 이 방법은 첫 번째 방법보다 프로그래머에게 훨씬 더 복잡합니다 (링커가 자동으로 설정하는 대신 수동으로 설정을 수행해야하기 때문에). -time은 첫 번째 방법에서 얻을 때 올바른 인수 유형으로 함수를 호출하고 있는지 확인하지만 이점은 런타임에로드 할 공유 객체 (또는로드 여부)를 결정할 수 있다는 것입니다. 플러그인 유형 기능을위한 인터페이스입니다. 마지막으로, dlopen 인터페이스는 역학 링커의 정확한 구현에 의존하기 때문에 다른 방법보다 이식성이 떨어집니다.libltdl이 차이점을 추상화하려고 시도합니다.

흥미로운; 따라서 바이너리 파일을 메모리에로드하는 것은 어려운 일이 아니기 때문에 동적으로로드 된 라이브러리는 동적으로 연결된 라이브러리라고하는 것이 좋습니다. 동적 라이브러리를로드 할 때 실제로 라이브러리를 주소 공간에 연결하거나 연결 해제하도록 요청합니다.
Dmitry

4

오늘날 대부분의 운영 체제는 1987 년 말 SunOS-4.0에 의해 도입 된 공유 라이브러리 방법을 사용합니다. 이 방법은 mmap ()을 통한 메모리 매핑을 기반으로합니다.

Sun은 1990 년대 초에 이전 a.out 기반 코드 (당시의 Solaris는 이미 ELF 기반 임)를 FreeBSD 사용자에게 기증했으며이 코드는 나중에 다른 많은 시스템 (Linux를 포함하여)에게 전달되었습니다. 플랫폼간에 큰 차이가없는 이유를 이해할 수 있습니다.


3

ltrace -Smmapglibc 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호출 하는 것을 봅니다 .openmmap

이 멋진 ltrace툴은 라이브러리 호출과 시스템 호출을 모두 추적하므로이 경우 진행중인 작업을 검사하는 데 적합합니다.

더 자세히 분석 open하면 파일 설명자를 반환합니다 3(stdin, out 및 err 다음에 비어 있음).

read그런 다음 해당 파일 디스크립터를 사용하지만 TODO mmap의 인수가 4로 제한되는 이유 는 5 번째 인수이므로 어떤 fd가 사용되었는지 알 수 없습니다 . strace예상 한대로 확인 3하고 우주의 순서가 복원됩니다.

용감한 영혼은 또한 glibc 코드로 모험을 할 수 있지만, 나는 mmap빨리 grep을 찾을 수 없었고 게으르다.

GitHub에 빌드 상용구를 사용하여이 최소 예제로 테스트했습니다 .


2

strace시스템 호출에 관한보고 (즉, 커널에 의해 직접 구현 된 함수). 동적 라이브러리는 커널 기능이 아닙니다. dlopen커널이 아닌 C 라이브러리의 일부입니다. 라이브러리 파일을 읽기 위해 dlopenwill 호출 open(시스템 호출)을 구현하여 읽을 수 있습니다.


5
을 사용하여 라이브러리 호출을 볼 수 있습니다 ltrace.
kasperd

@kasperd는 ltrace -S그것 또한 쇼의 콜로이를 분석하는 완벽 : unix.stackexchange.com/a/462710/32558
치로 틸리新疆改造中心法轮功六四事件
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.