1. C/C++ 编译的四个步骤从源代码到可执行文件,通常分为:预处理 → 编译 → 汇编 → 链接。1.1 预处理(Preprocessing)处理以#开头的预处理指令,例如展开#include引入的头文件、替换宏、处理条件编译,并去掉注释。gcc-Emain.c-omain.i-E表示只进行预处理。C 的预处理结果通常以.i结尾,C++ 通常以.ii结尾。1.2 编译(Compilation)对预处理后的代码进行语法、语义检查和优化,生成目标架构的汇编代码。gcc-Smain.i-omain.s-S表示执行到生成汇编代码为止。这里的“编译”指四个步骤中的这一步;平时也会用“编译”泛指整个构建过程。1.3 汇编(Assembly)把汇编代码转换成机器指令,生成目标文件。gcc-cmain.s-omain.o-c表示执行到生成目标文件为止,不进行链接。.o文件通常包含机器代码、符号表、重定位信息等,还不能直接作为程序运行。1.4 链接(Linking)把目标文件与其他目标文件、所需库以及启动代码组合起来,解析函数和变量等符号的引用,完成必要的重定位,生成可执行文件。以test.c和v.c两个源文件为例,先分别生成目标文件,再将它们链接为一个程序:# 分别生成目标文件(完成预处理、编译和汇编,不进行链接)gcc-ctest.c-otest.o gcc-cv.c-ov.o# 将两个目标文件链接成可执行文件 testgcc test.o v.o-otest# 运行程序(要求架构与当前系统兼容)./test其中,test.o和v.o是链接的输入,-o test指定生成的可执行文件名。例如,test.c中使用了在v.c中定义的全局变量或函数,需要在test.c中提供相应声明。分别生成目标文件后,对这些外部符号的引用通常仍待解析;链接器会在v.o中找到对应定义,把两个目标文件组合成完整程序。如果漏掉v.o,且其他输入也没有提供这些定义,通常会报undefined reference(未定义的引用)。代码中调用printf()等库函数时,链接还需要处理对相应库的引用。动态链接的程序在运行时还需要相应的动态库。1.5 一条命令完成整个过程# C 程序gcc main.c-omain# C++ 程序g++ main.cpp-omain# 运行生成的程序(要求架构与当前系统兼容)./main上面的单条构建命令会完成四个步骤,默认不会保留中间的.i、.s、.o文件。C++ 通常使用g++,它会自动链接常用的 C++ 标准库。记忆:预处理展开代码,编译生成汇编,汇编生成目标文件,链接生成可执行文件。2. 交叉编译工具链(以 i.MX6ULL 为例)2.1 什么是交叉编译交叉编译是指:在一种平台上编译,生成供另一种平台运行的程序。例如,在 x86_64 架构的 Linux 电脑上编译代码,生成能在 i.MX6ULL 开发板上运行的 ARM 程序。电脑是开发主机,开发板是目标平台。i.MX6ULL 是 NXP 的处理器,采用32 位 ARM Cortex-A7 内核。因此,为它编译程序时,需要使用适合目标 ARM 平台的工具链。参考:NXP i.MX6ULL 产品资料2.2 工具链一般从哪里获取一般优先使用芯片厂商或开发板厂商随 BSP/SDK 提供、推荐的交叉编译工具链。BSP(板级支持包):包含与开发板相关的启动、内核、驱动及构建配置等内容。SDK(软件开发套件):通常包含交叉编译工具链、目标系统的头文件和库,以及环境配置脚本。以 i.MX6ULL 为例,先查看 NXP 或所用开发板厂商的配套资料,使用与板上系统版本相匹配的工具链和 SDK。工具链不仅要匹配 CPU 架构,还要考虑 ABI(如浮点调用约定)、C 库及目标系统的库版本;仅看到名称里有arm,还不足以确认兼容。根据本次提供的百问网开发包目录,实际使用的工具链前缀是arm-buildroot-linux-gnueabihf-,后续示例采用这一前缀。2.3 为什么叫“工具链”它是一组配合完成编译、汇编、链接等工作的工具。以当前开发包的arm-buildroot-linux-gnueabihf-前缀为例:工具名称主要用途arm-buildroot-linux-gnueabihf-gccC 编译驱动,也可调度汇编、链接等步骤arm-buildroot-linux-gnueabihf-g++C++ 编译驱动arm-buildroot-linux-gnueabihf-as汇编器arm-buildroot-linux-gnueabihf-ld链接器arm-buildroot-linux-gnueabihf-ar创建静态库arm-buildroot-linux-gnueabihf-objcopy复制、提取或转换目标文件内容生成的test应复制到匹配的 i.MX6ULL Linux 开发板上运行;在普通 x86_64 主机上通常不能直接运行。记忆:在电脑上编译,在开发板上运行;工具链优先选厂商配套版本。3. ELF 文件格式3.1 什么是 ELFELF(Executable and Linkable Format,可执行与可链接格式)是 Linux 平台上广泛使用的二进制文件格式。前面生成的.o目标文件、最终的可执行程序,以及.so共享库,都可以采用 ELF 格式。ELF 文件不仅保存机器指令和数据,还保存文件头、加载信息、符号表、调试信息等,供链接器、系统加载器和调试器使用。Linux 执行 ELF 程序时,需要根据其中的加载信息建立程序的内存映像。3.2 ELF 文件结构示意图下图按课堂照片右侧的内容重绘,保留各层名称和分组:重点记住:文件头与头表:记录文件基本信息、各部分的位置及加载方式。.text:存放机器指令。.rodata:存放只读数据,如字符串常量。.data与.bss:存放全局变量和静态变量;初值非零的通常放在.data,未显式初始化或初值为零的通常放在.bss。符号与调试信息:.symtab记录函数、变量等符号,图中的.stab保存调试信息。记忆:ELF 不只是代码和数据,还包含供链接、加载和调试使用的信息。4. file 和 readelf 命令4.1 用两种编译器编译同一个 test.c在 Linux 开发主机上,进入test.c所在目录,分别使用普通gcc和开发板配套的交叉编译器编译同一份源码。以下假设交叉编译工具链的bin已加入PATH。# 普通 gcc:生成供当前 Linux 主机运行的程序gcc test.c-otest_pc# i.MX6ULL 配套交叉编译器:生成供开发板运行的程序arm-buildroot-linux-gnueabihf-gcc test.c-otest_arm两个命令使用同一个test.c,分别输出test_pc和test_arm。4.2 分别使用 file 查看两个文件成功生成两个文件后,在同一目录执行:filetest_pcfiletest_armfile用于识别文件类型。重点比较输出中的位数和目标架构:对比项test_pctest_arm位数64-bit,64 位32-bit,32 位目标架构x86-64,面向当前电脑ARM,面向 i.MX6ULL 开发板类型描述shared objectexecutable动态加载器/lib64/ld-linux-x86-64.so.2/lib/ld-linux-armhf.so.3两者都是 ELF 文件,LSB表示小端字节序,dynamically linked表示动态链接。结论:同一个test.c,普通gcc生成 x86-64 程序,交叉编译器生成 ARM 程序;两者面向不同平台,通常不能直接互换运行。4.3 使用 readelf -h 查看文件头readelf -h用于查看ELF 文件头,比file提供更详细的信息。分别查看两个文件:readelf-htest_pc readelf-htest_arm这里的-h表示查看文件头。也可使用工具链配套的arm-buildroot-linux-gnueabihf-readelf -h test_arm查看 ARM 程序。test_pc的实际输出:test_arm的实际输出:作用:确认程序的位数、目标架构、文件类型和入口等信息,帮助检查是否编译成了目标平台需要的程序。字段test_pctest_armClass(位数)ELF64,64 位ELF32,32 位Machine(架构)x86-64ARMType(类型)DYN,结合前面的编译方式,可能为 PIE 程序EXEC,可执行文件Flags(架构相关标志)0x0EABI5、hard-float ABI(硬浮点调用约定)Entry point address是程序入口,通常对应启动代码,不能直接当作main()的地址。5. BIN 文件与 ELF 的区别这里的BIN 指原始二进制镜像(Raw Binary),通常保存程序的机器指令和数据,没有 ELF 文件头、程序头表、节头表等结构信息,常用于裸机程序或固件烧录。对比ELFBIN(原始二进制镜像)内容代码、数据,以及加载、链接等结构信息,可含符号和调试信息主要是代码和数据的原始字节加载方式加载器可以从文件头和程序头等获取加载位置与入口加载位置和入口通常由启动流程或外部约定指定常见用途Linux 应用程序、目标文件、共享库及调试裸机程序、固件镜像及烧录信息查看可用readelf查看内部结构没有 ELF 结构,不能直接用readelf解析两者都可以包含 CPU 执行的机器指令。BIN 也需要正确加载和启动;把普通 Linux 应用的 ELF 转成 BIN,并不会自动变成能独立运行的裸机程序。GNUobjcopy的原始二进制输出说明可参考 官方文档。记忆:ELF 带有结构和描述信息,BIN 是按约定使用的原始字节镜像。.bin只是常见扩展名,不能仅凭后缀确定实际格式。6. 交叉编译工具链中常用的工具6.1 arm-buildroot-linux-gnueabihf-size 工具作用:统计目标文件或可执行文件中代码、数据等节的大小,帮助了解程序的空间占用。arm-buildroot-linux-gnueabihf-size test_arm实际输出:大小的单位都是字节。列名本次值含义text865程序指令和只读内容(如字符串)占多大data288静态区,全局变量bss4程序启动时要清零的数据占多大,如没写初值的全局变量dec1157前面三项加起来,用十进制表示hex485同一个总数,换成十六进制表示filenametest_arm查看的是哪个文件6.2 arm-buildroot-linux-gnueabihf-nm 工具作用:查看目标文件或可执行文件的符号表,了解函数、变量的名称、类型和地址等信息。arm-buildroot-linux-gnueabihf-nm test_arm可以把符号表理解成程序的**“索引表”,主要记录函数、变量等的名字、位置和类别**,方便链接器、调试器查找。例如图中的0001040c T main:main:函数的名字。0001040c:这个函数在该程序中的地址,用十六进制表示。T:表示符号位于代码区。图中的U puts@GLIBC_2.4表示:程序使用了puts,但它的定义由外部库提供,当前文件中没有定义。普通符号表通常不影响已链接程序的正常运行。链接完成后,CPU 按机器指令执行,调用函数不需要再查找main等名字。因此,去掉普通符号表(.symtab)通常仍能运行,只是查看函数名、调试和定位问题会更困难。动态链接所需的动态符号表(.dynsym)仍需保留。6.3 arm-buildroot-linux-gnueabihf-strip 工具作用:去掉程序中运行时不需要的符号、调试信息等,减小文件体积。# 查看处理前的文件信息filetest_arm# 使用交叉工具链的 strip,直接修改 test_armarm-buildroot-linux-gnueabihf-strip test_arm# 再次查看文件信息filetest_arm处理前not stripped:尚未剥离普通符号表等信息。处理后stripped:已剥离这些信息,文件通常会变小。图中处理前后仍是32 位 ARM ELF 可执行文件,动态链接方式也没有改变。去掉的是运行时不需要的辅助信息,通常不影响程序正常运行。6.4 arm-buildroot-linux-gnueabihf-objdump 工具作用:反汇编,把程序中的机器码显示成汇编指令,方便查看程序实际执行的指令。arm-buildroot-linux-gnueabihf-objdump-dtest_arm-d表示反汇编,查看test_arm中的机器码所对应的汇编指令。6.5 arm-buildroot-linux-gnueabihf-objcopy 工具作用:复制、提取或转换目标文件中的内容,例如把 ELF 文件转换成 BIN 文件。arm-buildroot-linux-gnueabihf-objcopy-Obinary test_arm test_arm.bin-O binary指定输出为原始二进制格式,test_arm是输入文件,test_arm.bin是生成的文件。格式转换不会让这个 Linux 应用自动变成能独立运行的裸机程序。为什么转成 BIN 后,仍不能直接脱离 Linux 运行?因为objcopy只转换文件格式,不改变程序原来的依赖。当前的test_arm是 Linux 动态链接程序,依赖 Linux 的加载器、库和系统服务,转成 BIN 后这些需求仍然存在。转换有什么意义?BIN 方便交给按地址写入原始字节的烧录工具或加载程序使用。裸机开发中,程序会事先配好启动代码、链接地址和必要的硬件初始化,先生成 ELF 供调试,再转换成 BIN 供烧录或加载:按裸机要求编写的程序 → ELF(供链接、调试)→ BIN(供烧录、加载)因此,本次把 Linux 应用转成 BIN,主要是练习格式转换;它不会因此获得裸机运行能力。能否脱离操作系统,取决于程序怎么编写和构建,而不是文件后缀。
1. C/C++ 编译的四个步骤从源代码到可执行文件,通常分为:预处理 → 编译 → 汇编 → 链接。1.1 预处理(Preprocessing)处理以#开头的预处理指令,例如展开#include引入的头文件、替换宏、处理条件编译,并去掉注释。gcc-Emain.c-omain.i-E表示只进行预处理。C 的预处理结果通常以.i结尾,C++ 通常以.ii结尾。1.2 编译(Compilation)对预处理后的代码进行语法、语义检查和优化,生成目标架构的汇编代码。gcc-Smain.i-omain.s-S表示执行到生成汇编代码为止。这里的“编译”指四个步骤中的这一步;平时也会用“编译”泛指整个构建过程。1.3 汇编(Assembly)把汇编代码转换成机器指令,生成目标文件。gcc-cmain.s-omain.o-c表示执行到生成目标文件为止,不进行链接。.o文件通常包含机器代码、符号表、重定位信息等,还不能直接作为程序运行。1.4 链接(Linking)把目标文件与其他目标文件、所需库以及启动代码组合起来,解析函数和变量等符号的引用,完成必要的重定位,生成可执行文件。以test.c和v.c两个源文件为例,先分别生成目标文件,再将它们链接为一个程序:# 分别生成目标文件(完成预处理、编译和汇编,不进行链接)gcc-ctest.c-otest.o gcc-cv.c-ov.o# 将两个目标文件链接成可执行文件 testgcc test.o v.o-otest# 运行程序(要求架构与当前系统兼容)./test其中,test.o和v.o是链接的输入,-o test指定生成的可执行文件名。例如,test.c中使用了在v.c中定义的全局变量或函数,需要在test.c中提供相应声明。分别生成目标文件后,对这些外部符号的引用通常仍待解析;链接器会在v.o中找到对应定义,把两个目标文件组合成完整程序。如果漏掉v.o,且其他输入也没有提供这些定义,通常会报undefined reference(未定义的引用)。代码中调用printf()等库函数时,链接还需要处理对相应库的引用。动态链接的程序在运行时还需要相应的动态库。1.5 一条命令完成整个过程# C 程序gcc main.c-omain# C++ 程序g++ main.cpp-omain# 运行生成的程序(要求架构与当前系统兼容)./main上面的单条构建命令会完成四个步骤,默认不会保留中间的.i、.s、.o文件。C++ 通常使用g++,它会自动链接常用的 C++ 标准库。记忆:预处理展开代码,编译生成汇编,汇编生成目标文件,链接生成可执行文件。2. 交叉编译工具链(以 i.MX6ULL 为例)2.1 什么是交叉编译交叉编译是指:在一种平台上编译,生成供另一种平台运行的程序。例如,在 x86_64 架构的 Linux 电脑上编译代码,生成能在 i.MX6ULL 开发板上运行的 ARM 程序。电脑是开发主机,开发板是目标平台。i.MX6ULL 是 NXP 的处理器,采用32 位 ARM Cortex-A7 内核。因此,为它编译程序时,需要使用适合目标 ARM 平台的工具链。参考:NXP i.MX6ULL 产品资料2.2 工具链一般从哪里获取一般优先使用芯片厂商或开发板厂商随 BSP/SDK 提供、推荐的交叉编译工具链。BSP(板级支持包):包含与开发板相关的启动、内核、驱动及构建配置等内容。SDK(软件开发套件):通常包含交叉编译工具链、目标系统的头文件和库,以及环境配置脚本。以 i.MX6ULL 为例,先查看 NXP 或所用开发板厂商的配套资料,使用与板上系统版本相匹配的工具链和 SDK。工具链不仅要匹配 CPU 架构,还要考虑 ABI(如浮点调用约定)、C 库及目标系统的库版本;仅看到名称里有arm,还不足以确认兼容。根据本次提供的百问网开发包目录,实际使用的工具链前缀是arm-buildroot-linux-gnueabihf-,后续示例采用这一前缀。2.3 为什么叫“工具链”它是一组配合完成编译、汇编、链接等工作的工具。以当前开发包的arm-buildroot-linux-gnueabihf-前缀为例:工具名称主要用途arm-buildroot-linux-gnueabihf-gccC 编译驱动,也可调度汇编、链接等步骤arm-buildroot-linux-gnueabihf-g++C++ 编译驱动arm-buildroot-linux-gnueabihf-as汇编器arm-buildroot-linux-gnueabihf-ld链接器arm-buildroot-linux-gnueabihf-ar创建静态库arm-buildroot-linux-gnueabihf-objcopy复制、提取或转换目标文件内容生成的test应复制到匹配的 i.MX6ULL Linux 开发板上运行;在普通 x86_64 主机上通常不能直接运行。记忆:在电脑上编译,在开发板上运行;工具链优先选厂商配套版本。3. ELF 文件格式3.1 什么是 ELFELF(Executable and Linkable Format,可执行与可链接格式)是 Linux 平台上广泛使用的二进制文件格式。前面生成的.o目标文件、最终的可执行程序,以及.so共享库,都可以采用 ELF 格式。ELF 文件不仅保存机器指令和数据,还保存文件头、加载信息、符号表、调试信息等,供链接器、系统加载器和调试器使用。Linux 执行 ELF 程序时,需要根据其中的加载信息建立程序的内存映像。3.2 ELF 文件结构示意图下图按课堂照片右侧的内容重绘,保留各层名称和分组:重点记住:文件头与头表:记录文件基本信息、各部分的位置及加载方式。.text:存放机器指令。.rodata:存放只读数据,如字符串常量。.data与.bss:存放全局变量和静态变量;初值非零的通常放在.data,未显式初始化或初值为零的通常放在.bss。符号与调试信息:.symtab记录函数、变量等符号,图中的.stab保存调试信息。记忆:ELF 不只是代码和数据,还包含供链接、加载和调试使用的信息。4. file 和 readelf 命令4.1 用两种编译器编译同一个 test.c在 Linux 开发主机上,进入test.c所在目录,分别使用普通gcc和开发板配套的交叉编译器编译同一份源码。以下假设交叉编译工具链的bin已加入PATH。# 普通 gcc:生成供当前 Linux 主机运行的程序gcc test.c-otest_pc# i.MX6ULL 配套交叉编译器:生成供开发板运行的程序arm-buildroot-linux-gnueabihf-gcc test.c-otest_arm两个命令使用同一个test.c,分别输出test_pc和test_arm。4.2 分别使用 file 查看两个文件成功生成两个文件后,在同一目录执行:filetest_pcfiletest_armfile用于识别文件类型。重点比较输出中的位数和目标架构:对比项test_pctest_arm位数64-bit,64 位32-bit,32 位目标架构x86-64,面向当前电脑ARM,面向 i.MX6ULL 开发板类型描述shared objectexecutable动态加载器/lib64/ld-linux-x86-64.so.2/lib/ld-linux-armhf.so.3两者都是 ELF 文件,LSB表示小端字节序,dynamically linked表示动态链接。结论:同一个test.c,普通gcc生成 x86-64 程序,交叉编译器生成 ARM 程序;两者面向不同平台,通常不能直接互换运行。4.3 使用 readelf -h 查看文件头readelf -h用于查看ELF 文件头,比file提供更详细的信息。分别查看两个文件:readelf-htest_pc readelf-htest_arm这里的-h表示查看文件头。也可使用工具链配套的arm-buildroot-linux-gnueabihf-readelf -h test_arm查看 ARM 程序。test_pc的实际输出:test_arm的实际输出:作用:确认程序的位数、目标架构、文件类型和入口等信息,帮助检查是否编译成了目标平台需要的程序。字段test_pctest_armClass(位数)ELF64,64 位ELF32,32 位Machine(架构)x86-64ARMType(类型)DYN,结合前面的编译方式,可能为 PIE 程序EXEC,可执行文件Flags(架构相关标志)0x0EABI5、hard-float ABI(硬浮点调用约定)Entry point address是程序入口,通常对应启动代码,不能直接当作main()的地址。5. BIN 文件与 ELF 的区别这里的BIN 指原始二进制镜像(Raw Binary),通常保存程序的机器指令和数据,没有 ELF 文件头、程序头表、节头表等结构信息,常用于裸机程序或固件烧录。对比ELFBIN(原始二进制镜像)内容代码、数据,以及加载、链接等结构信息,可含符号和调试信息主要是代码和数据的原始字节加载方式加载器可以从文件头和程序头等获取加载位置与入口加载位置和入口通常由启动流程或外部约定指定常见用途Linux 应用程序、目标文件、共享库及调试裸机程序、固件镜像及烧录信息查看可用readelf查看内部结构没有 ELF 结构,不能直接用readelf解析两者都可以包含 CPU 执行的机器指令。BIN 也需要正确加载和启动;把普通 Linux 应用的 ELF 转成 BIN,并不会自动变成能独立运行的裸机程序。GNUobjcopy的原始二进制输出说明可参考 官方文档。记忆:ELF 带有结构和描述信息,BIN 是按约定使用的原始字节镜像。.bin只是常见扩展名,不能仅凭后缀确定实际格式。6. 交叉编译工具链中常用的工具6.1 arm-buildroot-linux-gnueabihf-size 工具作用:统计目标文件或可执行文件中代码、数据等节的大小,帮助了解程序的空间占用。arm-buildroot-linux-gnueabihf-size test_arm实际输出:大小的单位都是字节。列名本次值含义text865程序指令和只读内容(如字符串)占多大data288静态区,全局变量bss4程序启动时要清零的数据占多大,如没写初值的全局变量dec1157前面三项加起来,用十进制表示hex485同一个总数,换成十六进制表示filenametest_arm查看的是哪个文件6.2 arm-buildroot-linux-gnueabihf-nm 工具作用:查看目标文件或可执行文件的符号表,了解函数、变量的名称、类型和地址等信息。arm-buildroot-linux-gnueabihf-nm test_arm可以把符号表理解成程序的**“索引表”,主要记录函数、变量等的名字、位置和类别**,方便链接器、调试器查找。例如图中的0001040c T main:main:函数的名字。0001040c:这个函数在该程序中的地址,用十六进制表示。T:表示符号位于代码区。图中的U puts@GLIBC_2.4表示:程序使用了puts,但它的定义由外部库提供,当前文件中没有定义。普通符号表通常不影响已链接程序的正常运行。链接完成后,CPU 按机器指令执行,调用函数不需要再查找main等名字。因此,去掉普通符号表(.symtab)通常仍能运行,只是查看函数名、调试和定位问题会更困难。动态链接所需的动态符号表(.dynsym)仍需保留。6.3 arm-buildroot-linux-gnueabihf-strip 工具作用:去掉程序中运行时不需要的符号、调试信息等,减小文件体积。# 查看处理前的文件信息filetest_arm# 使用交叉工具链的 strip,直接修改 test_armarm-buildroot-linux-gnueabihf-strip test_arm# 再次查看文件信息filetest_arm处理前not stripped:尚未剥离普通符号表等信息。处理后stripped:已剥离这些信息,文件通常会变小。图中处理前后仍是32 位 ARM ELF 可执行文件,动态链接方式也没有改变。去掉的是运行时不需要的辅助信息,通常不影响程序正常运行。6.4 arm-buildroot-linux-gnueabihf-objdump 工具作用:反汇编,把程序中的机器码显示成汇编指令,方便查看程序实际执行的指令。arm-buildroot-linux-gnueabihf-objdump-dtest_arm-d表示反汇编,查看test_arm中的机器码所对应的汇编指令。6.5 arm-buildroot-linux-gnueabihf-objcopy 工具作用:复制、提取或转换目标文件中的内容,例如把 ELF 文件转换成 BIN 文件。arm-buildroot-linux-gnueabihf-objcopy-Obinary test_arm test_arm.bin-O binary指定输出为原始二进制格式,test_arm是输入文件,test_arm.bin是生成的文件。格式转换不会让这个 Linux 应用自动变成能独立运行的裸机程序。为什么转成 BIN 后,仍不能直接脱离 Linux 运行?因为objcopy只转换文件格式,不改变程序原来的依赖。当前的test_arm是 Linux 动态链接程序,依赖 Linux 的加载器、库和系统服务,转成 BIN 后这些需求仍然存在。转换有什么意义?BIN 方便交给按地址写入原始字节的烧录工具或加载程序使用。裸机开发中,程序会事先配好启动代码、链接地址和必要的硬件初始化,先生成 ELF 供调试,再转换成 BIN 供烧录或加载:按裸机要求编写的程序 → ELF(供链接、调试)→ BIN(供烧录、加载)因此,本次把 Linux 应用转成 BIN,主要是练习格式转换;它不会因此获得裸机运行能力。能否脱离操作系统,取决于程序怎么编写和构建,而不是文件后缀。