
#星光计划1.0# v54.04 鸿蒙内核源码分析(静态链接) 原创 精华
子曰:“回也其庶乎,屡空。赐不受命,而货殖焉,亿则屡中。” 《论语》:先进篇
百篇博客分析.本篇为: (静态链接篇) | 一个小项目看中间过程
加载运行相关篇为:
- v51.04 鸿蒙内核源码分析(ELF格式) | 应用程序入口并非main
- v53.03 鸿蒙内核源码分析(ELF解析) | 敢忘了她姐俩你就不是银
- v54.04 鸿蒙内核源码分析(静态链接) | 一个小项目看中间过程
- v55.04 鸿蒙内核源码分析(重定位) | 与国际接轨的对外发言人
- v56.05 鸿蒙内核源码分析(进程映像) | 程序是如何被加载运行的
下图是一个可执行文件编译,链接的过程.
本篇将通过一个完整的小工程来阐述ELF编译,链接过程,并分析.o和bin文件中各区,符号表之间的关系.从一个崭新的视角去看中间过程.
准备工作
先得有个小工程,麻雀虽小,但五脏俱全,标准的文件夹和Makefile结构,如下:
目录结构
看到 .c .h .o 就感觉特别的亲切 : ),项目很简单,但具有代表性,有全局变量/函数,extern
,多文件链接,和动态链接库的printf
,用cat命令看看三个文件内容。
cat .c .h
cat Makefile
Makefile
采用标准写法,关于makefile系列篇会在编译过程篇中详细说明,此处先看点简单的。
编译.链接.运行.看结果
结果很简单,没什么好说的.
开始分析
准备工作完成,开始了真正的分析. 因为命令输出内容太多,本篇做了精简,去除了干扰项.对这些命令还不行清楚的请翻看系列篇其他文章,此处不做介绍,阅读本篇需要一定的基础.
readelf 大S小s ./obj/main.o
解读
编译 main.c 后 main.o 告诉了链接器以下信息
- 有一个文件 叫 main.c
(Type=FILE)
- 文件中有个函数叫 main
(Type=FUNC)
,并且这是一个全局函数,(Bind = GLOBAL , Vis = DEFAULT
,全局的意思就是可以被外部文件所引用. - 剩下的
g_str
,printf
,func_int
,…,都是需要外部提供,并未在本文件中定义的符号(Ndx = UND , Type = NOTYPE)
,至于怎么顺藤摸瓜找到这些符号那我不管,.o文件是独立存在,它只是告诉你我用了哪些东西,但我也不知道在哪里. printf
和func_int
对它来说一视同仁,都是外部链接符号,没有特殊对待.
readelf 大S小s ./obj/part.o
解读
编译 part.c 后part.o告诉了链接器以下信息
-
有一个文件 叫 part.c
(Type=FILE)
-
文件中有两个函数叫
func_int
,func_str
(Type=FUNC)
,并且都是全局函数,(Bind = GLOBAL , Vis = DEFAULT
,全局的意思就是可以被外部文件所引用. -
文件中有两个对象叫
g_int
,g_str
(Type=OBJECT)
,并且都是全局对象,同样可以被外部使用. -
剩下的
printf
,_GLOBAL_OFFSET_TABLE_
,都是需要外部提供,并未在本文件中定义的符号(Ndx = UND , Type = NOTYPE)
-
另外 part.c的局部变量
tmp
并没有出现在符号表中.因为符号表相当于外交部,只有对外的内容. -
func_int
,func_str
在1区代码区.text
. -
g_int
在3区.data
数据区, 打开3区,发现了 0x33 就是源码中 int g_int = 51;的值 -
g_str
在6区,.data.rel.local
数据区,打开6区看结果并未发现 char *g_str = “hello world”;的身影,反而抛下一句话 NOTE: This section has relocations against it, but these have NOT been applied to this dump.翻译过来是 注意:此部分已针对它进行重定位,但是尚未将其应用于此转储. 最后在5区 '.rodata’找到了
hello world
至于重定向是如何实现的,在系列篇 重定向篇中已有详细说明,不再此展开说.
-
看完两个符号表总结下来就是三句话
- 我是谁,我在哪
- 我能提供什么给别人用
- 我需要别人提供什么给我用.
readelf 大S小s ./bin/weharmony
weharmony
是将 main.o
,part.o
和库文件链接完成后的可执行文件.
解读
链接后的可执行文件 weharmony
将告诉加载器以下信息
-
涉及文件有哪些
Type = FILE
-
涉及函数有哪些
Type = FUNC
func_str,func_int,_start,main -
涉及对象有哪些
Type = OBJECT
g_int,g_str,…它将这些数据统一归到了25区.
前往25区查看下数据,同样只发现了 int g_int = 51; 的数据.是不是和part.o一样也被放在了
.rodata
区,再反查 18区,果然发了 main.c和part.c的数据都放在了这里. -
另外还有注意
printf
的变化,从Type = NOTYPE
变成了Type = FUNC
,告诉了后续的动态链接这是个函数但是内容依然是
Ndx=UND
,weharmony也提供不了,内容需要运行时环境提供.并在需要动态链接表中也已经注明了内容清单,运行环境必须提供以下内容才能真正跑起来weharmony.本例在windows环境中一般是跑不起来的.除非提供对应的运行时环境.
百篇博客分析.深挖内核地基
- 给鸿蒙内核源码加注释过程中,整理出以下文章。内容立足源码,常以生活场景打比方尽可能多的将内核知识点置入某种场景,具有画面感,容易理解记忆。说别人能听得懂的话很重要! 百篇博客绝不是百度教条式的在说一堆诘屈聱牙的概念,那没什么意思。更希望让内核变得栩栩如生,倍感亲切.确实有难度,自不量力,但已经出发,回头已是不可能的了。 😛
- 与代码有bug需不断debug一样,文章和注解内容会存在不少错漏之处,请多包涵,但会反复修正,持续更新,v**.xx 代表文章序号和修改的次数,精雕细琢,言简意赅,力求打造精品内容。
按功能模块:
- 前因后果 >> 总目录 | 调度故事 | 内存主奴 | 源码注释 | 源码结构 | 静态站点 |
- 基础工具 >> 双向链表 | 位图管理 | 用栈方式 | 定时器 | 原子操作 | 时间管理 |
- 加载运行 >> ELF格式 | ELF解析 | 静态链接 | 重定位 | 进程映像 |
- 进程管理 >> 进程管理 | 进程概念 | Fork | 特殊进程 | 进程回收 | 信号生产 | 信号消费 | Shell编辑 | Shell解析 |
- 编译构建 >> 编译环境 | 编译过程 | 环境脚本 | 构建工具 | gn应用 | 忍者ninja |
- 进程通讯 >> 自旋锁 | 互斥锁 | 进程通讯 | 信号量 | 事件控制 | 消息队列 |
- 内存管理 >> 内存分配 | 内存管理 | 内存汇编 | 内存映射 | 内存规则 | 物理内存 |
- 任务管理 >> 时钟任务 | 任务调度 | 任务管理 | 调度队列 | 调度机制 | 线程概念 | 并发并行 | CPU | 系统调用 | 任务切换 |
- 文件系统 >> 文件概念 | 文件系统 | 索引节点 | 挂载目录 | 根文件系统 | 字符设备 | VFS | 文件句柄 | 管道文件 |
- 硬件架构 >> 汇编基础 | 汇编传参 | 工作模式 | 寄存器 | 异常接管 | 汇编汇总 | 中断切换 | 中断概念 | 中断管理 |
百万汉字注解.精读内核源码
四大码仓中文注解 . 定期同步官方代码
鸿蒙研究站( weharmonyos ) | 每天死磕一点点,原创不易,欢迎转载,请注明出处。若能支持点赞则更佳,感谢每一份支持。
【本文正在参与51CTO HarmonyOS技术社区创作者激励-星光计划1.0】
