Development Tip

이 C 프로그램은 두 가지 주요 기능으로 어떻게 컴파일되고 실행됩니까?

yourdevel 2020. 11. 18. 21:32
반응형

이 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) 링커는 여기에 어떤 역할도하지 않으며 모든 기호가 포함되어 단일 바이너리를 만들고 분명히 중복 기호가 있습니다.

The bottom line is that linker looks at the archive only if there are missing symbols. Otherwise, it's as good as not linking with any libraries.


After the linker loads any object files, it searches libraries for undefined symbols. If there are none, then no libraries need to be read. Since main has been defined, even if it finds a main in every library, there is no reason to load a second one.

Linkers have dramatically different behaviors, however. For example, if your library included an object file with both main () and foo () in it, and foo was undefined, you would very likely get an error for a multiply defined symbol main ().

Modern (tautological) linkers will omit global symbols from objects that are unreachable - e.g. AIX. Old style linkers like those found on Solaris, and Linux systems still behave like the unix linkers from the 1970s, loading all of the symbols from an object module, reachable or not. This can be a source of horrible bloat as well as excessive link times.

Also characteristic of *nix linkers is that they effectively search a library only once for each time it is listed. This puts a demand on the programmer to order the libraries on the command line to a linker or in a make file, in addition to writing a program. Not requiring an ordered listing of libraries is not modern. Older operating systems often had linkers that would search all libraries repeatedly until a pass failed to resolve a symbol.

참고URL : https://stackoverflow.com/questions/29556164/how-does-this-c-program-compile-and-run-with-two-main-functions

반응형