main()
에서 함수 없이 다음 프로그램을 컴파일하고 실행하려고합니다 C
. 다음 명령을 사용하여 프로그램을 컴파일했습니다.
gcc -nostartfiles nomain.c
그리고 컴파일러는 경고를 제공합니다.
/usr/bin/ld: warning: cannot find entry symbol _start; defaulting to 0000000000400340
알겠습니다. 문제 없습니다. 그런 다음 실행 파일 (a.out)을 실행하고 두 printf
명령문이 모두 성공적으로 인쇄 된 다음 분할 오류가 발생 합니다.
그래서, 내 질문은, 인쇄 문을 성공적으로 실행 한 후 왜 세분화 오류가 발생합니까?
내 코드 :
#include <stdio.h>
void nomain()
{
printf("Hello World...\n");
printf("Successfully run without main...\n");
}
산출:
Hello World...
Successfully run without main...
Segmentation fault (core dumped)
노트 :
여기서 -nostartfiles
gcc 플래그는 링크 할 때 컴파일러가 표준 시작 파일을 사용하지 못하도록합니다.
답변
프로그램 의 생성 된 어셈블리 를 살펴 보겠습니다 .
.LC0:
.string "Hello World..."
.LC1:
.string "Successfully run without main..."
nomain:
push rbp
mov rbp, rsp
mov edi, OFFSET FLAT:.LC0
call puts
mov edi, OFFSET FLAT:.LC1
call puts
nop
pop rbp
ret
ret
진술에 유의하십시오 . 프로그램의 진입 점이으로 결정되었습니다 nomain
. 모두 괜찮습니다. 그러나 함수가 반환되면 채워지지 않은 호출 스택의 주소로 점프하려고 시도합니다. 그것은 불법적 인 접근이고 세분화 오류가 뒤 따릅니다.
빠른 해결책은 exit()
프로그램 끝에서 호출하는 것입니다 (그리고 C11을 가정하면 함수를으로 표시 할 수 있습니다 _Noreturn
).
#include <stdio.h>
#include <stdlib.h>
_Noreturn void nomain(void)
{
printf("Hello World...\n");
printf("Successfully run without main...\n");
exit(0);
}
실제로 함수는 main
에서 반환 한 후의 반환 값으로 호출 main
되므로 이제 exit
함수는 일반 함수 와 거의 비슷하게 작동 main
합니다.
답변
C에서 함수 / 서브 루틴이 호출되면 스택이 다음과 같이 채워집니다 (순서대로).
- 인수,
- 반송 주소,
- 지역 변수,-> 스택 상단
main ()이 시작점이고, ELF는 먼저 오는 명령어가 먼저 푸시되도록 프로그램을 구성합니다.이 경우에는 printfs가 그렇습니다.
이제 프로그램은 반환 주소 또는 반환 주소없이 잘립니다. __end__
실제로 해당 ( __end__
) 위치 의 스택에있는 모든 것이 반환 주소 라고 가정 하지만 불행히도 그렇지 않아 충돌합니다.