linux内核有main函数吗

linux内核有main函数;main函数是程序的入口,main是应用程序和操作系统之间约定好的一个接口名,所以linux中每个应用程序的第一个函数必须是main。

linux内核有main函数吗

本教程操作环境:linux5.9.8系统、Dell G3电脑。

linux内核有main函数吗?

linux内核源码之main函数解析

这几天一直在纠结:

 

main函数是程序的入口,一个程序启动后,经过bootloader的初始化就该经main函数进入c语言的世界,但是linux中每个应用程序的开始都是从main函数开始的。linux下有多个应用程序,岂不是有很多个main。那bootloader会知道跳到哪个main?多个main编译怎么不冲突?

 

 

 

在网上搜索了很久,渐渐的有些明白了:

 

1、main函数是C语言的入口,这句话没错;但是这句话仅仅是一个约定,而非一个亘古不变的铁律!从程序的更为本质的汇编代码来看,只是大家约定汇编初始化完了后,跳到一个名字叫”main”的标号处;言外之意就是这个标号也是可以改名的,比如linux的C语言入口就是start_kernel();从这个标号地址后就是C语言的天下了。用main这个名字仅仅是因为大家的约定而已,不遵守约定能玩的转也行啊,就像苹果充电线啥的都和别人不一样。

 

2、在编译时是不存多个main函数的!每个应用程序虽说都有一个main函数(从应用程序来看应用程序的入口是main函数哦);但是应用程序都是独立编译的,不会一起编译,操作系统内核就更不可能和应用程序一起编译了!所以根本不存在多个main冲突的!!可能是统一操作系统与应用程序之间的接口,亦或是侧面影响下main是程序入口的说法,main是应用程序和操作系统之间约定好的一个接口名!所以linux中每个应用程序的第一个函数必须是main。除非你改掉了内核调度的接口地方。

 

3、linux的应用程序的安装启动也可以类比下我们每天都在用的windows。Windows应用程序的安装其实也是把一些执行文件拷贝到指定的文件夹里(从绿色软件看),点击就可以运行。linux下也是这样。编译好的bin文件放到指定的文件夹目录下,然后用命令启动执行。

 

/*  *  linux/init/main.c  *  *  Copyright (C) 1991, 1992  Linus Torvalds  *  *  GK 2/5/95  -  Changed to support mounting root fs via NFS  *  Added initrd &amp; change_root: Werner Almesberger &amp; Hans Lermen, Feb '96  *  Moan early if gcc is old, avoiding bogus kernels - Paul Gortmaker, May '96  *  Simplified starting of init:  Michael A. Griffith <grif>   * start_kernel-&gt;rest_init-&gt;kernel_init创建用户init  pid=1                           -&gt;kthreadd管理内核线程     pid=x                           -&gt;pid=0,是idle线程     在rest_init中,会创建kernel_init线程,它负责创建用户init进程,完成工作后,自己     化身为idle线程  */   #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux> #include <linux>   #include <asm> #include <asm> #include <asm> #include <asm> #include <asm>   #ifdef CONFIG_X86_LOCAL_APIC #include <asm> #endif   static int kernel_init(void *);   extern void init_IRQ(void); extern void fork_init(unsigned long); extern void mca_init(void); extern void sbus_init(void); extern void prio_tree_init(void); extern void radix_tree_init(void); #ifndef CONFIG_DEBUG_RODATA static inline void mark_rodata_ro(void) { } #endif   #ifdef CONFIG_TC extern void tc_init(void); #endif   /*  * Debug helper: via this flag we know that we are in 'early bootup code'  * where only the boot processor is running with IRQ disabled.  This means  * two things - IRQ must not be enabled before the flag is cleared and some  * operations which are not allowed with IRQ disabled are allowed while the  * flag is set.  */ bool early_boot_irqs_disabled __read_mostly;   enum system_states system_state __read_mostly; EXPORT_SYMBOL(system_state);   /*  * Boot command-line arguments  */ #define MAX_INIT_ARGS CONFIG_INIT_ENV_ARG_LIMIT #define MAX_INIT_ENVS CONFIG_INIT_ENV_ARG_LIMIT   extern void time_init(void); /* Default late time init is NULL. archs can override this later. */ void (*__initdata late_time_init)(void); extern void softirq_init(void);   /* Untouched command line saved by arch-specific code. */ char __initdata boot_command_line[COMMAND_LINE_SIZE]; /* Untouched saved command line (eg. for /proc) */ char *saved_command_line; /* Command line for parameter parsing */ static char *static_command_line;   static char *execute_command; static char *ramdisk_execute_command;   /*  * If set, this is an indication to the drivers that reset the underlying  * device before going ahead with the initialization otherwise driver might  * rely on the BIOS and skip the reset operation.  *  * This is useful if kernel is booting in an unreliable environment.  * For ex. kdump situaiton where previous kernel has crashed, BIOS has been  * skipped and devices will be in unknown state.  */ unsigned int reset_devices; EXPORT_SYMBOL(reset_devices);   static int __init set_reset_devices(char *str) {     reset_devices = 1;     return 1; }   __setup("reset_devices", set_reset_devices);   static const char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, }; const char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=linux", NULL, }; static const char *panic_later, *panic_param;   extern const struct obs_kernel_param __setup_start[], __setup_end[];   static int __init obsolete_checksetup(char *line) {     const struct obs_kernel_param *p;     int had_early_param = 0;       p = __setup_start;     do {         int n = strlen(p-&gt;str);         if (parameqn(line, p-&gt;str, n)) {             if (p-&gt;early) {                 /* Already done in parse_early_param?                  * (Needs exact match on param part).                  * Keep iterating, as we can have early                  * params and __setups of same names 8( */                 if (line[n] == '' || line[n] == '=')                     had_early_param = 1;             } else if (!p-&gt;setup_func) {                 printk(KERN_WARNING "Parameter %s is obsolete,"                        " ignoredn", p-&gt;str);                 return 1;             } else if (p-&gt;setup_func(line + n))                 return 1;         }         p++;     } while (p early &amp;&amp; parameq(param, p-&gt;str)) ||             (strcmp(param, "console") == 0 &amp;&amp;              strcmp(p-&gt;str, "earlycon") == 0)         ) {             if (p-&gt;setup_func(val) != 0)                 printk(KERN_WARNING                        "Malformed early option '%s'n", param);         }     }     /* We accept everything at this stage. */     return 0; } void __init parse_early_options(char *cmdline) {     parse_args("early options", cmdline, NULL, 0, 0, 0, do_early_param); } /* Arch code calls this early on, or if not, just before other parsing. */ void __init parse_early_param(void) {     static __initdata int done = 0;     static __initdata char tmp_cmdline[COMMAND_LINE_SIZE];     if (done)         return;     /* All fall through to do_early_param. */     strlcpy(tmp_cmdline, boot_command_line, COMMAND_LINE_SIZE);     parse_early_options(tmp_cmdline);     done = 1; } /*  *  Activate the first processor.  */ static void __init boot_cpu_init(void) {     int cpu = smp_processor_id();     /* Mark the boot cpu "present", "online" etc for SMP and UP case */     set_cpu_online(cpu, true);     set_cpu_active(cpu, true);     set_cpu_present(cpu, true);     set_cpu_possible(cpu, true); } void __init __weak smp_setup_processor_id(void) { } void __init __weak thread_info_cache_init(void) { } /*  * Set up kernel memory allocators  */ static void __init mm_init(void) {     /*      * page_cgroup requires contiguous pages,      * bigger than MAX_ORDER unless SPARSEMEM.      */     page_cgroup_init_flatmem();     mem_init();     kmem_cache_init();     percpu_init_late();     pgtable_cache_init();     vmalloc_init(); } asmlinkage void __init start_kernel(void) {     char * command_line;     extern const struct kernel_param __start___param[], __stop___param[];     /*      * Need to run as early as possible, to initialize the      * lockdep hash:      */     //初始化2个hash表-Lock Dependency Validator(内核依赖的关系表)     lockdep_init();     smp_setup_processor_id(); //空函数     debug_objects_early_init();//初始化内核调试相关     /*      * Set up the the initial canary ASAP:      */     boot_init_stack_canary();//栈溢出保护初始化     //控制组初始化-cgroup-资源任务分组管理     cgroup_init_early();     local_irq_disable();//关中断     early_boot_irqs_disabled = true; /*  * Interrupts are still disabled. Do necessary setups, then  * enable them  */     tick_init();//时钟初始化     boot_cpu_init();//启动cpu初始化     page_address_init();//页面初始化     printk(KERN_NOTICE "%s", linux_banner);     setup_arch(&amp;command_line);//架构相关初始化     mm_init_owner(&amp;init_mm, &amp;init_task);//内存管理初始化     mm_init_cpumask(&amp;init_mm);//内存管理初始化     setup_command_line(command_line);//处理命令行(保存2份)     setup_nr_cpu_ids();//cpuid相关     setup_per_cpu_areas();//每cpu变量申请空间(包括gdt)     //smp中用来启动的cpu     smp_prepare_boot_cpu(); /* arch-specific boot-cpu hooks */      //建立系统内存页区链表     build_all_zonelists(NULL);     //内存页相关初始化     page_alloc_init();     printk(KERN_NOTICE "Kernel command line: %sn", boot_command_line);     //命令行boot_command_line     parse_early_param();     //解析参数     parse_args("Booting kernel", static_command_line, __start___param,            __stop___param - __start___param,            -1, -1, &amp;unknown_bootoption);     //     jump_label_init();     /*      * These use large bootmem allocations and must precede      * kmem_cache_init()      * 内存初始化相关      */     setup_log_buf(0);     pidhash_init();     vfs_caches_init_early();     sort_main_extable();     trap_init();     mm_init();     /*      * Set up the scheduler prior starting any interrupts (such as the      * timer interrupt). Full topology setup happens at smp_init()      * time - but meanwhile we still have a functioning scheduler.      * 调度初始化      */     sched_init();     /*      * Disable preemption - early bootup scheduling is extremely      * fragile until we cpu_idle() for the first time.      * 抢占禁用      */     preempt_disable();     if (!irqs_disabled()) {         printk(KERN_WARNING "start_kernel(): bug: interrupts were "                 "enabled *very* early, fixing itn");         local_irq_disable();     }     idr_init_cache();//idr     perf_event_init();//performance event     rcu_init();//read-copy-update 机制     radix_tree_init();//radix树机制     /* init some links before init_ISA_irqs() */     early_irq_init();//中断请求     init_IRQ();//中断请求     prio_tree_init();//优先查找树     init_timers();//时钟     hrtimers_init();//High-resolution kernel timers高精度内核时钟     softirq_init();//软中断     timekeeping_init();//时间相关     time_init();//时间     profile_init();//分配内核性能统计保存的内存     call_function_init();//smp中每cpu的call_single_queue初始化     if (!irqs_disabled())         printk(KERN_CRIT "start_kernel(): bug: interrupts were "                  "enabled earlyn");     early_boot_irqs_disabled = false;//中断请求开     local_irq_enable();//本地中断开     kmem_cache_init_late();//kmem后期初始化     /*      * HACK ALERT! This is early. We're enabling the console before      * we've done PCI setups etc, and console_init() must be aware of      * this. But we do want output early, in case something goes wrong.      */     console_init();//初始化系统控制台结构     if (panic_later)         panic(panic_later, panic_param);     //锁依赖信息     lockdep_info();     /*      * Need to run this when irqs are enabled, because it wants      * to self-test [hard/soft]-irqs on/off lock inversion bugs      * too:      */     locking_selftest(); #ifdef CONFIG_BLK_DEV_INITRD     if (initrd_start &amp;&amp; !initrd_below_start_ok &amp;&amp;         page_to_pfn(virt_to_page((void *)initrd_start)) &gt; 10;     printk(KERN_DEBUG "initcall %pF returned %d after %lld usecsn", fn,         ret, duration);     return ret; } int __init_or_module do_one_initcall(initcall_t fn) {     int count = preempt_count();     int ret;     if (initcall_debug)         ret = do_one_initcall_debug(fn);     else         ret = fn();     msgbuf[0] = 0;     if (ret &amp;&amp; ret != -ENODEV &amp;&amp; initcall_debug)         sprintf(msgbuf, "error code %d ", ret);     if (preempt_count() != count) {         strlcat(msgbuf, "preemption imbalance ", sizeof(msgbuf));         preempt_count() = count;     }     if (irqs_disabled()) {         strlcat(msgbuf, "disabled interrupts ", sizeof(msgbuf));         local_irq_enable();     }     if (msgbuf[0]) {         printk("initcall %pF returned with %sn", fn, msgbuf);     }     return ret; } extern initcall_t __initcall_start[]; extern initcall_t __initcall0_start[]; extern initcall_t __initcall1_start[]; extern initcall_t __initcall2_start[]; extern initcall_t __initcall3_start[]; extern initcall_t __initcall4_start[]; extern initcall_t __initcall5_start[]; extern initcall_t __initcall6_start[]; extern initcall_t __initcall7_start[]; extern initcall_t __initcall_end[]; static initcall_t *initcall_levels[] __initdata = {     __initcall0_start,     __initcall1_start,     __initcall2_start,     __initcall3_start,     __initcall4_start,     __initcall5_start,     __initcall6_start,     __initcall7_start,     __initcall_end, }; static char *initcall_level_names[] __initdata = {     "early parameters",     "core parameters",     "postcore parameters",     "arch parameters",     "subsys parameters",     "fs parameters",     "device parameters",     "late parameters", }; static void __init do_initcall_level(int level) {     extern const struct kernel_param __start___param[], __stop___param[];     initcall_t *fn;     strcpy(static_command_line, saved_command_line);     parse_args(initcall_level_names[level],            static_command_line, __start___param,            __stop___param - __start___param,            level, level,            repair_env_string);     for (fn = initcall_levels[level]; fn signal-&gt;flags |= SIGNAL_UNKILLABLE;     //如果ramdisk_execute_command变量指定了init程序,执行它     if (ramdisk_execute_command) {         run_init_process(ramdisk_execute_command);         printk(KERN_WARNING "Failed to execute %sn",                 ramdisk_execute_command);     }     /*      * We try each of these until one succeeds.      *      * The Bourne shell can be used instead of init if we are      * trying to recover a really broken machine.      * 又一个程序,看能不能执行,如果不能,则执行下面4个之一      */     if (execute_command) {         run_init_process(execute_command);         printk(KERN_WARNING "Failed to execute %s.  Attempting "                     "defaults...n", execute_command);     }     run_init_process("/sbin/init");     run_init_process("/etc/init");     run_init_process("/bin/init");     run_init_process("/bin/sh");     //两个变量和4个init都不能成功执行,报错     panic("No init found.  Try passing init= option to kernel. "           "See Linux Documentation/init.txt for guidance."); } static int __init kernel_init(void * unused) {     /*      * Wait until kthreadd is all set-up.等待kthreadd的启动完成      */     wait_for_completion(&amp;kthreadd_done);     /* Now the scheduler is fully set up and can do blocking allocations       *       */     gfp_allowed_mask = __GFP_BITS_MASK;     /*      * init can allocate pages on any node      */     set_mems_allowed(node_states[N_HIGH_MEMORY]);     /*      * init can run on any cpu.      */     set_cpus_allowed_ptr(current, cpu_all_mask);     //cad_pid为接收Ctrl-alt-del操作的INT信号的进程ID,设置成了init的pid     //说明init可接受这3个键     cad_pid = task_pid(current);     //smp系统准备、激活所有cpu     smp_prepare_cpus(setup_max_cpus);     do_pre_smp_initcalls();     lockup_detector_init();     smp_init();     sched_init_smp();     //初始化设备驱动、内核模块     do_basic_setup();     /* Open the /dev/console on the rootfs, this should never fail       * 打开/dev/console设备      */     if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) <p>推荐学习:《<a href="https://www.php.cn/course/list/33.html" target="_blank">linux视频教程</a>》</p></asm></asm></asm></asm></asm></asm></linux></linux></linux></linux></linux></linux></linux></linux></linux></linux></linux></linux></linux></linux></linux></linux></linux></linux></linux></linux></linux></linux></linux></linux></linux></linux></linux></linux></linux></linux></linux></linux></linux></linux></linux></linux></linux></linux></linux></linux></linux></linux></linux></linux></linux></linux></linux></linux></linux></linux></linux></linux></linux></linux></linux></linux></linux></linux></linux></grif>

© 版权声明
THE END
喜欢就支持一下吧
点赞13 分享