prosource

다른 실행 파일이 필요한 에 실행 파일을 연결할 때 ld가 -rpath-link가 필요한 이유는 무엇입니까?

probook 2023. 6. 7. 23:01
반응형

다른 실행 파일이 필요한 에 실행 파일을 연결할 때 ld가 -rpath-link가 필요한 이유는 무엇입니까?

그냥 궁금해서 그러는데요.공유 개체를 만들었습니다.

gcc -o liba.so -fPIC -shared liba.c

그리고 또 하나의 공유 객체는 전자 객체와 연결됩니다.

gcc -o libb.so -fPIC -shared libb.c liba.so

다음에 연결할 실행 파일을 만들 때libb.so해야 -rpath-link told를 수 .liba.so을 발견했을 때.libb.so 다릅니다.

gcc -o test -Wl,-rpath-link,./ test.c libb.so

그렇지 않으면 ld가 불평할 것입니다.

는 반드시 ld의 를 찾을 수 합니까, LD의 위치를 알 수 있습니다.liba.so를 할 때test하는 것 외에는 것 때문입니다.liba.so를 들어, 존들어, 행실을 실행하는 입니다.readelf --dynamic ./test만 표시libb.so필요에 따라, 그래서 나는 동적 링커가 그것을 발견해야 한다고 생각합니다.libb.so -> liba.so그 자체에 의존하고, 그것을 자체적으로 검색하게 합니다.liba.so.

GNU 플랫폼에 , x86-64 GNU/리눅스의 루틴, 메인()-에 있습니다.test에서 함수를 합니다.libb.so은 차로함호출다니합를수의 .liba.so.

는 반드시 ld의 를 찾을 수 합니까, LD의 위치를 알 수 있습니다.liba.so를 할 때test하는 것 외에는 것 때문입니다.liba.so를 들어, 존들어, 행실을 실행하는 입니다.readelf --dynamic ./test만 표시libb.so필요에 따라, 그래서 나는 동적 링커가 그것을 발견해야 한다고 생각합니다.libb.so -> liba.so그 자체에 의존하고, 그것을 자체적으로 검색하게 합니다.liba.so.

음, 내가 링크 과정을 올바르게 이해한다면, ld는 실제로 찾을 필요가 없습니다.libb.so에서 확인되지 않은 모든 참조를 무시할 수 있습니다.test가 로드할 때 .libb.so런타임에그러나 이러한 방식으로 작업을 수행하는 경우 많은 "정의되지 않은 참조" 오류가 링크 시간에 감지되지 않고 로드를 시도할 때 발견됩니다.test런타임에Sold는 모든 기호를 찾을 수 없는 추가 확인만 수행합니다.test가 공유 에서 실제로 수 .test에 달려 있다.그래서 만약에test에 " reference오류가 (가 "filename"에 .)test그 자체도 아닌libb.so은 단순히 링크 .), 이는런타뿐링크아분시명도다니집해간에니만라임▁),다니.따라서 그러한 행동은 단지 추가적인 제정신성 검사일 뿐입니다.

하지만 ld는 더 멀리 갑니다.링크할 때testld는 또한 에서 해결되지 않은 모든 참조를 확인합니다.libb.so 수 있습니다.libb.so에 따라 다릅니다(우리의 경우).libb.so 따라 .liba.so그래서 그것은 필요합니다.liba.so링크 시간에 위치해야 함).음, 사실 ld는 이미 이 확인을 했습니다, 링크할 때.libb.so왜 두 번째 검사를 하는 거지?아마도 ld 개발자들은 프로그램을 링크된 시간에 로드될 수 있는 오래된 라이브러리와 연결하려고 할 때 손상된 종속성을 감지하는 데 이 이중 검사가 유용하다고 생각했지만, 이제는 의존하는 라이브러리가 업데이트되었기 때문에 로드할 수 없습니다(예:liba.so나중에 재작업되어 일부 기능이 제거되었습니다.)

업데이

몇 가지 실험만 했을 뿐입니다.제 추측은 "사실 ld가 링크할 때 이미 이 검사를 수행했다"는 것은 잘못된 것 같습니다.

다음과 같이 가정합니다.liba.c내용은 다음과 같습니다.

int liba_func(int i)
{
    return i + 1;
}

그리고.libb.c다음이 있습니다.

int liba_func(int i);
int liba_nonexistent_func(int i);

int libb_func(int i)
{
    return liba_func(i + 1) + liba_nonexistent_func(i + 2);
}

그리고.test.c

#include <stdio.h>

int libb_func(int i);

int main(int argc, char *argv[])
{
    fprintf(stdout, "%d\n", libb_func(argc));
    return 0;
}

할 때libb.so:

gcc -o libb.so -fPIC -shared libb.c liba.so

링커는 다음과 같은 오류 메시지를 생성하지 않습니다.liba_nonexistent_func수 . 라이브러리인 &quot;&quot;를 으로 생성합니다. 대신 손상된 공유 라이브러리만 자동으로 생성합니다.libb.so 것과 .libb.a) 생성된 라이브러리의 기호도 확인하지 않는 ar를 사용합니다.

하지만 당신이 연결하려고 할 때test:

gcc -o test -Wl,-rpath-link=./ test.c libb.so

오류가 발생합니다.

libb.so: undefined reference to `liba_nonexistent_func'
collect2: ld returned 1 exit status

폴더가 모든 공유 라이브러리를 재귀적으로 검색하지 않았다면 이러한 오류를 탐지할 수 없습니다.따라서 질문에 대한 대답은 위에서 말한 것과 같습니다. ld needs -rpath-link는 나중에 동적으로 로드되어 링크된 실행 파일을 로드할 수 있도록 하기 위해 필요합니다.그냥 제정신이 아니에요.

UPD2

되지 않은 한 입니다.libb.so), 하지만 ld는 어떤 이유로 이것을 하지 않습니다.아마도 공유 라이브러리에 대한 주기적인 종속성을 허용하기 위한 것일 것입니다.

liba.c에는 다음과 같은 구현이 있을 수 있습니다.

int libb_func(int i);

int liba_func(int i)
{
    int (*func_ptr)(int) = libb_func;
    return i + (int)func_ptr;
}

그렇게liba.so사용하다libb.so그리고.libb.so사용하다liba.so(그런 일은 절대로 하지 않는 것이 좋습니다.)이것은 성공적으로 컴파일되고 작동합니다.

$ gcc -o liba.so -fPIC -shared liba.c
$ gcc -o libb.so -fPIC -shared libb.c liba.so
$ gcc -o test test.c -Wl,-rpath=./ libb.so
$ ./test
-1217026998

비록 리드엘프가 그렇게 말하지만,liba.so 필요 libb.so:

$ readelf -d liba.so | grep NEEDED
 0x00000001 (NEEDED)                     Shared library: [libc.so.6]
$ readelf -d libb.so | grep NEEDED
 0x00000001 (NEEDED)                     Shared library: [liba.so]
 0x00000001 (NEEDED)                     Shared library: [libc.so.6]

공유 라이브러리를 연결하는 동안 확인되지 않은 기호가 있는지 확인한 경우 연결,liba.so가능하지 않을 것입니다.

참고로 -rpath-link 대신 -rpath 키를 사용했습니다.차이점은 -rpath-link는 최종 실행 파일의 모든 기호를 확인하기 위해서만 연결 시간에 사용되는 반면, -rpath는 실제로 매개 변수로 지정한 경로를 ELF에 포함합니다.

$ readelf -d test | grep RPATH
 0x0000000f (RPATH)                      Library rpath: [./]

그서이실가다니능합행이래제다▁run니▁so▁possible▁to가'▁nows능▁it그합을 실행할 수 있습니다.test 공유 라이브러리공유 라이브러리)liba.so그리고.libb.so는 현재 에 ../만약 당신이 단지 -rpath-link를 사용했다면, 그러한 항목은 없을 것입니다.test은 ELF에 해야 할 입니다./etc/ld.so.conf으로.LD_LIBRARY_PATH환경 변수입니다.

UPD3

공유 라이브러리를 되지 않은 할 수 .--no-undefined다음을 수행하려면 옵션을 사용해야 합니다.

$ gcc -Wl,--no-undefined -o libb.so -fPIC -shared libb.c liba.so
/tmp/cc1D6uiS.o: In function `libb_func':
libb.c:(.text+0x2d): undefined reference to `liba_nonexistent_func'
collect2: ld returned 1 exit status

또한 다른 공유 라이브러리에 의존하는 공유 라이브러리를 연결하는 많은 측면을 설명하는 좋은 기사를 찾았습니다.예를 들어 Linux 2차 종속성 해결 방법을 더 잘 이해합니다.

당신은 언제 사용해야 할지 알아야 할 것 같습니다.-rpath 및 옵션-rpath-link선택.먼저 인용하겠습니다.man ld: 지됨:

  1. -rpath와 -rpath-link의 차이점은 -rpath 옵션으로 지정된 디렉토리가 실행 파일에 포함되어 런타임에 사용되는 반면 -rpath-link 옵션은 링크 시간에만 유효하다는 것입니다.이런 방식으로 -rpath를 검색하는 것은 --with-sysroot 옵션으로 구성된 네이티브 링커 및 크로스 링커에서만 지원됩니다.

링크 시간과 런타임을 구분해야 합니다.승인된 anton_rh의 답변에 따르면, 공유 라이브러리 또는 정적 라이브러리를 컴파일하고 연결할 때 정의되지 않은 기호를 확인하는 것이 활성화되지 않고 실행 파일을 컴파일하고 연결할 때 활성화됩니다.(그러나 실행 파일뿐만 아니라 공유 라이브러리인 일부 파일이 있습니다. 예를 들어,ld.so합니다.유형man ld.so이러한 "듀얼" 종류의 파일을 컴파일할 때 정의되지 않은 기호를 확인할 수 있는지 여부를 알 수 없습니다.

그렇게-rpath-link링크 시간 확인에 사용됩니다.-rpath및되는 이유는 "" " " " " 입니다." 때문입니다.rpathELF 헤더에 포함됩니다.하지만 당신은 조심해야 합니다.-rpath-link옵션이 재정의됩니다.-rpath둘 다 지정된 경우 링크 시간 중에 선택할 수 있습니다.

그래도 왜요?-rpath-option그리고.-rpath옵션?저는 그들이 "과잉 연결"을 제거하는 데 사용된다고 생각합니다. 항목을 참조하십시오. Linux 2차 종속성에 대한 이해 예제를 사용하여 해결하십시오. 간단히 사용하십시오.ctrl + F"오버링크"와 관련된 내용으로 이동합니다.당신은 왜 "오버링크"가 나쁜지에 초점을 맞춰야 하며, 우리가 "오버링크"를 피하기 위해 채택하는 방법 때문에, 그 존재에 초점을 맞춰야 합니다.ld옵션들-rpath-link그리고.-rpath합리적입니다. "오버링크"를 피하기 위해 컴파일 및 링크 명령에서 일부 라이브러리를 의도적으로 생략합니다.ld필요하다.-rpath-link또는-rpath이러한 누락된 라이브러리를 찾습니다.

당신의 시스템, 통과ld.so.conf,ld.so.conf.d시스템 환경,LD_LIBRARY_PATH등을 통해 설치된 라이브러리에 의해 보완되는 시스템 전체 라이브러리 검색 경로를 제공합니다.pkg-config표준 라이브러리를 기반으로 빌드할 때 정보 등이 제공됩니다.라이브러리가 정의된 검색 경로에 있으면 표준 라이브러리 검색 경로가 자동으로 수행되므로 필요한 모든 라이브러리를 찾을 수 있습니다.

사용자가 직접 만든 사용자 정의 공유 라이브러리에 대한 표준 런타임 라이브러리 검색 경로가 없습니다.를 통해 라이브러리에 대한 검색 경로를 지정합니다.-L/path/to/lib컴파일 및 링크 중 지정.비표준 위치에 있는 라이브러리의 경우, 실행 파일이 필요한 라이브러리를 찾을 수 있도록 라이브러리 검색 경로를 컴파일 시 실행 파일(ELF 헤더)의 헤더에 선택적으로 배치할 수 있습니다.

rpath사용자 지정 런타임 라이브러리 검색 경로를 ELF 헤더에 포함하여 사용자 지정 라이브러리를 찾을 때마다 검색 경로를 지정하지 않아도 됩니다.이것은 라이브러리에 의존하는 라이브러리에도 적용됩니다.찾은 대로 명령줄에서 라이브러리를 지정하는 순서가 중요할 뿐만 아니라, 실행에 필요한 모든 라이브러리의 위치가 헤더에 포함되도록 링크 중인 각 종속 라이브러리에 대한 런타임 라이브러리 검색 경로 또는 rpath 정보도 제공해야 합니다.

주석에서 추가

제 질문은 주로 왜 ld가 "자동으로 공유 라이브러리를 찾으려 시도"(liba.so )하고 "링크에서 검색"해야 하는지에 대한 것입니다.

그것이 바로 방법입니다.ldworks. Fromman ld"-rpath 옵션은 링크에 명시적으로 포함된 공유 개체에 필요한 공유 개체를 찾을 때도 사용됩니다...ELF 실행 파일을 연결할 때 -rPATH를 사용하지 않으면 환경 변수 "LD_RUN_PATH"의 내용이 정의된 경우 사용됩니다."당신의 경우에는liba위치가 없습니다.LD_RUN_PATH그렇게ld찾을 방법이 필요할 것입니다liba실행 파일을 컴파일하는 동안.rpath(위에서 설명함) 또는 명시적인 검색 경로를 제공하여 검색할 수 있습니다.

두 번째로 "링크에 포함"하는 것은 정말 의미가 있습니다.제게 그것은 단지 "존재를 인정하라"(liba.so 의)는 의미인 것 같습니다. lib 이후로.따라서 의 ELF 헤더는 수정되지 않으며(이들은 이미 liba.so 에 대해 필요한 태그를 가지고 있음), Exec의 헤더는 libb.so 을 필요한 것으로 선언합니다.왜 liba.so 을 찾는 데 신경을 쓰는 걸까요? 런타임 링커에게 작업을 맡길 수는 없을까요?

아니요, 다시 의미론으로 돌아갑니다.ld"좋은 연결고리"를 만들기 위해,ld모든 종속 라이브러리를 찾을 수 있어야 합니다. ld그렇지 않으면 좋은 링크를 보장할 수 없습니다.런타임 링커는 프로그램필요한 공유 라이브러리를 찾는 뿐만 아니라 찾아 로드해야 합니다. ld그렇지 않으면 그것이 일어날 것이라고 장담할 수 없습니다.ld프로그램이 연결될 때 필요한 모든 공유 라이브러리를 찾을있습니다.

실제로 ld를 알려주지 않습니다(링크할 때).libb그에 반대하여liba) 어디에 liba단지 의존성일 뿐입니다.잠깐ldd libb.so찾을 수 없다는 것을 보여줄 것입니다.liba.

이러한 라이브러리는 링커 검색 경로에 없으므로 실행 파일을 연결할 때 링커 오류가 발생합니다.liba 자체를 링크할 때 lib의 함수는 아직 해결되지 않았지만,ld의 기본 동작은 최종 실행 파일을 연결할 때까지 DSO의 확인되지 않은 기호에 대해 신경 쓰지 않는 것입니다.

언급URL : https://stackoverflow.com/questions/24598047/why-does-ld-need-rpath-link-when-linking-an-executable-against-a-so-that-needs

반응형