Skompilować i uruchomić program bez main() w C
Próbuję skompilować i uruchomić następujący program bez main()
funkcji w C
. Skompilowałem mój program używając następującego polecenia.
gcc -nostartfiles nomain.c
I kompilator daje ostrzeżenie
/usr/bin/ld: warning: cannot find entry symbol _start; defaulting to 0000000000400340
Nie ma sprawy. następnie uruchomiłem plik wykonywalny (a. out), obie printf
instrukcje druk pomyślnie, a następnie uzyskać segmentation fault.
Moje pytanie brzmi: Dlaczego błąd segmentacji po pomyślnym wykonaniu instrukcji print?
Mój kod:
#include <stdio.h>
void nomain()
{
printf("Hello World...\n");
printf("Successfully run without main...\n");
}
Wyjście:
Hello World...
Successfully run without main...
Segmentation fault (core dumped)
Uwaga:
Tutaj, -nostartfiles
flaga gcc uniemożliwia kompilatorowi używanie standardowych plików startowych podczas łączenia
2 answers
Spójrzmy na wygenerowany assembly Twojego programu:
.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
Zwróć uwagę na ret
oświadczenie. Punkt wejścia Twojego programu jest określony jako nomain
, wszystko jest w porządku. Ale gdy funkcja powróci, próbuje wskoczyć na adres na stosie połączeń... to nie jest zaludnione. To jest nielegalny dostęp i wynika z tego błąd segmentacji.
Szybkim rozwiązaniem byłoby wywołanie exit()
na końcu programu (i zakładając C11 możemy równie dobrze oznaczyć funkcja jako _Noreturn
):
#include <stdio.h>
#include <stdlib.h>
_Noreturn void nomain(void)
{
printf("Hello World...\n");
printf("Successfully run without main...\n");
exit(0);
}
W rzeczywistości, teraz twoja funkcja zachowuje się prawie jak zwykła funkcja main
, ponieważ po powrocie z main
, Funkcja exit
jest wywoływana z wartością zwracaną przez main
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-20 18:25:48
W C, gdy funkcje / podprogramy są wywoływane, stos jest wypełniany w kolejności:
- argumenty,
- adres zwrotny,
- zmienne lokalne, -- > top of the stack
Main () jako punkt startowy, Elf konstruuje program w taki sposób, że instrukcje, które pojawią się pierwsze, zostaną wypchnięte jako pierwsze, w tym przypadku printf.
Teraz program jest jakby okrojony bez return-address lub {[0] } i zakłada, że cokolwiek jest na stosie w tej lokalizacji (__end__
) jest adresem zwrotnym, ale niestety nie jest i dlatego się zawiesza.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-19 17:54:16