嵌入式八股C语言-文件,可执行文件的加载与运行篇
嵌入式八股C语言—文件,可执行文件的加载与运行篇
C语言文件操作
- fopen
- fseek
- fread
- fwrite
- fclose
可执行文件
可执行文件的格式
在裸机环境下,得到的是HEX/BIN格式的文件,而使用操作系统时,操作的往往是ELF格式的文件
BIN/HEX文件是纯指令文件,没有其他杂七杂八的辅助信息,BIN文件最纯粹,而HEX文件会有一些附加的信息比如校验什么的;而ELF文件除了基本的代码段、数据段,还有文件头、符号表、program header table等用来辅助程序运行的信息
裸机环境下程序的运行
在ARM架构下 bin文件的头部的第一个存放的是SP指针的值 第二个存放的是RestHandler的地址 这样的话一上电SP指针和PC指针得到了相关的值就知道怎么运行了,同时在进入main函数之前会有一个__main函数,__main函数解析了bin文件中关于ZI段,数据段等信息,并对相应的SRAM内存做了操作,比如分配堆/栈,清空ZI段,加载数据段等等
ELF的加载与运行
ELF通过加载器加载到内存当中
.text段:代码段
.bss段: 未初始化的全局变量(实际上此时只记录了符号 并没有分配内存,只有使用的时候才会加载)
.data段: 初始化的全局变量
.rodata段: 字符串/const修饰的常量
.elf headler:记录了一些关键信息不可缺少
可执行文件加载的过程
如何把一个可执行文件转换为进程呢
静态链接
静态链接就是在程序链接的过程中 就把引用的函数和变量编入可执行文件里面了 这样做的话会大大增加可执行文件的体积,并且假设多个文件都使用了printf 每个人一个副本的话也 浪费内存 ,关键是C语言 是以文件为基本单位的 ,所以实际上多的不止printf而是整个的xx.c文件
- ar命令可以用来生成静态库
- gcc -L -l用来指定链接的库
动态链接
动态链接就是为了解决静态链接的缺点而存在的 同样的动态链接有一个动态链接器。
动态链接器通过解析ELF,做这样几件事
对动态链接库进行 重定位 :调整库内代码和数据的地址以适应实际加载地址的过程
对用到动态库的符号重定位( 更新GOT表 ):(也不知道动态库被加载到哪里了 所以动态库加载完毕后,需要重新找然后告诉程序更新了)
然后再把控制权交给程序本身
与地址无关的代码与GOT表
你不能每个进程都用printf就重新加载一遍动态链接库到对应进程,这不白操作了吗 我们希望的是虽然多个进程都是用了printf 但实际上printf的代码执被加载了一次,这个事情需要动态链接库和应用程序双方的努力。
动态链接库:生成与地址无关的代码(比如偏移量靠绝对的)
应用程序: GOT表 把使用动态链接库的符号都取出来,到时候动态库加载了就实时更新这个表
延迟绑定
没有必要一次性把所有动态库都加载到内存,用到谁就加载谁
模块的加载流程
- 初始化 init_module–放在特殊的section段
- 拷贝到内核 copy_from_user
- 地址空间分配
- 符号解析
- 重定位
- 执行