이 C 프로그램은 두 가지 주요 기능으로 어떻게 컴파일 및 실행됩니까?
오늘 하나의 커스텀 라이브러리로 작업하던 중 이상한 행동을 발견했습니다.정적 라이브러리 코드에 디버깅이 포함되어 있습니다.main()
기능.그것은 안에 있지 않았다.#define
깃발. 그래서 도서관에도 있다.그리고 그것은 실제를 포함하고 있는 다른 프로그램 링크에 사용됩니다.main()
.
둘 다 링크되어 있는 경우 링커는 다음 명령어에 대해 다중 선언 오류를 발생시키지 않습니다.main()
어떻게 이런 일이 일어날 수 있는지 궁금했어요.
간단하게 하기 위해서, 같은 동작을 시뮬레이트 한 샘플 프로그램을 작성했습니다.
$ cat prog.c
#include <stdio.h>
int main()
{
printf("Main in prog.c\n");
}
$ cat static.c
#include <stdio.h>
int main()
{
printf("Main in static.c\n");
}
$ gcc -c static.c
$ ar rcs libstatic.a static.o
$ gcc prog.c -L. -lstatic -o 2main
$ gcc -L. -lstatic -o 1main
$ ./2main
Main in prog.c
$ ./1main
Main in static.c
"2main" 바이너리는 어떻게 다음 항목을 찾습니까?main
실행할까요?
그러나 이 두 가지를 함께 컴파일하면 여러 선언 오류가 발생합니다.
$ gcc prog.c static.o
static.o: In function `main':
static.c:(.text+0x0): multiple definition of `main'
/tmp/ccrFqgkh.o:prog.c:(.text+0x0): first defined here
collect2: ld returned 1 exit status
누가 이 행동을 설명할 수 있나요?
견적 ld(1):
링커는 명령줄에서 지정된 위치에서 아카이브를 한 번만 검색합니다.아카이브가 명령줄의 아카이브 앞에 나타난 일부 개체에서 정의되지 않은 기호를 정의한 경우 링커는 아카이브의 적절한 파일을 포함합니다.
2main을 링크하면 ld가 prog.o에서 픽업하기 때문에 ld가 -lstatic에 도달하기 전에 메인 기호가 해결됩니다.
1main을 링크할 때 -lstatic에 도달할 때까지 main을 정의하지 않았기 때문에 아카이브에서 main을 검색합니다.
이 논리는 아카이브(정적 라이브러리)에만 적용되며 일반 개체에는 적용되지 않습니다.prog.o와 static.o를 링크하면 두 개체의 모든 기호가 무조건 포함되므로 중복 정의 오류가 발생합니다.
정적 라이브러리(.a)를 링크하면 링커는 지금까지 추적된 정의되지 않은 기호가 있는 경우에만 아카이브를 검색합니다.그렇지 않으면 아카이브가 전혀 표시되지 않습니다.그래서 당신의2main
번역 유닛을 작성하기 위한 정의되지 않은 기호가 없기 때문에 아카이브를 참조하지 않습니다.
에 단순한 함수를 포함할 경우static.c
:
#include <stdio.h>
void fun()
{
printf("This is fun\n");
}
int main()
{
printf("Main in static.c\n");
}
에서 불러주세요.prog.c
그러면 링커는 기호를 찾기 위해 아카이브를 조사해야 합니다.fun
링커에서 중복 기호를 찾을 때와 동일한 다중 기본 정의 오류가 발생합니다.main
지금이다.
오브젝트 파일을 직접 컴파일 하는 경우( 참조)gcc a.o b.o
링커에는 역할이 없으며 모든 기호가 포함되어 단일 바이너리를 만듭니다.또한 중복된 기호가 존재합니다.
결론적으로 링커는 누락된 기호가 있는 경우에만 아카이브를 봅니다.그렇지 않으면 라이브러리와 링크하지 않는 것과 같습니다.
링커는 객체 파일을 로드한 후 라이브러리에서 정의되지 않은 기호를 검색합니다.아무것도 없는 경우는, 읽어낼 필요가 없는 라이브러리가 됩니다.main이 정의되어 있기 때문에 모든 라이브러리에서 main을 발견하더라도 두 번째 main을 로드할 필요가 없습니다.
그러나 링커들의 행동은 극적으로 다르다.예를 들어 라이브러리에 main()과 foo()가 모두 포함된 객체 파일이 포함되어 있고 foo가 정의되지 않은 경우 다중 정의된 기호 main()에 오류가 발생할 수 있습니다.
최신(동일어) 링커에서는 AIX와 같이 도달할 수 없는 개체에서 전역 기호를 생략합니다.Solaris나 Linux 시스템에 있는 것과 같은 오래된 스타일의 링커는 1970년대의 unix 링커와 동일하게 동작하며 도달 가능 여부에 관계없이 객체 모듈에서 모든 기호를 로드합니다.이로 인해 링크 시간이 지나치게 길어질 뿐만 아니라 끔찍한 블러트가 발생할 수 있습니다.
또한 *nix 링커의 특징은 라이브러리가 나열될 때마다 한 번만 효과적으로 검색된다는 것입니다.이로 인해 프로그래머는 프로그램 작성 외에 명령행의 라이브러리를 링커 또는 메이크 파일로 주문해야 합니다.라이브러리를 순서대로 나열할 필요가 없는 것은 현대적이지 않습니다.이전 운영 체제에는 종종 모든 라이브러리를 반복적으로 검색하여 통과가 실패하여 기호를 해결할 수 없을 때까지 검색하는 링커가 있었습니다.
언급URL : https://stackoverflow.com/questions/29556164/how-does-this-c-program-compile-and-run-with-two-main-functions
'itsource' 카테고리의 다른 글
이클립스 프로젝트에서 javascript 검증을 제거하려면 어떻게 해야 합니까? (0) | 2022.09.27 |
---|---|
iloc과 loc의 차이점은 무엇입니까? (0) | 2022.09.27 |
xdebug가 작동하는지 확인합니다. (0) | 2022.09.27 |
Vue 바인딩 상위 및 하위 구성 요소 (0) | 2022.09.26 |
MariaDb Json 지원 (0) | 2022.09.26 |