云计算百科
云计算领域专业知识百科平台

第十八讲:Linux下程序执行流程

大家好,接下来的一段时间我将开始学习野火的Linux系统课程并将学习到的干货逐步更新到我的CSDN博客中。没时间刷课的同学可以把我的博客喂给AI 突击一下。

目录

三个问题

1、了解 Hello World 程序的执行过程有什么用?

2、裸机开发中的 HelloWorld 程序是怎么执行的?

3、Linux 系统下的 Hello World 程序是怎么执行的?

阶段一:GCC 编译四步

阶段二:程序运行完整流程

四个案例

gcc 预处理 c 文件

gcc 编译 c 文件(生成汇编)

gcc 编译汇编(生成目标文件)

gcc 链接可重定位文件


Linux系统下的Hello World的借鉴意义非常强, 对我们以后进一步学习其他课程起到很好的指导作用,面试的时候面试官也很爱问这部分知识来考验面试者知识扎实程度,大家尽量把这块“硬骨头”啃下来。

5. Linux系统下的Hello World — [野火]嵌入式Linux基础与应用开发实战指南——基于i.MX6ULL开发板 文档https://doc.embedfire.com/linux/imx6/linux_base/zh/latest/linux_app/hello_in_linux/hello_in_linux.html

三个问题

1、了解 Hello World 程序的执行过程有什么用?

  • 对开发其他应用程序,有非常好的借鉴意义。
  • 对程序的报错有清晰的了解,从而针对性地解决问题。
  • 2、裸机开发中的 HelloWorld 程序是怎么执行的?

    裸机:无操作系统,CPU 上电直接跳转到程序入口。

    上电→CPU 复位,执行复位向量入口函数→初始化栈、bss 段→手动调用 main 函数→执行打印(操作寄存器驱动串口)→程序循环 / 退出。

    3、Linux 系统下的 Hello World 程序是怎么执行的?

    完整链路分为两大阶段:GCC 编译阶段 + 程序运行阶段(Shell‑内核‑glibc‑应用)

    阶段一:GCC 编译四步
    序号步骤命令输入输出说明
    预处理 gcc -E hello.c -o hello.i hello.c hello.i 展开头文件、宏替换,去掉注释
    编译 gcc -S hello.i -o hello.s hello.i hello.s C 语言→汇编代码
    汇编 gcc -c hello.s -o hello.o hello.s hello.o 汇编→机器码,可重定位目标文件
    链接 gcc hello.o -o hello hello.o hello(ELF 可执行程序) 合并段,链接系统库,生成最终可执行文件

    编译完成得到 ELF 格式 hello,Shell 输入 ./hello 开始运行。

    阶段二:程序运行完整流程

    ⑤ Shell 收到./hello命令 ⑥ Shell 调用fork()系统调用,创建子进程 ⑦ 子进程调用execve()用户态库函数 ⑧ 陷入内核,执行系统调用入口sys_execve() ⑨ 内核内部调用do_execve(),解析 ELF 文件 ⑩ load_elf_binary():内核加载 ELF 程序到进程虚拟地址空间;加载动态链接器ld‑linux‑xx.so ⑪ 把 CPU 控制权交给动态链接器 ⑫ 动态链接器完成库重定位,调用_start;_start调用 glibc 入口_libc_start_main() ⑬ _libc_start_main()做初始化,调用我们写的 main () 函数 ⑭ main 内部执行printf("hello,world!\\r\\n");main 返回后 glibc 调用_exit()系统调用,通知内核销毁进程,程序结束。

    关键点:main 不是程序的真正入口,真正入口是_start,main 只是库函数调用的一个普通函数。

    四个案例

    gcc 预处理 c 文件

    gcc -E hello.c -o hello.i #末尾加上-v把信息全部打印出来

    片段说明
    cc1 GCC 的 C 语言编译器前端(真正干活的程序,gcc 命令只是个调度器)
    -E 只做预处理,不编译
    hello.c 输入源文件
    -o hello.i 输出预处理后的 .i 文件
    -fstack-protector-strong 栈保护(防溢出攻击)
    -Wformat -Wformat-security 格式化字符串安全警告

    gcc 编译 c 文件(生成汇编)

    gcc -S hello.i -o hello.s #末尾加上-v把信息全部打印出来

    片段说明
    cc1 同一个编译器前端,这次不带 -E
    -fpreprocessed 告诉 cc1 输入已经是预处理过的文件,不用再处理宏了
    hello.i 输入:预处理文件
    -o hello.s 输出:汇编代码 .s 文件

    gcc 编译汇编(生成目标文件)

    gcc -c hello.s -o hello.o #末尾加上-v把信息全部打印出来

    片段说明
    as binutils 里的汇编器,不属于 gcc 本体
    -64 生成 64 位目标代码
    hello.s 输入:汇编文件
    -o hello.o 输出:二进制目标文件 .o(ELF 可重定位文件)

    gcc 链接可重定位文件

    gcc hello.o -o hello #末尾加上-v把信息全部打印出来

    片段说明
    collect2 GCC 的链接器封装,内部最终调用 ld
    crt1.o / crti.o / crtbegin.o C 运行时启动文件,包含 _start 入口,负责调用 _libc_start_main → main
    hello.o 我们自己编译的目标文件
    crtend.o / crtn.o 运行时收尾文件
    -lc 链接 libc 标准 C 库(printf 就在这里)
    -o hello 输出最终可执行程序

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » 第十八讲:Linux下程序执行流程
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!