1. ホーム
  2. c

C言語でmain()なしのプログラムをコンパイルして実行する

2023-08-28 12:50:22

質問

以下のプログラムを main() 関数が C . 以下のコマンドでプログラムをコンパイルしてみました。

gcc -nostartfiles nomain.c

そして、コンパイラは警告を出します。

/usr/bin/ld: warning: cannot find entry symbol _start; defaulting to 0000000000400340

OK、問題なし。では、実行ファイル(a.out)を実行すると、両方の printf ステートメントが正常にプリントされ、その後 セグメンテーションフォールト .

そこで質問なのですが printステートメントが正常に実行された後、なぜセグメンテーションフォールトが発生するのでしょうか?

私のコードです。

#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 の戻り値で呼び出されます。