IT박스

gcc에서 '-l'옵션의 순서가 중요한 이유는 무엇입니까?

itboxs 2020. 11. 5. 07:50
반응형

gcc에서 '-l'옵션의 순서가 중요한 이유는 무엇입니까?


udis86 라이브러리 를 사용하는 프로그램을 컴파일하려고합니다 . 사실 저는 도서관 사용자 매뉴얼나와있는 예제 프로그램을 사용 하고 있습니다. 그러나 컴파일하는 동안 오류가 발생합니다. 내가 얻는 오류는 다음과 같습니다.

example.c:(.text+0x7): undefined reference to 'ud_init'
example.c:(.text+0x7): undefined reference to 'ud_set_input_file'
.
.
example.c:(.text+0x7): undefined reference to 'ud_insn_asm'

내가 사용하는 명령은 다음과 같습니다.

$ gcc -ludis86 example.c -o example 

사용 설명서에 지시 된대로.

분명히 링커는 libudis 라이브러리를 연결할 수 없습니다. 하지만 명령을 다음과 같이 변경하면

$ gcc example.c -ludis86 -o example 

작동하기 시작합니다. 누군가가 첫 번째 명령의 문제점을 설명해 주시겠습니까?


이것이 GNU 링커에서 사용하는 연결 알고리즘이 작동하는 방식이기 때문입니다 (적어도 정적 라이브러리 연결과 관련하여). 링커는 단일 패스 링커이며 라이브러리가 발견되면 다시 방문하지 않습니다.

라이브러리는 개체 파일의 모음 (아카이브)입니다. -l옵션을 사용하여 라이브러리를 추가 할 때 링커는 무조건 라이브러리에서 모든 개체 파일을 가져 오지 않습니다 . 현재 필요한 객체 파일 , 즉 현재 해결되지 않은 (보류중인) 기호를 해결하는 파일 만 사용합니다. 그 후 링커는 해당 라이브러리를 완전히 잊습니다.

링커가 입력 개체 파일을 왼쪽에서 오른쪽으로 차례로 처리 할 때 보류중인 기호 목록은 링커에 의해 계속 유지됩니다. 각 개체 파일을 처리 할 때 일부 기호가 확인되어 목록에서 제거되고 새로 발견 된 다른 확인되지 않은 기호가 목록에 추가됩니다.

따라서를 사용하여 일부 라이브러리를 포함 -l하면 링커는 해당 라이브러리를 사용 하여 현재 보류중인 기호를 가능한 한 많이 확인한 다음 해당 라이브러리를 완전히 잊어 버립니다. 이 경우 나중에 갑자기 지금이 라이브러리에서 몇 가지 추가 오브젝트 파일을 필요로 발견 한, 링커는 라이브러리에없는 "반환"이러한 추가 오브젝트 파일을 검색 할 수 있습니다. 이미 너무 늦었습니다.

이러한 이유로 링커의 명령 줄에서 늦게-l 옵션 을 사용 하여 링커가 도달 할 때까지 필요한 개체 파일과 필요하지 않은 개체 파일을 안정적으로 결정할 수 있도록하는 것이 좋습니다. 옵션을 링커의 첫 번째 매개 변수로 배치하는 것은 일반적으로 전혀 의미가 없습니다. 맨 처음에 보류중인 기호 목록이 비어 있습니다 (또는 더 정확하게는 단일 기호로 구성됨 ). 즉, 링커가 전혀 도서관.-l-lmain

귀하의 경우, 개체 파일이 example.o심볼에 대한 참조 포함 ud_init, ud_set_input_file등을 먼저 오브젝트 파일을 받아야 링커. 보류중인 기호 목록에 이러한 기호를 추가합니다. 그런 다음 -l옵션을 사용 하여 라이브러리를 추가 할 수 있습니다 -ludis86.. 링커는 라이브러리를 검색하고 보류중인 기호를 해결하는 모든 라이브러리를 가져옵니다.

-ludis86명령 줄에서 옵션을 먼저 배치하면 링커가 라이브러리 를 효과적으로 무시 합니다. 처음에는 ud_init, ud_set_input_file이 필요한지 알지 못하기 때문입니다 . 나중에 처리 example.o이러한 기호를 발견하고 보류중인 기호에 추가합니다. 명부. 그러나 이러한 기호 -ludis86는 이미 처리되었으며 사실상 무시되었으므로 끝까지 해결되지 않은 상태로 유지됩니다 .

두 개 이상의 라이브러리가 순환 방식으로 서로를 참조 할 때 -l링커가 해당 라이브러리에서 필요한 개체 파일을 검색 할 수있는 두 번의 기회를 제공하기 위해 동일한 라이브러리 에서 옵션을 두 번 사용해야 할 수도 있습니다.


나는 이 같은 문제 를 얼마 동안 만났습니다. 결론은 gnu 도구가 누락 된 기호를 해결하기 위해 라이브러리 목록에서 항상 "뒤로 검색"하지는 않는다는 것입니다. 쉬운 수정은 다음 중 하나입니다.

  1. 종속성 순서로 libs 및 objs를 지정하십시오 (위에서 발견 한대로).

  2. 또는 순환 종속성이있는 경우 (libA는 libB의 함수를 참조하지만 libB는 libA의 함수를 참조) 명령 줄에서 libs를 두 번 지정하면됩니다. 이것은 매뉴얼 페이지에서도 제안하는 것입니다.

    gcc foo.c -lfoo -lbar -lfoo
    
  3. 이러한 순환 종속성이있는 아카이브 그룹을 지정 하려면 -(-)매개 변수를 사용하십시오 . --start-group에 대한 GNU 링커 설명서를 참조하십시오 --end-group. 자세한 내용은 여기 를 참조하십시오.

옵션 2 또는 3을 사용하면 연결에 대한 성능 비용이 발생할 수 있습니다. 연결할 것이 많지 않다면 중요하지 않을 수 있습니다.


또는 재검색 사용

Oracle Solaris 11.1 링커 및 라이브러리 설명서 41 페이지에서 발췌 :

아카이브간에 상호 종속성이 존재할 수 있으므로 한 아카이브에서 구성원을 추출하는 경우 다른 아카이브에서 구성원을 추출하여 해결해야합니다. 이러한 종속성이 주기적이면 이전 참조를 충족하기 위해 명령 줄에서 아카이브를 반복적으로 지정해야합니다.

$ cc -o prog .... -lA -lB -lC -lA -lB -lC -lA 

반복되는 아카이브 사양의 결정 및 유지 관리는 지루할 수 있습니다.

-z rescan-now 옵션을 사용하면이 프로세스가 더 간단 해집니다. -z rescan-now 옵션은 명령 줄에서 옵션이 발견되는 즉시 링크 편집기에 의해 처리됩니다. 이 옵션 이전에 명령 줄에서 처리 된 모든 아카이브는 즉시 다시 처리됩니다. 이 처리는 기호 참조를 해결하는 추가 아카이브 멤버를 찾으려고 시도합니다. 이 아카이브 재검색은 새 구성원이 추출되지 않는 아카이브 목록을 통과 할 때까지 계속됩니다. 이전 예는 다음과 같이 단순화 할 수 있습니다.

$ cc -o prog .... -lA -lB -lC -z rescan-now 

또는 -z rescan-start 및 -z rescan-end 옵션을 사용하여 상호 종속적 인 아카이브를 하나의 아카이브 그룹으로 그룹화 할 수 있습니다. 이러한 그룹은 명령 줄에서 닫는 구분 기호를 만나면 링크 편집기에 의해 즉시 다시 처리됩니다. 그룹 내에서 발견 된 아카이브는 기호 참조를 확인하는 추가 아카이브 멤버를 찾으려고 재 처리됩니다. 이 아카이브 재검색은 새 구성원이 추출되지 않는 아카이브 그룹을 통과 할 때까지 계속됩니다. 아카이브 그룹을 사용하면 이전 예제를 다음과 같이 작성할 수 있습니다.

$ cc -o prog .... -z rescan-start -lA -lB -lC -z rescan-end

참고 URL : https://stackoverflow.com/questions/11893996/why-does-the-order-of-l-option-in-gcc-matter

반응형