programing

메모리에서 열립니까?

sourcejob 2023. 7. 23. 14:13
반응형

메모리에서 열립니까?

생성된 객체 코드를 메모리에서 직접 로드하는 방법을 찾고 있습니다.

파일에 작성하면 dlopen을 호출하여 동적으로 심볼을 로드하고 링크할 수 있는 것으로 알고 있습니다.그러나 메모리에서 시작하여 디스크에 기록된 다음 dlopen에 의해 메모리에 다시 로드된다는 점을 고려하면 이것은 약간 우회적인 방법인 것 같습니다.메모리에 존재하는 객체 코드를 동적으로 연결할 수 있는 방법이 있는지 궁금합니다.이를 위한 몇 가지 다른 방법이 있을 수 있습니다.

  1. 당신의 메모리 위치가 결코 메모리를 떠나지 않더라도 파일이라고 생각하도록 트릭을 엽니다.

  2. 내가 찾고 있는 것을 수행하는 다른 시스템 호출을 찾습니다(존재하지 않는 것 같습니다).

  3. 메모리에서 직접 코드를 연결할 수 있는 동적 연결 라이브러리를 찾습니다.분명히, 이것은 구글에서 찾기가 조금 어렵습니다. "동적 연결 라이브러리"는 동적 연결 작업을 수행하는 라이브러리가 아니라 동적으로 라이브러리를 연결하는 방법에 대한 정보를 찾기 때문입니다.

  4. 링커에서 일부 API를 추상화하고 코드베이스에서 새 라이브러리를 만듭니다.(만약 이것이 나에게 가장 바람직하지 않은 선택이라면).

이 중 어떤 것이 가능할까요?실현 가능합니까?제가 가정한 것들 중에 어떤 것이 존재하는지 알려주실 수 있나요?제가 생각지도 못한 다른 방법이 있을까요?

(데이터베이스에서 Blob을 사용하여) 파일 시스템이 없고 일부 스크립트를 지원하기 위해 이진 플러그인을 로드해야 하는 스크립트 가능 시스템이 있기 때문에 이에 대한 솔루션이 필요했습니다.이것은 FreeBSD에서 작동하지만 휴대가 불가능할 수 있는 해결책입니다.

void *dlblob(const void *blob, size_t len) {
    /* Create shared-memory file descriptor */
    int fd = shm_open(SHM_ANON, O_RDWR, 0);
    ftruncate(fd, len);
    /* MemMap file descriptor, and load data */
    void *mem = mmap(NULL, len, PROT_WRITE, MAP_SHARED, fd, 0);
    memcpy(mem, blob, len);
    munmap(mem, len);
    /* Open Dynamic Library from SHM file descriptor */
    void *so = fdlopen(fd,RTLD_LAZY);
    close(fd);
    return so;
}

분명히 코드에는 어떤 종류의 오류 검사 등이 없지만, 이것이 핵심 기능입니다.

ETA: 제가 처음 생각한 것은fdlopenPOSIX가 틀렸습니다. 이것은 FreeBSD-ism으로 보입니다.

왜 그런 모르겠어요.dlopen로드를 위해 디스크에 올바른 개체 형식(예: ELF)을 생성하려면 훨씬 더 많은 비휴대용 코드가 필요하기 때문입니다.아키텍처를 , 아처에대한기코생있알면다이고미,mmap 있는 메모리.PROT_READ|PROT_WRITE|PROT_EXEC거기에 코드를 넣은 다음 주소를 함수 포인터에 할당하고 호출합니다.아주 간단합니다.

것 외에 . 파일을 적는 것과 함께 하는 것 .dlopen().

현재 특정 플랫폼에서 다른 방법을 찾을 수 있습니다.이 방법이 '표준 및 (상대적으로) 휴대용' 접근법을 사용하는 것보다 더 나은지 여부는 사용자에게 달려 있습니다.

애초에 객체 코드를 생성하는 것은 플랫폼별로 다소 다르기 때문에 추가적인 플랫폼별 기술은 문제가 되지 않을 수 있습니다.그러나 그것은 판단 요청이며, 어떤 경우에도 비교적 가능성이 낮은 비표준 기술이 있는지에 달려 있습니다.

우리는 이것을 할 수 있는 방법을 구글에서 구현했습니다.불행히도 업스트림 glibc는 필요성을 이해하지 못해서 절대 받아들여지지 않았습니다.패치가 포함된 기능 요청이 중지되었습니다.로 알려져 있습니다.dlopen_from_offset.

dlopen_with_offset glibc 코드는 glibc google/grte* 분기에서 사용할 수 있습니다.하지만 아무도 그들 자신의 글릭을 수정하는 것을 즐기지 말아야 합니다.

메모리에 생성된 코드는 이미 메모리에 있으므로 로드할 필요가 없습니다!

그러나 휴대할 수 없는 방식으로 메모리에 기계 코드를 생성할 수 있습니다(메모리 세그먼트에 있는 경우).PROT_EXEC플래그)를 누릅니다.

(이 경우, 특히 외부 함수를 호출하기 위해 절대 또는 상대 주소가 확정된 기계 코드를 생성하므로 "연결" 또는 재배치 단계가 필요하지 않습니다.)

다음과 같은 기능을 하는 일부 라이브러리가 존재합니다.x86 또는 x86-64 아래의 GNU/리눅스에서는 GNU 라이트닝(천천히 실행되는 기계 코드를 빠르게 생성함), DotGNU LibJ알고 있습니다.IT(중간 품질 코드 생성) 및 LLVM & GCCJIT(메모리에서 상당히 최적화된 코드를 생성할 수 있지만 이 코드를 내보내는 데 시간이 걸립니다.)루아짓도 비슷한 시설을 가지고 있습니다.2015년부터 GCC 5는 gccjit 라이브러리를 보유하고 있습니다.

그리고 물론 파일에서 C 코드를 생성하고, 컴파일러를 포크하여 공유 객체로 컴파일하고, 공유 객체 파일을 열 수 있습니다.저는 GCC를 확장하기 위한 도메인 특정 언어인 GCC MELT에서 그것을 하고 있습니다.그것은 실제로 꽤 잘 작동합니다.

부록

생성된 C 파일의 쓰기 성능이 문제라면(C 파일을 컴파일하는 것이 쓰기보다 훨씬 느리기 때문에 문제가 되지 않아야 함) 이를 위해 일부 tmpfs 파일 시스템을 사용하는 것을 고려하십시오(아마도 다음과 같습니다)./tmp/Linux의 경우 tmpfs 파일 시스템인 경우가 많습니다.)

메모리에서 솔리브를 로드하는 데는 고유한 제한이 있습니다.즉, 솔리브의 DT_NEDDep은 메모리 버퍼를 참조할 수 없습니다.이것은 무엇보다도 메모리 버퍼에서 dep으로 solib를 쉽게 로드할 수 없다는 것을 의미합니다.유감스럽게도 ELF 사양이 DT_NEDED가 파일 이름이 아닌 다른 객체를 참조할 수 있도록 확장되지 않으면 메모리 버퍼에서 솔리브를 로드하기 위한 표준 API가 없을 것입니다.

posix의 shm_open()을 사용한 다음 공유 메모리를 mmap하고 거기서 솔리브를 생성한 다음 /dev/shm 마운트 포인트를 통해 플레인 dlopen()을 사용해야 한다고 생각합니다.이렇게 하면 일반 파일을 참조하거나 생성된 솔리브가 있는 /dev/shm 개체를 참조할 수도 있습니다.

이에 대한 해결책을 찾았습니다. 메모리 파일을 생성한 다음dlopen.

shm_open+dlopen을 사용하면 공유 메모리에서 동적 라이브러리를 로드합니다. /dev/shm이 noexec 권한을 가지고 있으면 동적 라이브러리가 로드되지 않습니다.

언급URL : https://stackoverflow.com/questions/5053664/dlopen-from-memory

반응형