固件即固化到计算机非易失存储器中的内容。
固化:在计算机领域指烧录,编程等一系列能将二进制数据存储到存储体内的过程;
计算机:既指通用的个人电脑也指单片机,soc等其他可编程芯片;
非易失存储器:指数据不容易被更改,丢失的存储体,常见的比如ROM FLASH EEPROM等;
内容:指仅能被计算机识别和存储的二进制数据。
所有计算机的源代码编译之后都会只生成3种二进制数据,分别是 .text, .data 和 .bss,这三部分数据分别对应代码中的代码段(包含代码经过汇编器转化为的机器指令码和常量数据),有初始值的变量段 和 无初始值的变量段。链接器将所有源文件的上述3个段内的数据合并 并 分配在真实存储体上的存储布局。其中.data段、.bss段在RAM的存储位置和.data段、.bss段的长度这些信息也会被链接器生成并已文件的形式输出,而这个文件就是 .elf、.hex 和 .bin文件。这3个文件只在数据丰富度和数据形式上有差异,核心部分数据是完全一致的。初始值不为0的全局和静态变量放入data段,无初始值和初始值为0的放入bss段。data段在ROM中的地址叫加载地址(LMA),c环境初始化时拷贝到RAM中的地址叫虚拟地址(VMA)
Hex文件是以ASCII文本形式保存编译后的二进制文件信息,Hex文件使用ASCII文本的形式保存Bin文件的内容和Bin文件的一些配置信息。HEX文件会携带各段的地址信息,各个段由04开头,后面最多跟随00开头的64KB的数据,这些数据就是bin中数据。HEX文件每行以:开始, \r\n结尾,每行的第 9 个字符决定此行数据的类型,常见的0表示数据,1表示文件结束,4表示一个段的开始,5表示复位入口地址;HEX文件会存在非对齐的情况,需要根据ROM的默认逻辑值是0/1去填充00或FF,(ARM的fls擦除后的默认逻辑值是1,所以填充FF;而tc397需要填充00),hex文件转bin文件就是将 0 类型的数据由2个字符转一个16进制数,bin文件没有地址信息,只有一个起始地址和整个bin的长度(这两个值也不是在bin中,而是由人为获取的),使用bin格式烧录时需指定此二值。 ROM地址不连续时只能使用hex;ROM连续,但HEX中的各段未占满时,在hex转bin时需要填充大量的00/FF,这样出来的bin就会比hex大许多。(比如HEX中有80000000和90000000两个段,但80000000段只使用了1k,那么hex转bin时从80000400到90000000就都需要填充;而HEX则即指定了段的开始地址也指定了段的长度)
Bin文件是MCU固件烧写的最终形式,也就是说MCU的ROM中烧写的内容完全就是Bin文件的内容。Bin文件作为固化固件的最终形式,是使用串口下载或远程升级时的指定格式。
const char str[] = "123"; //.const
const char *const str = "123"; //.const
char str[] = "123"; //.data + .const
char str[20] = "123"; //.data + .const
const char *str = 123; //.data + .const
Linux 的启动流程:
理解:x86架构的cpu采用冯诺依曼结构,需要把代码拷贝到内存中去执行,电脑开机伊始 pc 寄存器会由硬件设置为0xFFFF0。这个区域存放的是BIOS的代码,因此会先执行BIOSROM中的代码,代码中会有从一个固定地址(即第一个扇区)拷贝512B数据到内存地址0x7C00,并将 pc 寄存器指向这里的操作。而linus个人实现了bootsect.S文件,且通过汇编器AS86,链接器LD86生成一个可执行的镜像文件,并将其烧录在了第一扇区,这样当pc指向0x7c00后就可以执行bootsect.S中的代码。同时linus又在文件bootsect.S中实现了将文件bootsect.S从0x7c00处搬运到0x90000,将文件setup.s搬运到0x90200,将文件system模块搬运到0x10000处 这些操作,并最终使Linux操作系统运行起来。
x86cpu的地址总线全挂在RAM上,对硬盘中文件的读写不使用地址总线寻址,而是用IO总线将硬盘中的数据放入RAM,再由cpu对RAM寻址,实现对硬盘数据的访问;而mcu通常将RAM和ROM都挂在地址总线上,实现统一寻址。统一寻址的总容量必然不大于2^32。