デバイスドライバーとカーネルプログラミングを学んでいます。 Jonathan Corbetの本によると、デバイスドライバーにはmain()
関数はありません。
だから私は2つの質問:
main()
関数が必要ないのはなぜですか?main()
関数がありますか?誰かがこれを私に説明できますか?
ユーザー空間プログラムでは、main()
はプログラムへのエントリポイントです。つまり、バイナリが実行されたときに libc初期化コードによって呼び出されます です。 libc自体がメモリの割り当て、I/O、プロセス管理などをカーネルのsyscallインターフェースに依存しているため、カーネルコードにはlibcに依存する余裕はありません。
とは言っても、カーネルコードでのmain()
はstart_kernel()
であり、これは ブートローダーによって呼び出されます カーネルイメージをロードしてメモリに解凍した後、重要なハードウェアとメモリのページングをセットアップします。 start_kernel()
は、システムセットアップの大部分を実行し、最終的にinitプロセスを生成します。
Linuxカーネルモジュールへのエントリポイントは、module_init()
マクロを呼び出すことによってカーネルに登録されるinit関数です。登録されたモジュール初期化関数は、カーネルの起動時にdo_initcalls()
関数を介して カーネルコードによって呼び出されます になります。
カーネルにはmain
関数がありません。 main
はC言語の概念です。カーネルはCおよびアセンブリで記述されています。カーネルのエントリコードはアセンブリによって記述されます。
起動シーケンスは次のように構成されています。
initrd
)で可能です。次に、あるアドレスのコードが実行されます。init
プロセス)を作成し、CPUのコンテキストをリング0からリング3に切り替え、initプロセス(プロセスIDは1)を開始します。これでカーネルブートが完了しました。init
プログラムは、すべてのinitスクリプトを実行します。すべてのサービスが開始されます。シェルが呼び出されます。ユーザーはログインできます。main
関数はC関数です。実は主な方法はCプログラムの入り口ではありません。 Cランタイムはmain
の前に多くの関数を呼び出します。 GCCには拡張機能(コンストラクター)があります。 「コンストラクタ」と宣言された関数は、main
の前に呼び出されます。
例えば:
/* This should not be used directly. Use block_init etc. instead. */
#define module_init(function, type) \
static void _attribute__((constructor)) do_qemu_init ## function(void) { \
register_module_init(function, type); \
}
このマクロはqemuプロジェクトからのものです。
たとえば、 Arch/x86/boot/main.c のmain()関数は、システムをリアルモードからプロテクトモードに切り替える準備をしますが、他のアーキテクチャにはそのようなコードはありません。ニース 概要 x86プラットフォームでのLinuxカーネル2.6.xのブートがどのように機能するかを示します。それは本当に読む価値があります。
ドキュメント HOWTO Linuxカーネル開発を行う によると、Linuxカーネルは
標準Cライブラリに依存しない独立したC環境。C標準の一部はサポートされていません。
c標準によると、BTWはそれを意味します
自立環境のプログラムが「メイン」関数を定義する必要があるかどうかは、実装定義です。