首页 文章 精选 留言 我的

精选列表

搜索[HarmonyOS SDK],共10000篇文章
优秀的个人博客,低调大师

鸿蒙内核源码分析(静态站点篇) | 五一哪也没去就干了这事 | 百篇博客分析HarmonyOS源码 | v52.01

OpenHarmony开发者文档 国内访问 : https://openharmony.21cloudbox.com/ 国外访问 : https://openharmony.github.io/ 先看图: 在给鸿蒙内核加注和写博客期间需要不断的查找资料,觉得官方目前资料展示方式并不能满足自己的需求,浪费了很多宝贵的时间,所以在想能不能将官方文档整个静态站点出来即方便别人更方便自己,这是一劳永逸,利己利他的事干嘛不做的,刚好五一有成块的时间,本来也想出去走走,结果却哪都没去,期间遇到不少问题,但基本都解决了,有段时间没更新博客了但换来未来的一片爽朗之声, hin 值得! 这里必须要感谢下这套主体的作者 Mr.hope ,人非常的nice, 晚上12点我们还在一起解决问题.再次感谢!!! 主题地址:vuepress-theme-hope 有兴趣的可以去了解下,一个功能强大的 vuepress 主题. 静态站点将每月同步官方文档,静态站点仓库已经开放,仓库地址 欢迎拿去部署. 侧边栏 这个不用说,都恨不得多开几个屏幕,技术人没它真不行,虽用谁知道,侧边栏是按官方的目录结构来的,但目前不是最优方案,会随时调整到最佳结构. 主题色 多种主题色,可以根据您的选择自动切换模式,搞技术的注意保护好视力,个人偏向白色. 搜索极为便利,国内外双站点 这个是很重要的功能,无搜索不技术,说到这个强烈建议不要用某度,因之前从未写过博客不清楚搜索结果是怎么效果法,现在有对比,去搜下自己的文章 ..., 各搜索引擎差别真的很大,谷歌就不用去说了,有条件的推荐要用,搜狗,360都比它好, 它虽然全但更杂,会干扰你的注意力. 哎, 以后有机会要写篇文章痛批阿度,真是太耽误事了,心疼流失了这么多人宝贵的时间. 中英文切换 这个估计国内的各位都不会去看,希望能有更多友人能了解鸿蒙.搞技术的都有操作系统情怀,个人坚信鸿蒙必定成功,也必然成功,它的成功意义非凡,或者能明白的人不多,自己一定是那个摇旗呐喊者. 带私货 这是私货,是自己一直想做也正在做的事,有些事情一旦开始,就真的停不下来了.不知道你有没有这样的感受. 百篇博客.往期回顾 在加注过程中,整理出以下文章.内容立足源码,常以生活场景打比方尽可能多的将内核知识点置入某种场景,具有画面感,容易理解记忆. 说别人能听得懂的话很重要! 百篇博客绝不是百度教条式的在说一堆诘屈聱牙的概念,那没什么意思.更希望让内核变得栩栩如生,倍感亲切.确实有难度,自不量力,但已经出发,回头已是不可能的了.:P 与写代码有bug需不断debug一样,文章和注解内容会将错漏之处反复修正,持续更新,.xx代表修改的次数,精雕细琢,言简意赅,力求打造精品内容. v51.xx 鸿蒙内核源码分析(ELF格式篇) | 应用程序入口并不是main | 51 .c .h .o v50.xx 鸿蒙内核源码分析(编译环境篇) | 编译鸿蒙看这篇或许真的够了 | 51 .c .h .o v49.xx 鸿蒙内核源码分析(信号消费篇) | 谁让CPU连续四次换栈运行 | 51 .c .h .o v48.xx 鸿蒙内核源码分析(信号生产篇) | 年过半百,依然活力十足 | 51 .c .h .o v47.xx 鸿蒙内核源码分析(进程回收篇) | 临终前如何向老祖宗托孤 | 51 .c .h .o v46.xx 鸿蒙内核源码分析(特殊进程篇) | 龙生龙凤生凤老鼠生儿会打洞 | 51 .c .h .o v45.xx 鸿蒙内核源码分析(Fork篇) | 一次调用,两次返回 | 51 .c .h .o v44.xx 鸿蒙内核源码分析(中断管理篇) | 江湖从此不再怕中断 | 51 .c .h .o v43.xx 鸿蒙内核源码分析(中断概念篇) | 海公公的日常工作 | 51 .c .h .o v42.xx 鸿蒙内核源码分析(中断切换篇) | 系统因中断活力四射 | 51 .c .h .o v41.xx 鸿蒙内核源码分析(任务切换篇) | 看汇编如何切换任务 | 51 .c .h .o v40.xx 鸿蒙内核源码分析(汇编汇总篇) | 汇编可爱如邻家女孩 | 51 .c .h .o v39.xx 鸿蒙内核源码分析(异常接管篇) | 社会很单纯,复杂的是人 | 51 .c .h .o v38.xx 鸿蒙内核源码分析(寄存器篇) | 小强乃宇宙最忙存储器 | 51 .c .h .o v37.xx 鸿蒙内核源码分析(系统调用篇) | 开发者永远的口头禅 | 51 .c .h .o v36.xx 鸿蒙内核源码分析(工作模式篇) | CPU是韦小宝,七个老婆 | 51 .c .h .o v35.xx 鸿蒙内核源码分析(时间管理篇) | 谁是内核基本时间单位 | 51 .c .h .o v34.xx 鸿蒙内核源码分析(原子操作篇) | 谁在为原子操作保驾护航 | 51 .c .h .o v33.xx 鸿蒙内核源码分析(消息队列篇) | 进程间如何异步传递大数据 | 51 .c .h .o v32.xx 鸿蒙内核源码分析(CPU篇) | 整个内核就是一个死循环 | 51 .c .h .o v31.xx 鸿蒙内核源码分析(定时器篇) | 哪个任务的优先级最高 | 51 .c .h .o v30.xx 鸿蒙内核源码分析(事件控制篇) | 任务间多对多的同步方案 | 51 .c .h .o v29.xx 鸿蒙内核源码分析(信号量篇) | 谁在负责解决任务的同步 | 51 .c .h .o v28.xx 鸿蒙内核源码分析(进程通讯篇) | 九种进程间通讯方式速揽 | 51 .c .h .o v27.xx 鸿蒙内核源码分析(互斥锁篇) | 比自旋锁丰满的互斥锁 | 51 .c .h .o v26.xx 鸿蒙内核源码分析(自旋锁篇) | 自旋锁当立贞节牌坊 | 51 .c .h .o v25.xx 鸿蒙内核源码分析(并发并行篇) | 听过无数遍的两个概念 | 51 .c .h .o v24.xx 鸿蒙内核源码分析(进程概念篇) | 进程在管理哪些资源 | 51 .c .h .o v23.xx 鸿蒙内核源码分析(汇编传参篇) | 如何传递复杂的参数 | 51 .c .h .o v22.xx 鸿蒙内核源码分析(汇编基础篇) | CPU在哪里打卡上班 | 51 .c .h .o v21.xx 鸿蒙内核源码分析(线程概念篇) | 是谁在不断的折腾CPU | 51 .c .h .o v20.xx 鸿蒙内核源码分析(用栈方式篇) | 程序运行场地由谁提供 | 51 .c .h .o v19.xx 鸿蒙内核源码分析(位图管理篇) | 谁能一分钱分两半花 | 51 .c .h .o v18.xx 鸿蒙内核源码分析(源码结构篇) | 内核每个文件的含义 | 51 .c .h .o v17.xx 鸿蒙内核源码分析(物理内存篇) | 怎么管理物理内存 | 51 .c .h .o v16.xx 鸿蒙内核源码分析(内存规则篇) | 内存管理到底在管什么 | 51 .c .h .o v15.xx 鸿蒙内核源码分析(内存映射篇) | 虚拟内存虚在哪里 | 51 .c .h .o v14.xx 鸿蒙内核源码分析(内存汇编篇) | 谁是虚拟内存实现的基础 | 51 .c .h .o v13.xx 鸿蒙内核源码分析(源码注释篇) | 鸿蒙必定成功,也必然成功 | 51 .c .h .o v12.xx 鸿蒙内核源码分析(内存管理篇) | 虚拟内存全景图是怎样的 | 51 .c .h .o v11.xx 鸿蒙内核源码分析(内存分配篇) | 内存有哪些分配方式 | 51 .c .h .o v10.xx 鸿蒙内核源码分析(内存主奴篇) | 皇上和奴才如何相处 | 51 .c .h .o v09.xx 鸿蒙内核源码分析(调度故事篇) | 用故事说内核调度过程 | 51 .c .h .o v08.xx 鸿蒙内核源码分析(总目录) | 百万汉字注解 百篇博客分析 | 51 .c .h .o v07.xx 鸿蒙内核源码分析(调度机制篇) | 任务是如何被调度执行的 | 51 .c .h .o v06.xx 鸿蒙内核源码分析(调度队列篇) | 内核有多少个调度队列 | 51 .c .h .o v05.xx 鸿蒙内核源码分析(任务管理篇) | 任务池是如何管理的 | 51 .c .h .o v04.xx 鸿蒙内核源码分析(任务调度篇) | 任务是内核调度的单元 | 51 .c .h .o v03.xx 鸿蒙内核源码分析(时钟任务篇) | 触发调度谁的贡献最大 | 51 .c .h .o v02.xx 鸿蒙内核源码分析(进程管理篇) | 谁在管理内核资源 | 51 .c .h .o v01.xx 鸿蒙内核源码分析(双向链表篇) | 谁是内核最重要结构体 | 51 .c .h .o 关于 51 .c .h .o 看系列篇文章会常看到 51 .c .h .o,希望这对大家阅读不会造成影响. 分别对应以下四个站点的首个字符,感谢这些站点一直以来对系列篇的支持和推荐,尤其是 oschina gitee ,很喜欢它的界面风格,简洁大方,让人感觉到开源的伟大! 51cto csdn harmony oschina 而巧合的是.c .h .o是C语言的头/源/目标文件,这就很有意思了,冥冥之中似有天数,将这四个宝贝以这种方式融合在一起. 51 .c .h .o , 我要CHO ,嗯嗯,hin 顺口 : ) 百万汉字注解.百篇博客分析 百万汉字注解 >> 精读鸿蒙源码,中文注解分析, 深挖地基工程,大脑永久记忆,四大码仓每日同步更新< gitee | github | csdn | coding > 百篇博客分析 >> 故事说内核,问答式导读,生活式比喻,表格化说明,图形化展示,主流站点定期更新中< 51cto | csdn | harmony | osc > 关注不迷路.代码即人生 热爱是所有的理由和答案 - turing 原创不易,欢迎转载,但麻烦请注明出处.

优秀的个人博客,低调大师

鸿蒙内核源码分析(ELF格式篇) | 用户程序入口并不是main | 百篇博客分析HarmonyOS源码 | v51.04

百万汉字注解 >> 精读鸿蒙源码,中文注解分析, 深挖地基工程,大脑永久记忆,四大码仓每日同步更新< gitee | github | csdn | coding > 百篇博客分析 >> 故事说内核,问答式导读,生活式比喻,表格化说明,图形化展示,主流站点定期更新中< osc | 51cto | csdn | harmony > 阅读之前的说明 先说明,本篇很长,也很枯燥,若不是绝对的技术偏执狂是看不下去的.将通过一段简单代码去跟踪编译成ELF格式后的内容.看看ELF究竟长了怎样的一副花花肠子,用readelf命令去窥视ELF的全貌,最后用objdump命令反汇编ELF.找到了大家熟悉main函数. 开始之前先说结论: ELF有两个重要概念 Segment(段) 和 Section(区),段比区大,是包含关系,一个段可由多区组成,一个区可被多段所共有. ELF 分四块,其中三块是描述信息(也叫头信息),另一块是内容,放的是所有区的内容. 第一块ELF头定义全局性信息 第二块Segment(段)头,内容描述段的名字,开始位置,类型,偏移,大小及每段由哪些区组成. 第三块内容区,放.text,.data,.bss所有区的内容,为了表述严谨,系列篇将统一说代码区,数据区,不再说代码段. 第四块Section(区)头,内容描述区的名字,开始位置,类型,偏移,大小等信息 鸿蒙对EFL的定义在 kernel\extended\dynload\include\los_ld_elf_pri.h文件中 示例代码 在windows目录E:\harmony\docker\test4harmony下创建 main.c文件,如下: #include <stdio.h> void say_hello(char *who) { printf("hello, %s!\n", who); } char *my_name = "harmony os"; int main() { say_hello(my_name); return 0; } 因在 v50.xx (编译环境篇) | 编译鸿蒙看这篇或许真的够了 < csdn | 51cto | osc > 篇中已做好了环境映射,所以文件会同时出现在docker中.编译生成ELF->运行->readelf -h查看app头部信息. root@5e3abe332c5a:/home/docker/test4harmony# ls main.c root@5e3abe332c5a:/home/docker/test4harmony# gcc -o app main.c root@5e3abe332c5a:/home/docker/test4harmony# ls app main.c root@5e3abe332c5a:/home/docker/test4harmony# ./app hello, harmony os! root@5e3abe332c5a:/home/docker/test4harmony# readelf -h app ELF Header: Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 Class: ELF64 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: DYN (Shared object file) Machine: Advanced Micro Devices X86-64 Version: 0x1 Entry point address: 0x1060 Start of program headers: 64 (bytes into file) Start of section headers: 14784 (bytes into file) Flags: 0x0 Size of this header: 64 (bytes) Size of program headers: 56 (bytes) Number of program headers: 13 Size of section headers: 64 (bytes) Number of section headers: 31 Section header string table index: 30 这里留意这几个内容,下面会说明,先记住. Entry point address: 0x1060 //代码区 .text 起始位置,即程序运行开始位置 Number of program headers: 13 //段数量 Number of section headers: 31 //区数量 Section header string table index: 30 //字符串数组索引,该区记录所有区名称 ELF历史 ELF的英文全称是The Executable and Linking Format,最初是由UNIX系统实验室开发、发布的ABI(Application Binary Interface)接口的一部分,是鸿蒙的主要可执行文件格式。 ELF整体布局 ELF格式可以表达四种类型的二进制对象文件(object files): 可重定位文件(relocatable file,就是大家平常见到的.o文件)包含基础代码和数据,但它的代码及数据都没有指定绝对地址,因此它适合于与其他目标文件链接来创建可执行文件或者共享目标文件。 可执行文件(executable file, 例上述示例代码生成的app文件)包含代码和数据,是可以直接运行的程序。其代码和数据都有固定的地址 (或相对于基地址的偏移 ),系统可根据这些地址信息把程序加载到内存执行。 共享库文件(shared object file,就是.so文件,用来做动态链接)也称动态库文件,包含了代码和数据,这些数据是在链接时被链接器(ld)和运行时动态链接器(ld.so.l、libc.so.l、ld-linux.so.l)使用的。 核心转储文件(core dump file,就是core dump文件) 可重定位文件用在编译和链接阶段;可执行文件用在程序运行阶段;共享库则同时用在编译链接和运行阶段。在不同阶段,我们可以用不同视角来理解ELF文件,整体布局如下图所示: 从上图可见,ELF格式文件整体可分为四大部分: ELF Header: 在文件的开始,描述整个文件的组织。即readelf -h app看到的内容 Program Header Table: 告诉系统如何创建进程映像。用来构造进程映像的目标文件必须具有程序头部表,可重定位文件可以不需要这个表。表描述段(Segment)信息的数组,每个元素对应一个段 , 即readelf -l app看到的前半部分内容. Segments and Sections: 段(Segment)由若干区(Section)组成;段在运行时被加载到进程地址空间中,包含在可执行文件中;区是段的组成单元,包含在可执行文件和可重定位文件中 即readelf -l app后半部分内容,readelf -x ** app可查看区具体内容.注意: Segments 是从运行的角度来描述 ELF 文件,Sections 是从链接的角度来描述 ELF 文件。也就是说,在链接阶段,我们可以忽略 program header table 来处理此文件,在运行阶段可以忽略 section header table 来处理此程序(所以很多加固手段删除了section header table)。 Section Header Table:描述区(Section)信息的数组,每个元素对应一个区,通常包含在可重定位文件中,可执行文件中为可选(通常包含) 即readelf -S app看到的内容 从图中可以看出 Segment:Section(M:N)是多对多的包含关系.Segment是由多个Section组成,Section也能属于多个段. ELF头信息 ELF头部信息对应鸿蒙源码结构体为 LDElf32Ehdr, 各字段含义已一一注解,很容易理解. //kernel\extended\dynload\include\los_ld_elf_pri.h /* Elf header */ #define LD_EI_NIDENT 16 typedef struct { UINT8 elfIdent[LD_EI_NIDENT]; /* Magic number and other info *///含前16个字节,又可细分成class、data、version等字段,具体含义不用太关心,只需知道前4个字节点包含`ELF`关键字,这样可以判断当前文件是否是ELF格式 UINT16 elfType; /* Object file type *///表示具体ELF类型,可重定位文件/可执行文件/共享库文件 UINT16 elfMachine; /* Architecture *///表示cpu架构 UINT32 elfVersion; /* Object file version *///表示文件版本号 UINT32 elfEntry; /* Entry point virtual address *///对应`Entry point address`,程序入口函数地址,通过进程虚拟地址空间地址表达 UINT32 elfPhoff; /* Program header table file offset *///对应`Start of program headers`,表示program header table在文件内的偏移位置 UINT32 elfShoff; /* Section header table file offset *///对应`Start of section headers`,表示section header table在文件内的偏移位置 UINT32 elfFlags; /* Processor-specific flags *///表示与CPU处理器架构相关的信息 UINT16 elfHeadSize; /* ELF header size in bytes *///对应`Size of this header`,表示本ELF header自身的长度 UINT16 elfPhEntSize; /* Program header table entry size *///对应`Size of program headers`,表示program header table中每个元素的大小 UINT16 elfPhNum; /* Program header table entry count *///对应`Number of program headers`,表示program header table中元素个数 UINT16 elfShEntSize; /* Section header table entry size *///对应`Size of section headers`,表示section header table中每个元素的大小 UINT16 elfShNum; /* Section header table entry count *///对应`Number of section headers`,表示section header table中元素的个数 UINT16 elfShStrIndex; /* Section header string table index *///对应`Section header string table index`,表示描述各section字符名称的string table在section header table中的下标 } LDElf32Ehdr; 结构体对应readelf -h app命令内容来理解,就不再贴出来了. 段(Segment)头信息 段(Segment)信息对应鸿蒙源码结构体为 LDElf32Phdr, //kernel\extended\dynload\include\los_ld_elf_pri.h /* Program Header */ typedef struct { UINT32 type; /* Segment type */ UINT32 offset; /* Segment file offset */ UINT32 vAddr; /* Segment virtual address */ UINT32 phyAddr; /* Segment physical address */ UINT32 fileSize; /* Segment size in file */ UINT32 memSize; /* Segment size in memory */ UINT32 flags; /* Segment flags */ UINT32 align; /* Segment alignment */ } LDElf32Phdr; 用readelf -l查看app段头部表内容 root@5e3abe332c5a:/home/docker/test4harmony# readelf -l app Elf file type is DYN (Shared object file) Entry point 0x1060 There are 13 program headers, starting at offset 64 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flags Align PHDR 0x0000000000000040 0x0000000000000040 0x0000000000000040 0x00000000000002d8 0x00000000000002d8 R 0x8 ......... 解读 先看命令返回的前半部分: Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flags Align PHDR 0x0000000000000040 0x0000000000000040 0x0000000000000040 0x00000000000002d8 0x00000000000002d8 R 0x8 INTERP 0x0000000000000318 0x0000000000000318 0x0000000000000318 0x000000000000001c 0x000000000000001c R 0x1 [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2] LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000 0x0000000000000618 0x0000000000000618 R 0x1000 LOAD 0x0000000000001000 0x0000000000001000 0x0000000000001000 0x0000000000000225 0x0000000000000225 R E 0x1000 LOAD 0x0000000000002000 0x0000000000002000 0x0000000000002000 0x0000000000000190 0x0000000000000190 R 0x1000 LOAD 0x0000000000002db8 0x0000000000003db8 0x0000000000003db8 0x0000000000000260 0x0000000000000268 RW 0x1000 DYNAMIC 0x0000000000002dc8 0x0000000000003dc8 0x0000000000003dc8 0x00000000000001f0 0x00000000000001f0 RW 0x8 NOTE 0x0000000000000338 0x0000000000000338 0x0000000000000338 0x0000000000000020 0x0000000000000020 R 0x8 NOTE 0x0000000000000358 0x0000000000000358 0x0000000000000358 0x0000000000000044 0x0000000000000044 R 0x4 GNU_PROPERTY 0x0000000000000338 0x0000000000000338 0x0000000000000338 0x0000000000000020 0x0000000000000020 R 0x8 GNU_EH_FRAME 0x000000000000201c 0x000000000000201c 0x000000000000201c 0x000000000000004c 0x000000000000004c R 0x4 GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000 0x0000000000000000 0x0000000000000000 RW 0x10 GNU_RELRO 0x0000000000002db8 0x0000000000003db8 0x0000000000003db8 0x0000000000000248 0x0000000000000248 R 0x1 数一下一共13个段,其实在ELF头信息也告诉了我们共13个段 Number of program headers: 13 //段数量 仔细看下这些段的开始地址和大小,发现有些段是重叠的.那是因为一个区可以被多个段所拥有.例如:0x2db8 对应的 .init_array区就被第四LOAD 和 GNU_RELRO两段所共有. PHDR,此类型header元素描述了program header table自身的信息。从这里的内容看出,示例程序的program header table在文件中的偏移(Offset)为0x40,即64号字节处;该段映射到进程空间的虚拟地址(VirtAddr)为0x40;PhysAddr暂时不用,其保持和VirtAddr一致;该段占用的文件大小FileSiz为0x2d8;运行时占用进程空间内存大小MemSiz也为0x2d8;Flags标记表示该段的读写权限,这里R表示只读,Align对齐为8,表明本段按8字节对齐。 INTERP,此类型header元素描述了一个特殊内存段,该段内存记录了动态加载解析器的访问路径字符串。示例程序中,该段内存位于文件偏移0x318处,即紧跟program header table;映射的进程虚拟地址空间地址为0x318;文件长度和内存映射长度均为0x1c,即28个字符,具体内容为/lib64/ld-linux-x86-64.so.2;段属性为只读,并按字节对齐; LOAD,此类型header元素描述了可加载到进程空间的代码区或数据区: 第二段包含了代码区,文件内偏移为0x1000,映射到进程地址0x001000处,代码区的长度为0x618个字节,属性为只读可执行(RE),段地址按0x1000(4K)边界对齐; 第四段包含了数据区,文件内偏移为0x1000,映射到进程地址为0x1000处(按2M对齐移动),文件大小为0x230,内存大小为0x238(因为其内部包含了8字节的bss区,即未初始化数据区,该区内容不占文件空间,但在运行时需要为其分配空间并清零),属性为读写(RW),段地址也按0x1000(4K)边界对齐。 DYNAMIC,此类型header元素描述了动态加载段,其内部通常包含了一个名为.dynamic的动态加载区;这也是一个数组,每个元素描述了与动态加载相关的各方面信息,将在系列篇(动态加载篇)中介绍。该段是从文件偏移0x2dc8处开始,长度为0x1f0,并映射到进程的0x3dc8;可见该段和上一个段LOAD4 0x2db8是有重叠的。 再看命令返回内容的后半部分-段区映射关系 Section to Segment mapping: Segment Sections... 00 01 .interp 02 .interp .note.gnu.property .note.gnu.build-id .note.ABI-tag .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt 03 .init .plt .plt.got .plt.sec .text .fini 04 .rodata .eh_frame_hdr .eh_frame 05 .init_array .fini_array .dynamic .got .data .bss 06 .dynamic 07 .note.gnu.property 08 .note.gnu.build-id .note.ABI-tag 09 .note.gnu.property 10 .eh_frame_hdr 11 12 .init_array .fini_array .dynamic .got Segment:Section(M:N)是多对多的包含关系.Segment是由多个Section组成,Section也能属于多个段.这个很重要,说第二遍了. INTERP段只包含了.interp区 LOAD2段包含.interp、.plt、.text等区,.text代码区位于这个段. LOAD4包含.dynamic、.data、.bss`等区, 数据区位于这个段. DYNAMIC段包含.dynamic区。 区表 区(section)头表信息对应鸿蒙源码结构体为 LDElf32Shdr, //kernel\extended\dynload\include\los_ld_elf_pri.h /* Section header */ typedef struct { UINT32 shName; /* Section name (string tbl index) *///表示每个区的名字 UINT32 shType; /* Section type *///表示每个区的功能 UINT32 shFlags; /* Section flags *///表示每个区的属性 UINT32 shAddr; /* Section virtual addr at execution *///表示每个区的进程映射地址 UINT32 shOffset; /* Section file offset *///表示文件内偏移 UINT32 shSize; /* Section size in bytes *///表示区的大小 UINT32 shLink; /* Link to another section *///Link和Info记录不同类型区的相关信息 UINT32 shInfo; /* Additional section information *///Link和Info记录不同类型区的相关信息 UINT32 shAddrAlign; /* Section alignment *///表示区的对齐单位 UINT32 shEntSize; /* Entry size if section holds table *///表示区中每个元素的大小(如果该区为一个数组的话,否则该值为0) } LDElf32Shdr; 示例程序共生成31个区.其实在头文件中也已经告诉我们了 Number of section headers: 31 //区数量 通过readelf -S命令看看示例程序中 section header table的内容,如下所示。 root@5e3abe332c5a:/home/docker/test4harmony# readelf -S app There are 31 section headers, starting at offset 0x39c0: Section Headers: [Nr] Name Type Address Offset Size EntSize Flags Link Info Align [ 0] NULL 0000000000000000 00000000 0000000000000000 0000000000000000 0 0 0 [ 1] .interp PROGBITS 0000000000000318 00000318 000000000000001c 0000000000000000 A 0 0 1 [ 2] .note.gnu.propert NOTE 0000000000000338 00000338 0000000000000020 0000000000000000 A 0 0 8 [ 3] .note.gnu.build-i NOTE 0000000000000358 00000358 0000000000000024 0000000000000000 A 0 0 4 [ 4] .note.ABI-tag NOTE 000000000000037c 0000037c 0000000000000020 0000000000000000 A 0 0 4 [ 5] .gnu.hash GNU_HASH 00000000000003a0 000003a0 0000000000000024 0000000000000000 A 6 0 8 [ 6] .dynsym DYNSYM 00000000000003c8 000003c8 00000000000000a8 0000000000000018 A 7 1 8 [ 7] .dynstr STRTAB 0000000000000470 00000470 0000000000000084 0000000000000000 A 0 0 1 [ 8] .gnu.version VERSYM 00000000000004f4 000004f4 000000000000000e 0000000000000002 A 6 0 2 [ 9] .gnu.version_r VERNEED 0000000000000508 00000508 0000000000000020 0000000000000000 A 7 1 8 [10] .rela.dyn RELA 0000000000000528 00000528 00000000000000d8 0000000000000018 A 6 0 8 [11] .rela.plt RELA 0000000000000600 00000600 0000000000000018 0000000000000018 AI 6 24 8 [12] .init PROGBITS 0000000000001000 00001000 000000000000001b 0000000000000000 AX 0 0 4 [13] .plt PROGBITS 0000000000001020 00001020 0000000000000020 0000000000000010 AX 0 0 16 [14] .plt.got PROGBITS 0000000000001040 00001040 0000000000000010 0000000000000010 AX 0 0 16 [15] .plt.sec PROGBITS 0000000000001050 00001050 0000000000000010 0000000000000010 AX 0 0 16 [16] .text PROGBITS 0000000000001060 00001060 00000000000001b5 0000000000000000 AX 0 0 16 [17] .fini PROGBITS 0000000000001218 00001218 000000000000000d 0000000000000000 AX 0 0 4 [18] .rodata PROGBITS 0000000000002000 00002000 000000000000001b 0000000000000000 A 0 0 4 [19] .eh_frame_hdr PROGBITS 000000000000201c 0000201c 000000000000004c 0000000000000000 A 0 0 4 [20] .eh_frame PROGBITS 0000000000002068 00002068 0000000000000128 0000000000000000 A 0 0 8 [21] .init_array INIT_ARRAY 0000000000003db8 00002db8 0000000000000008 0000000000000008 WA 0 0 8 [22] .fini_array FINI_ARRAY 0000000000003dc0 00002dc0 0000000000000008 0000000000000008 WA 0 0 8 [23] .dynamic DYNAMIC 0000000000003dc8 00002dc8 00000000000001f0 0000000000000010 WA 7 0 8 [24] .got PROGBITS 0000000000003fb8 00002fb8 0000000000000048 0000000000000008 WA 0 0 8 [25] .data PROGBITS 0000000000004000 00003000 0000000000000018 0000000000000000 WA 0 0 8 [26] .bss NOBITS 0000000000004018 00003018 0000000000000008 0000000000000000 WA 0 0 1 [27] .comment PROGBITS 0000000000000000 00003018 000000000000002a 0000000000000001 MS 0 0 1 [28] .symtab SYMTAB 0000000000000000 00003048 0000000000000648 0000000000000018 29 46 8 [29] .strtab STRTAB 0000000000000000 00003690 0000000000000216 0000000000000000 0 0 1 [30] .shstrtab STRTAB 0000000000000000 000038a6 000000000000011a 0000000000000000 0 0 1 Key to Flags: W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), C (compressed), x (unknown), o (OS specific), E (exclude), l (large), p (processor specific) String Table 从上述Section Header Table示例中,我们看到有一种类型为STRTAB的区(在Section Header Table中的下标为7,29,30)。此类区叫做String Table,其作用是集中记录字符串信息,其它区在需要使用字符串的时候,只需要记录字符串起始地址在该String Table表中的偏移即可,而无需包含整个字符串内容。 我们使用readelf -x读出下标30区的数据: root@5e3abe332c5a:/home/docker/test4harmony# readelf -x 30 app Hex dump of section '.shstrtab': 0x00000000 002e7379 6d746162 002e7374 72746162 ..symtab..strtab 0x00000010 002e7368 73747274 6162002e 696e7465 ..shstrtab..inte 0x00000020 7270002e 6e6f7465 2e676e75 2e70726f rp..note.gnu.pro 0x00000030 70657274 79002e6e 6f74652e 676e752e perty..note.gnu. 0x00000040 6275696c 642d6964 002e6e6f 74652e41 build-id..note.A 0x00000050 42492d74 6167002e 676e752e 68617368 BI-tag..gnu.hash 0x00000060 002e6479 6e73796d 002e6479 6e737472 ..dynsym..dynstr 0x00000070 002e676e 752e7665 7273696f 6e002e67 ..gnu.version..g 0x00000080 6e752e76 65727369 6f6e5f72 002e7265 nu.version_r..re 0x00000090 6c612e64 796e002e 72656c61 2e706c74 la.dyn..rela.plt 0x000000a0 002e696e 6974002e 706c742e 676f7400 ..init..plt.got. 0x000000b0 2e706c74 2e736563 002e7465 7874002e .plt.sec..text.. 0x000000c0 66696e69 002e726f 64617461 002e6568 fini..rodata..eh 0x000000d0 5f667261 6d655f68 6472002e 65685f66 _frame_hdr..eh_f 0x000000e0 72616d65 002e696e 69745f61 72726179 rame..init_array 0x000000f0 002e6669 6e695f61 72726179 002e6479 ..fini_array..dy 0x00000100 6e616d69 63002e64 61746100 2e627373 namic..data..bss 0x00000110 002e636f 6d6d656e 7400 ..comment. 可以发现,这里其实是一堆字符串,这些字符串对应的就是各个区的名字。因此section header table中每个元素的Name字段其实是这个string table的索引。再回头看看ELF header中的 elfShStrIndex, Section header string table index: 30 //字符串数组索引,该区记录所有区名称 它的值正好就是30,指向了当前的string table。 再来看下29区的内容,如下所示 root@5e3abe332c5a:/home/docker/test4harmony# readelf -x 29 app Hex dump of section '.strtab': 0x00000000 00637274 73747566 662e6300 64657265 .crtstuff.c.dere 0x00000010 67697374 65725f74 6d5f636c 6f6e6573 gister_tm_clones 0x00000020 005f5f64 6f5f676c 6f62616c 5f64746f .__do_global_dto 0x00000030 72735f61 75780063 6f6d706c 65746564 rs_aux.completed 0x00000040 2e383036 30005f5f 646f5f67 6c6f6261 .8060.__do_globa 0x00000050 6c5f6474 6f72735f 6175785f 66696e69 l_dtors_aux_fini 0x00000060 5f617272 61795f65 6e747279 00667261 _array_entry.fra 0x00000070 6d655f64 756d6d79 005f5f66 72616d65 me_dummy.__frame 0x00000080 5f64756d 6d795f69 6e69745f 61727261 _dummy_init_arra 0x00000090 795f656e 74727900 6d61696e 2e63005f y_entry.main.c._ 0x000000a0 5f465241 4d455f45 4e445f5f 005f5f69 _FRAME_END__.__i 0x000000b0 6e69745f 61727261 795f656e 64005f44 nit_array_end._D 0x000000c0 594e414d 4943005f 5f696e69 745f6172 YNAMIC.__init_ar 0x000000d0 7261795f 73746172 74005f5f 474e555f ray_start.__GNU_ 0x000000e0 45485f46 52414d45 5f484452 005f474c EH_FRAME_HDR._GL 0x000000f0 4f42414c 5f4f4646 5345545f 5441424c OBAL_OFFSET_TABL 0x00000100 455f005f 5f6c6962 635f6373 755f6669 E_.__libc_csu_fi 0x00000110 6e69006d 795f6e61 6d65005f 49544d5f ni.my_name._ITM_ 0x00000120 64657265 67697374 6572544d 436c6f6e deregisterTMClon 0x00000130 65546162 6c65005f 65646174 61007072 eTable._edata.pr 0x00000140 696e7466 4040474c 4942435f 322e322e intf@@GLIBC_2.2. 0x00000150 35005f5f 6c696263 5f737461 72745f6d 5.__libc_start_m 0x00000160 61696e40 40474c49 42435f32 2e322e35 ain@@GLIBC_2.2.5 0x00000170 005f5f64 6174615f 73746172 74005f5f .__data_start.__ 0x00000180 676d6f6e 5f737461 72745f5f 005f5f64 gmon_start__.__d 0x00000190 736f5f68 616e646c 65005f49 4f5f7374 so_handle._IO_st 0x000001a0 64696e5f 75736564 005f5f6c 6962635f din_used.__libc_ 0x000001b0 6373755f 696e6974 005f5f62 73735f73 csu_init.__bss_s 0x000001c0 74617274 006d6169 6e007361 795f6865 tart.main.say_he 0x000001d0 6c6c6f00 5f5f544d 435f454e 445f5f00 llo.__TMC_END__. 0x000001e0 5f49544d 5f726567 69737465 72544d43 _ITM_registerTMC 0x000001f0 6c6f6e65 5461626c 65005f5f 6378615f loneTable.__cxa_ 0x00000200 66696e61 6c697a65 4040474c 4942435f finalize@@GLIBC_ 0x00000210 322e322e 3500 2.2.5. 这里看到了main、say_hello字符串,这些是在示例中源码中定义的符号,由此29区是应用自身的String Table,记录了应用程序使用的字符串。这个表就是符号表的一部分. 通过readelf -s命令能拿到全部符号信息.如下 符号表 Symbol Table Section Header Table中,还有一类SYMTAB(DYNSYM)区,该区叫符号表。符号表中的每个元素对应一个符号,记录了每个符号对应的实际数值信息,通常用在重定位过程中或问题定位过程中,进程执行阶段并不加载符号表。符号表对应鸿蒙源码结构体为 LDElf32Sym. //kernel\extended\dynload\include\los_ld_elf_pri.h /* Symbol table */ typedef struct { UINT32 stName; /* Symbol table name (string tbl index) *///表示符号对应的源码字符串,为对应String Table中的索引 UINT32 stValue; /* Symbol table value *///表示符号对应的数值 UINT32 stSize; /* Symbol table size *///表示符号对应数值的空间占用大小 UINT8 stInfo; /* Symbol table type and binding *///表示符号的相关信息 如符号类型(变量符号、函数符号) UINT8 stOther; /* Symbol table visibility */ UINT16 stShndx; /* Section table index *///表示与该符号相关的区的索引,例如函数符号与对应的代码区相关 } LDElf32Sym; 用readelf -s读出示例程序中的符号表,如下所示 root@5e3abe332c5a:/home/docker/test4harmony# readelf -s app Symbol table '.dynsym' contains 7 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTab 2: 0000000000000000 0 FUNC GLOBAL DEFAULT UND printf@GLIBC_2.2.5 (2) 3: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (2) 4: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__ 5: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable 6: 0000000000000000 0 FUNC WEAK DEFAULT UND __cxa_finalize@GLIBC_2.2.5 (2) Symbol table '.symtab' contains 67 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000000318 0 SECTION LOCAL DEFAULT 1 2: 0000000000000338 0 SECTION LOCAL DEFAULT 2 3: 0000000000000358 0 SECTION LOCAL DEFAULT 3 4: 000000000000037c 0 SECTION LOCAL DEFAULT 4 5: 00000000000003a0 0 SECTION LOCAL DEFAULT 5 6: 00000000000003c8 0 SECTION LOCAL DEFAULT 6 7: 0000000000000470 0 SECTION LOCAL DEFAULT 7 8: 00000000000004f4 0 SECTION LOCAL DEFAULT 8 9: 0000000000000508 0 SECTION LOCAL DEFAULT 9 10: 0000000000000528 0 SECTION LOCAL DEFAULT 10 11: 0000000000000600 0 SECTION LOCAL DEFAULT 11 12: 0000000000001000 0 SECTION LOCAL DEFAULT 12 13: 0000000000001020 0 SECTION LOCAL DEFAULT 13 14: 0000000000001040 0 SECTION LOCAL DEFAULT 14 15: 0000000000001050 0 SECTION LOCAL DEFAULT 15 16: 0000000000001060 0 SECTION LOCAL DEFAULT 16 17: 0000000000001218 0 SECTION LOCAL DEFAULT 17 18: 0000000000002000 0 SECTION LOCAL DEFAULT 18 19: 000000000000201c 0 SECTION LOCAL DEFAULT 19 20: 0000000000002068 0 SECTION LOCAL DEFAULT 20 21: 0000000000003db8 0 SECTION LOCAL DEFAULT 21 22: 0000000000003dc0 0 SECTION LOCAL DEFAULT 22 23: 0000000000003dc8 0 SECTION LOCAL DEFAULT 23 24: 0000000000003fb8 0 SECTION LOCAL DEFAULT 24 25: 0000000000004000 0 SECTION LOCAL DEFAULT 25 26: 0000000000004018 0 SECTION LOCAL DEFAULT 26 27: 0000000000000000 0 SECTION LOCAL DEFAULT 27 28: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c 29: 0000000000001090 0 FUNC LOCAL DEFAULT 16 deregister_tm_clones 30: 00000000000010c0 0 FUNC LOCAL DEFAULT 16 register_tm_clones 31: 0000000000001100 0 FUNC LOCAL DEFAULT 16 __do_global_dtors_aux 32: 0000000000004018 1 OBJECT LOCAL DEFAULT 26 completed.8060 33: 0000000000003dc0 0 OBJECT LOCAL DEFAULT 22 __do_global_dtors_aux_fin 34: 0000000000001140 0 FUNC LOCAL DEFAULT 16 frame_dummy 35: 0000000000003db8 0 OBJECT LOCAL DEFAULT 21 __frame_dummy_init_array_ 36: 0000000000000000 0 FILE LOCAL DEFAULT ABS main.c 37: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c 38: 000000000000218c 0 OBJECT LOCAL DEFAULT 20 __FRAME_END__ 39: 0000000000000000 0 FILE LOCAL DEFAULT ABS 40: 0000000000003dc0 0 NOTYPE LOCAL DEFAULT 21 __init_array_end 41: 0000000000003dc8 0 OBJECT LOCAL DEFAULT 23 _DYNAMIC 42: 0000000000003db8 0 NOTYPE LOCAL DEFAULT 21 __init_array_start 43: 000000000000201c 0 NOTYPE LOCAL DEFAULT 19 __GNU_EH_FRAME_HDR 44: 0000000000003fb8 0 OBJECT LOCAL DEFAULT 24 _GLOBAL_OFFSET_TABLE_ 45: 0000000000001000 0 FUNC LOCAL DEFAULT 12 _init 46: 0000000000001210 5 FUNC GLOBAL DEFAULT 16 __libc_csu_fini 47: 0000000000004010 8 OBJECT GLOBAL DEFAULT 25 my_name 48: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTab 49: 0000000000004000 0 NOTYPE WEAK DEFAULT 25 data_start 50: 0000000000004018 0 NOTYPE GLOBAL DEFAULT 25 _edata 51: 0000000000001218 0 FUNC GLOBAL HIDDEN 17 _fini 52: 0000000000000000 0 FUNC GLOBAL DEFAULT UND printf@@GLIBC_2.2.5 53: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@@GLIBC_ 54: 0000000000004000 0 NOTYPE GLOBAL DEFAULT 25 __data_start 55: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__ 56: 0000000000004008 0 OBJECT GLOBAL HIDDEN 25 __dso_handle 57: 0000000000002000 4 OBJECT GLOBAL DEFAULT 18 _IO_stdin_used 58: 00000000000011a0 101 FUNC GLOBAL DEFAULT 16 __libc_csu_init 59: 0000000000004020 0 NOTYPE GLOBAL DEFAULT 26 _end 60: 0000000000001060 47 FUNC GLOBAL DEFAULT 16 _start 61: 0000000000004018 0 NOTYPE GLOBAL DEFAULT 26 __bss_start 62: 0000000000001174 30 FUNC GLOBAL DEFAULT 16 main 63: 0000000000001149 43 FUNC GLOBAL DEFAULT 16 say_hello 64: 0000000000004018 0 OBJECT GLOBAL HIDDEN 25 __TMC_END__ 65: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable 66: 0000000000000000 0 FUNC WEAK DEFAULT UND __cxa_finalize@@GLIBC_2.2 在最后位置找到了亲切的老朋友 main和say_hello 62: 0000000000001174 30 FUNC GLOBAL DEFAULT 16 main 63: 0000000000001149 43 FUNC GLOBAL DEFAULT 16 say_hello main函数符号对应的数值为0x1174,其类型为FUNC,大小为30字节,对应的代码区索引为16; say_hello函数符号对应数值为0x1149,其类型为FUNC,大小为43字节,对应的代码区索引同为16。 Section Header Table: [16] .text PROGBITS 0000000000001060 00001060 00000000000001b5 0000000000000000 AX 0 0 16 反汇编代码区 在理解了String Table和Symbol Table的作用后,通过objdump反汇编来理解一下.text代码区: root@5e3abe332c5a:/home/docker/test4harmony# objdump -j .text -l -C -S app 0000000000001149 <say_hello>: say_hello(): 1149: f3 0f 1e fa endbr64 114d: 55 push %rbp 114e: 48 89 e5 mov %rsp,%rbp 1151: 48 83 ec 10 sub $0x10,%rsp 1155: 48 89 7d f8 mov %rdi,-0x8(%rbp) 1159: 48 8b 45 f8 mov -0x8(%rbp),%rax 115d: 48 89 c6 mov %rax,%rsi 1160: 48 8d 3d 9d 0e 00 00 lea 0xe9d(%rip),%rdi # 2004 <_IO_stdin_used+0x4> 1167: b8 00 00 00 00 mov $0x0,%eax 116c: e8 df fe ff ff callq 1050 <printf@plt> 1171: 90 nop 1172: c9 leaveq 1173: c3 retq 0000000000001174 <main>: main(): 1174: f3 0f 1e fa endbr64 1178: 55 push %rbp 1179: 48 89 e5 mov %rsp,%rbp 117c: 48 8b 05 8d 2e 00 00 mov 0x2e8d(%rip),%rax # 4010 <my_name> 1183: 48 89 c7 mov %rax,%rdi 1186: e8 be ff ff ff callq 1149 <say_hello> 118b: b8 00 00 00 00 mov $0x0,%eax 1190: 5d pop %rbp 1191: c3 retq 1192: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1) 1199: 00 00 00 119c: 0f 1f 40 00 nopl 0x0(%rax) 0x1149 0x1174正是say_hello,main函数的入口地址.并看到了激动人心的指令 1186: e8 be ff ff ff callq 1149 <say_hello> 很佩服你还能看到这里,牛逼,牛逼! 看了这么久还记得开头的C代码的样子吗? 再看一遍 : ) #include <stdio.h> void say_hello(char *who) { printf("hello, %s!\n", who); } char *my_name = "harmony os"; int main() { say_hello(my_name); return 0; } root@5e3abe332c5a:/home/docker/test4harmony# ./app hello, harmony os! 但是!!! 晕,怎么还有but,西卡西...,上面请大家记住的还有一个地方没说到 Entry point address: 0x1060 //代码区 .text 起始位置,即程序运行开始位置 它的地址并不是main函数位置0x1174,是0x1060!而且代码区的开始位置是0x1060没错的. [16] .text PROGBITS 0000000000001060 00001060 00000000000001b5 0000000000000000 AX 0 0 16 难度main不是入口地址? 那0x1060上放的是何方神圣,再查符号表发现是 60: 0000000000001060 47 FUNC GLOBAL DEFAULT 16 _start 从反汇编堆中找到 _start 0000000000001060 <_start>: _start(): 1060: f3 0f 1e fa endbr64 1064: 31 ed xor %ebp,%ebp 1066: 49 89 d1 mov %rdx,%r9 1069: 5e pop %rsi 106a: 48 89 e2 mov %rsp,%rdx 106d: 48 83 e4 f0 and $0xfffffffffffffff0,%rsp 1071: 50 push %rax 1072: 54 push %rsp 1073: 4c 8d 05 96 01 00 00 lea 0x196(%rip),%r8 # 1210 <__libc_csu_fini> 107a: 48 8d 0d 1f 01 00 00 lea 0x11f(%rip),%rcx # 11a0 <__libc_csu_init> 1081: 48 8d 3d ec 00 00 00 lea 0xec(%rip),%rdi # 1174 <main> 1088: ff 15 52 2f 00 00 callq *0x2f52(%rip) # 3fe0 <__libc_start_main@GLIBC_2.2.5> 108e: f4 hlt 108f: 90 nop 这才看到了0x1174的main函数.所以真正的说法是: 从内核动态加载的视角看,程序运行首个函数并不是main,而是_start. 但从应用程序开发者视角看,main就是启动函数. 鸿蒙源码百篇博客 往期回顾 在给 鸿蒙内核源码加中文注释 过程中,整理出以下文章.内容立足源码,常以生活场景打比方尽可能多的将内核知识点置入某种场景,具有画面感.百篇博客绝不是百度教条式的在说一堆诘屈聱牙的概念,那没什么意思.更希望让内核变得栩栩如生,倍感亲切.确实有难度,自不量力,但已经出发,回头已是不可能的了.:P 写文章比写代码累多了,越深入研究,越觉得没写好,所以文章和注解会反复修正, .xx代表修改的次数, 将持续完善源码注解和文档内容,精雕细琢,言简意赅, 尽全力打磨精品内容. v51.xx (ELF格式篇) | 用户程序入口并不是main < csdn | harmony | 51cto | osc > v50.xx (编译环境篇) | 编译鸿蒙看这篇或许真的够了 < csdn | harmony | 51cto | osc > v49.xx (信号消费篇) | 谁让CPU连续四次换栈运行 < csdn | harmony | 51cto | osc > v48.xx (信号生产篇) | 年过半百,依然活力十足 < csdn | harmony | 51cto | osc > v47.xx (进程回收篇) | 临终前如何向老祖宗托孤 < csdn | harmony | 51cto | osc > v46.xx (特殊进程篇) | 龙生龙凤生凤老鼠生儿会打洞 < csdn | harmony | 51cto | osc > v45.xx (Fork篇) | 一次调用,两次返回 < csdn | harmony | 51cto | osc > v44.xx (中断管理篇) | 江湖从此不再怕中断 < csdn | harmony | 51cto | osc > v43.xx (中断概念篇) | 海公公的日常工作 < csdn | harmony | 51cto | osc > v42.xx (中断切换篇) | 系统因中断活力四射 < csdn | harmony | 51cto | osc > v41.xx (任务切换篇) | 切换交给了单纯的汇编 < csdn | harmony | 51cto | osc > v40.xx (汇编汇总篇) | 汇编即可爱又单纯 < csdn | harmony | 51cto | osc > v39.xx (异常接管篇) | 社会很单纯,复杂的是人 < csdn | harmony | 51cto | osc > v38.xx (寄存器篇) | 小强乃宇宙最忙存储器 < csdn | harmony | 51cto | osc > v37.xx (系统调用篇) | 开发者永远的口头禅 < csdn | harmony | 51cto | osc > v36.xx (工作模式篇) | CPU是韦小宝,七个老婆 < csdn | harmony | 51cto | osc > v35.xx (时间管理篇) | 谁是操作系统基本时间单位 < csdn | harmony | 51cto | osc > v34.xx (原子操作篇) | 谁在为原子操作保驾护航 < csdn | harmony | 51cto | osc > v33.xx (消息队列篇) | 进程间如何异步传递大数据 < csdn | harmony | 51cto | osc > v32.xx (CPU篇) | 整个内核就是一个死循环 < csdn | harmony | 51cto | osc > v31.xx (定时器篇) | 哪个任务的优先级最高 < csdn | harmony | 51cto | osc > v30.xx (事件控制篇) | 任务间多对多的同步方案 < csdn | harmony | 51cto | osc > v29.xx (信号量篇) | 谁在负责解决任务的同步 < csdn | harmony | 51cto | osc > v28.xx (进程通讯篇) | 九种进程间通讯方式速揽 < csdn | harmony | 51cto | osc > v27.xx (互斥锁篇) | 比自旋锁丰满的互斥锁 < csdn | harmony | 51cto | osc > v26.xx (自旋锁篇) | 自旋锁当立贞节牌坊 < csdn | harmony | 51cto | osc > v25.xx (并发并行篇) | 听过无数编的两个概念 < csdn | harmony | 51cto | osc > v24.xx (进程概念篇) | 进程在管理哪些资源 < csdn | harmony | 51cto | osc > v23.xx (汇编传参篇) | 如何传递复杂的参数 < csdn | harmony | 51cto | osc > v22.xx (汇编基础篇) | CPU在哪里打卡上班 < csdn | harmony | 51cto | osc > v21.xx (线程概念篇) | 是谁在不断的折腾CPU < csdn | harmony | 51cto | osc > v20.xx (用栈方式篇) | 程序运行场地谁提供的 < csdn | harmony | 51cto | osc > v19.xx (位图管理篇) | 谁能一分钱分两半用 < csdn | harmony | 51cto | osc > v18.xx (源码结构篇) | 内核每个文件的含义 < csdn | harmony | 51cto | osc > v17.xx (物理内存篇) | 怎么管理物理内存 < csdn | harmony | 51cto | osc > v16.xx (内存规则篇) | 内存管理到底在管什么 < csdn | harmony | 51cto | osc > v15.xx (内存映射篇) | 虚拟内存虚在哪里 < csdn | harmony | 51cto | osc > v14.xx (内存汇编篇) | 谁是虚拟内存实现的基础 < csdn | harmony | 51cto | osc > v13.xx (源码注释篇) | 鸿蒙必须成功,也必然成功 < csdn | harmony | 51cto | osc > v12.xx (内存管理篇) | 虚拟内存全景图是怎样的 < csdn | harmony | 51cto | osc > v11.xx (内存分配篇) | 内存有哪些分配方式 < csdn | harmony | 51cto | osc > v10.xx (内存主奴篇) | 皇上和奴才如何相处 < csdn | harmony | 51cto | osc > v09.xx (调度故事篇) | 用故事说内核调度过程 < csdn | harmony | 51cto | osc > v08.xx (总目录) | 百万汉字注解 百篇博客分析 < csdn | harmony | 51cto | osc > v07.xx (调度机制篇) | 任务是如何被调度执行的 < csdn | harmony | 51cto | osc > v06.xx (调度队列篇) | 内核有多少个调度队列 < csdn | harmony | 51cto | osc > v05.xx (任务管理篇) | 任务池是如何管理的 < csdn | harmony | 51cto | osc > v04.xx (任务调度篇) | 任务是内核调度的单元 < csdn | harmony | 51cto | osc > v03.xx (时钟任务篇) | 触发调度谁的贡献最大 < csdn | harmony | 51cto | osc > v02.xx (进程管理篇) | 谁在管理内核资源 < csdn | harmony | 51cto | osc > v01.xx (双向链表篇) | 谁是内核最重要结构体 < csdn | harmony | 51cto | osc > 进入 >> osc | csdn | 51cto | 掘金 | 公众号 | 头条号 | gitee | github 关注领取.免费资料.定期更新 热爱是所有的理由和答案 - turing 百万汉字注解鸿蒙源码,百篇博客深挖地基工程. 原创不易,欢迎转载,但麻烦请注明出处.

优秀的个人博客,低调大师

鸿蒙内核源码分析(编译环境篇) | 编译鸿蒙看这篇或许真的够了 | 百篇博客分析HarmonyOS源码 | v50.02

百万汉字注解 >> 精读鸿蒙源码,中文注解分析, 深挖地基工程,大脑永久记忆,四大码仓每日同步更新< gitee | github | csdn | coding > 百篇博客分析 >> 故事说内核,问答式导读,生活式比喻,表格化说明,图形化展示,主流站点定期更新中< oschina | 51cto | csdn | harmony > 编译鸿蒙 本篇记录编译鸿蒙的过程,以备后续不用再去一大堆无效的误导式软文中搜寻芝麻大点有用的信息,那样真挺费时的. 编译环境 先安装 Docker Desktop 下载windows版本一直下一步. 在windows下拉取openharmony-docker官方镜像,Docker方式获取编译环境 强烈推荐这么做. docker pull swr.cn-south-1.myhuaweicloud.com/openharmony-docker/openharmony-docker:0.0.3 2.36G, 拉取看网速, 大概10分钟后成功了,有了镜像 PS E:\harmony\kernel_liteos_a_note> docker images REPOSITORY TAG IMAGE ID CREATED SIZE swr.cn-south-1.myhuaweicloud.com/openharmony-docker/openharmony-docker 0.0.3 50d0aa6ea9ba 2 weeks ago 2.36GB vscode对docker的管理插件非常的强大,管理镜像和容器的工作就交给它了. 启动docker,创建好容器,本文的选择是这样的,当然大家可以灵活处理,命名. 容器创建成功后可以在 vscode 右键容器inspect查看到绑定的目录. "HostConfig": { "Binds": [ "E:\\harmony\\code-1.0:/home/harmony", "E:\\harmony\\docker:/home/docker" ], 本文这样做的目的为了在windows上能方便的查看文件.harmony目录用于下载编译源码目录,另外一个docker放其他无关文件 repo方式下载源码 进入容器,vscode右键容器 Attach shell root@5e3abe332c5a:/home/harmony#repo init -u https://gitee.com/openharmony/manifest.git -b master --no-repo-verify root@5e3abe332c5a:/home/harmony#repo sync -c 这个过程也是比网速.慢慢等吧. 下载完成之后的样子 root@5e3abe332c5a:/home/harmony# ls applications base build build.py developtools device docs domains drivers foundation kernel ohos_config.json prebuilts test third_party utils vendor 编译过程 在源码的根目录执行如下命令安装hb root@5e3abe332c5a:/home/harmony#python3 -m pip install --user build/lite 设置编译路径,选择当前路径 root@5e3abe332c5a:/home/harmony#hb set [OHOS INFO] Input code path: . OHOS Which product do you need? (Use arrow keys) hisilicon ❯ ipcamera_hispark_aries wifiiot_hispark_pegasus ipcamera_hispark_taurus 直接回车,代表选择了ipcamera_hispark_aries,这三个对应平台的关系如下 Hi3518:ipcamera_hispark_aries@hisilicon Hi3861:wifiiot_hispark_pegasus@hisilicon Hi3516:ipcamera_hispark_taurus@hisilicon 执行编译,过程大概20分钟 root@5e3abe332c5a:/home/harmony#hb build -f 查看编译结果 每个的目录含义如下 目录名 描述 applications 应用程序样例,包括wifi-iot,camera等 base 基础软件服务子系统集&硬件服务子系统集 build 组件化编译、构建和配置脚本 docs 说明文档 domains 增强软件服务子系统集 drivers 驱动子系统 foundation 系统基础能力子系统集 kernel 内核子系统 prebuilts 编译器及工具链子系统 test 测试子系统 third_party 开源第三方组件 utils 常用的工具集 vendor 厂商提供的软件 build.py 编译脚本文件 out 编译后生成 编译输出 out为编译结果输出目录 out/hispark_aries/ipcamera_hispark_aries 进入目录 root@5e3abe332c5a:/home/harmony/out/hispark_aries/ipcamera_hispark_aries# ls args.gn build.log bundle_daemon_tool.map dev_tools libs NOTICE_FILE OHOS_Image.asm rootfs suites toggleButtonTest.map userfs vendor bin build.ninja config etc liteos.bin obj OHOS_Image.bin rootfs_jffs2.img test toolchain.ninja userfs_jffs2.img bm_tool.map build.ninja.d data foundation.map media_server.map OHOS_Image OHOS_Image.map server.map test_info unstripped usr 系列篇会详细讲解启动过程,此处进入bin目录瞅瞅都有些啥好宝贝. root@5e3abe332c5a:/home/harmony/out/hispark_aries/ipcamera_hispark_aries/bin# ls ai_server module_ActsAbilityMgrTest.bin module_ActsGraphVersionTest.bin module_ActsJFFS2CapabilityTest.bin module_ActsNFSTest.bin module_ActsSurfaceTest.bin os_dump apphilogcat module_ActsBootstrapTest.bin module_ActsHeapBaseTest.bin module_ActsJFFS2DACTest.bin module_ActsParameterTest.bin module_ActsSysApiTest.bin query.bin appspawn module_ActsBundleMgrTest.bin module_ActsHilogTest.bin module_ActsJFFS2Test.bin module_ActsPMSTest.bin module_ActsTimeApiTest.bin shell bundle_daemon module_ActsColorTest.bin module_ActsIoApiTest.bin module_ActsKvStoreTest.bin module_ActsProcessApiTest.bin module_ActsTransformTest.bin tftp CalcSubTest.bin module_ActsDyloadTest.bin module_ActsIpcMqTest.bin module_ActsListTest.bin module_ActsRectTest.bin module_ActsUiInterfaceTest1.bin wms_server foundation module_ActsFutexApiTest.bin module_ActsIpcPipeTest.bin module_ActsLwipTest.bin module_ActsSamgrTest.bin module_ActsUtilApiTest.bin hilogcat module_ActsGeometyr2dTest.bin module_ActsIpcSemTest.bin module_ActsMathApiTest.bin module_ActsSchedApiTest.bin module_ActsVFATCapabilityTest.bin init module_ActsGraphicMathTest.bin module_ActsIpcShmTest.bin module_ActsMemApiTest.bin module_ActsSecurityDataTest.bin module_ActsVFATDACTest.bin media_server module_ActsGraphMemApiTest.bin module_ActsIpcSignalTest.bin module_ActsNetTest.bin module_ActsSoftBusTest.bin module_ActsVFATTest.bin 这难道都是ELF格式可执行程序? 用readelf命令试下shell就知道了.果然是shell程序,加载它将创建激动人心的shell进程 root@5e3abe332c5a:/home/harmony/out/hispark_aries/ipcamera_hispark_aries/bin# readelf -h shell ELF Header: Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 Class: ELF32 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: DYN (Shared object file) Machine: ARM Version: 0x1 Entry point address: 0x1000 Start of program headers: 52 (bytes into file) Start of section headers: 25268 (bytes into file) Flags: 0x5000200, Version5 EABI, soft-float ABI Size of this header: 52 (bytes) Size of program headers: 32 (bytes) Number of program headers: 11 Size of section headers: 40 (bytes) Number of section headers: 27 Section header string table index: 26 再随便选择一个module_ActsListTest.bin看下,这些是鸿蒙用于测试的代码生成的.也是一个个的独立程序.可以在工程里找到他们的身影list_test.cpp,ActsListTest.json等文件 root@5e3abe332c5a:/home/harmony/out/hispark_aries/ipcamera_hispark_aries/bin# readelf -h module_ActsListTest.bin ELF Header: Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 Class: ELF32 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: DYN (Shared object file) Machine: ARM Version: 0x1 Entry point address: 0xb000 Start of program headers: 52 (bytes into file) Start of section headers: 172256 (bytes into file) Flags: 0x5000200, Version5 EABI, soft-float ABI Size of this header: 52 (bytes) Size of program headers: 32 (bytes) Number of program headers: 11 Size of section headers: 40 (bytes) Number of section headers: 27 Section header string table index: 26 解读 仔细比较下这两个ELF的头文件看哪里不一样 Entry point address: 0x1000 Entry point address: 0xb000 这是程序的入口地址,也就是大家熟悉的main()函数的地址,用户程序是从这个位置开始执行. readelf的功能很强大,有兴趣的可以玩下这个命令,看看elf里面究竟装的啥. root@5e3abe332c5a:/home/harmony/out/hispark_aries/ipcamera_hispark_aries/bin# readelf -help readelf: option requires an argument -- 'p' Usage: readelf <option(s)> elf-file(s) Display information about the contents of ELF format files Options are: -a --all Equivalent to: -h -l -S -s -r -d -V -A -I -h --file-header Display the ELF file header -l --program-headers Display the program headers --segments An alias for --program-headers -S --section-headers Display the sections' header --sections An alias for --section-headers -g --section-groups Display the section groups -t --section-details Display the section details -e --headers Equivalent to: -h -l -S -s --syms Display the symbol table --symbols An alias for --syms --dyn-syms Display the dynamic symbol table -n --notes Display the core notes (if present) -r --relocs Display the relocations (if present) -u --unwind Display the unwind info (if present) -d --dynamic Display the dynamic section (if present) -V --version-info Display the version sections (if present) -A --arch-specific Display architecture specific information (if any) -c --archive-index Display the symbol/file index in an archive -D --use-dynamic Use the dynamic section info when displaying symbols -x --hex-dump=<number|name> Dump the contents of section <number|name> as bytes -p --string-dump=<number|name> Dump the contents of section <number|name> as strings -R --relocated-dump=<number|name> Dump the contents of section <number|name> as relocated bytes -z --decompress Decompress section before dumping it -w[lLiaprmfFsoRtUuTgAckK] or --debug-dump[=rawline,=decodedline,=info,=abbrev,=pubnames,=aranges,=macro,=frames, =frames-interp,=str,=loc,=Ranges,=pubtypes, =gdb_index,=trace_info,=trace_abbrev,=trace_aranges, =addr,=cu_index,=links,=follow-links] Display the contents of DWARF debug sections --dwarf-depth=N Do not display DIEs at depth N or greater --dwarf-start=N Display DIEs starting with N, at the same depth or deeper --ctf=<number|name> Display CTF info from section <number|name> --ctf-parent=<number|name> Use section <number|name> as the CTF parent --ctf-symbols=<number|name> Use section <number|name> as the CTF external symtab --ctf-strings=<number|name> Use section <number|name> as the CTF external strtab -I --histogram Display histogram of bucket list lengths -W --wide Allow output width to exceed 80 characters @<file> Read options from <file> -H --help Display this information -v --version Display the version number of readelf 具体的加载过程和elf格式后续有专门的篇幅详细介绍,此处不做说明. 用户进程 用grep过滤下干扰的*.bin,剩下的就是平台(Hi3518)需要内核创建的用户态进程. root@5e3abe332c5a:/home/harmony/out/hispark_aries/ipcamera_hispark_aries/bin# ls | grep -v .bin ai_server apphilogcat appspawn bundle_daemon foundation hilogcat init media_server os_dump shell tftp wms_server 这些服务含义和仓库如下. ai_server AI业务子系统 https://gitee.com/openharmony/ai_engine apphilogcat 小型系统的流水日志功能 https://gitee.com/openharmony/hiviewdfx_hilog_lite base\hiviewdfx\hilog_lite\services\apphilogcat\hiview_applogcat.c appspawn 应用孵化模块进程 https://gitee.com/openharmony/startup_appspawn_lite bundle_daemon 用户程序框架内部工具接口 https://gitee.com/openharmony/appexecfwk_appexecfwk_lite foundation foundation系统进程 https://gitee.com/openharmony/distributedschedule_safwk_lite hilogcat 管理日志打印 https://gitee.com/openharmony/hiviewdfx_hilog_lite base\hiviewdfx\hilog_lite\services\hilogcat\hiview_logcat.c init 用户态祖宗进程 1号进程, -> 鸿蒙内核源码分析(特殊进程篇) media_server 播放模块框架实现 https://gitee.com/openharmony/multimedia_media_lite os_dump 备份文件系统 utils\native\lite\os_dump\os_dump.c shell 窥视内核的窗口 3号进程, -> 鸿蒙内核源码分析(shell篇) tftp 传输文件 third_party\curl\lib\tftp.c wms_server 窗口管理服务 https://gitee.com/openharmony/graphic_wms 在整个项目工程中能轻易找到他们的入口函数.比如appspawn的启动过程 //base\startup\appspawn_lite\services\src\main.c int main(int argc, char * const argv[]) { sleep(1); HILOG_INFO(HILOG_MODULE_HIVIEW, "[appspawn] main, enter."); // 1. ipc module init HOS_SystemInit(); // 2. register signal for SIGCHLD SignalRegist(); // 3. keep process alive HILOG_INFO(HILOG_MODULE_HIVIEW, "[appspawn] main, entering wait."); while (1) { // pause only returns when a signal was caught and the signal-catching function returned. // pause only returns -1, no need to process the return value. (void)pause(); } } 鸿蒙将服务做成了组件,为最上层的应用程度提供管理/工具类的服务.但这些都是framework层的工作,超出了内核源码分析的范畴.希望后续有机会能去剖析它们. 鸿蒙源码百篇博客 往期回顾 在给 鸿蒙内核源码加中文注释 过程中,整理出以下文章.内容立足源码,常以生活场景打比方尽可能多的将内核知识点置入某种场景,具有画面感.百篇博客绝不是百度教条式的在说一堆诘屈聱牙的概念,那没什么意思.更希望让内核变得栩栩如生,倍感亲切.确实有难度,自不量力,但已经出发,回头已是不可能的了.:P 写文章比写代码累多了,越深入研究,越觉得没写好,所以文章和注解会反复修正, .xx代表修改的次数, 将持续完善源码注解和文档内容,精雕细琢,言简意赅, 尽全力打磨精品内容. v50.xx (编译环境篇) | 编译鸿蒙看这篇或许真的够了 < csdn | 51cto | harmony > v49.xx (信号消费篇) | 用户栈到内核栈的两次切换 < csdn | 51cto | harmony > v48.xx (信号生产篇) | 如何安装和发送信号? < csdn | 51cto | harmony > v47.xx (进程回收篇) | 进程在临终前如何向老祖宗托孤 < csdn | 51cto | harmony > v46.xx (特殊进程篇) | 龙生龙,凤生凤,老鼠生儿会打洞 < csdn | 51cto | harmony > v45.xx (fork篇) | fork是如何做到调用一次,返回两次的 ? < csdn | 51cto | harmony > v44.xx (中断管理篇) | 硬中断的实现<>观察者模式 < csdn | 51cto | harmony > v43.xx (中断概念篇) | 外人眼中权势滔天的当红海公公 < csdn | 51cto | harmony > v42.xx (中断切换篇) | 中断切换到底在切换什么? < csdn | 51cto | harmony > v41.xx (任务切换篇) | 汇编告诉任务到底在切换什么 < csdn | 51cto | harmony > v40.xx (汇编汇总篇) | 所有的汇编代码都在这里 < csdn | 51cto | harmony > v39.xx (异常接管篇) | 社会很单纯,复杂的是人 < csdn | 51cto | harmony > v38.xx (寄存器篇) | arm所有寄存器一网打尽,不再神秘 < csdn | 51cto | harmony > v37.xx (系统调用篇) | 系统调用到底经历了什么 < csdn | 51cto | harmony > v36.xx (工作模式篇) | cpu是韦小宝,有哪七个老婆? < csdn | 51cto | harmony > v35.xx (时间管理篇) | tick是操作系统的基本时间单位 < csdn | 51cto | harmony > v34.xx (原子操作篇) | 是谁在为原子操作保驾护航? < csdn | 51cto | harmony > v33.xx (消息队列篇) | 进程间如何异步解耦传递大数据 ? < csdn | 51cto | harmony > v32.xx (cpu篇) | 整个内核就是一个死循环 < csdn | 51cto | harmony > v31.xx (定时器篇) | 内核最高优先级任务是谁? < csdn | 51cto | harmony > v30.xx (事件控制篇) | 任务间多对多的同步方案 < csdn | 51cto | harmony > v29.xx (信号量篇) | 信号量解决任务同步问题 < csdn | 51cto | harmony > v28.xx (进程通讯篇) | 九种进程间通讯方式速揽 < csdn | 51cto | harmony > v27.xx (互斥锁篇) | 比自旋锁丰满许多的互斥锁 < csdn | 51cto | harmony > v26.xx (自旋锁篇) | 自旋锁当立贞节牌坊! < csdn | 51cto | harmony > v25.xx (并发并行篇) | 怎么记住并发并行的区别? < csdn | 51cto | harmony > v24.xx (进程概念篇) | 进程在管理哪些资源? < csdn | 51cto | harmony > v23.xx (汇编传参篇) | 汇编如何传递复杂的参数? < csdn | 51cto | harmony > v22.xx (汇编基础篇) | cpu在哪里打卡上班? < csdn | 51cto | harmony > v21.xx (线程概念篇) | 是谁在不断的折腾cpu? < csdn | 51cto | harmony > v20.xx (用栈方式篇) | 栈是构建底层运行的基础 < csdn | 51cto | harmony > v19.xx (位图管理篇) | 为何进程和线程优先级都是32个? < csdn | 51cto | harmony > v18.xx (源码结构篇) | 梳理内核源文件的作用和含义 < csdn | 51cto | harmony > v17.xx (物理内存篇) | 这样记伙伴算法永远不会忘 < csdn | 51cto | harmony > v16.xx (内存规则篇) | 内存管理到底在管什么? < csdn | 51cto | harmony > v15.xx (内存映射篇) | 什么是内存最重要的实现基础 ? < csdn | 51cto | harmony > v14.xx (内存汇编篇) | 什么是虚拟内存的实现基础? < csdn | 51cto | harmony > v13.xx (源码注释篇) | 鸿蒙必须成功,也必然成功 < csdn | 51cto | harmony > v12.xx (内存管理篇) | 虚拟内存全景图是怎样的? < csdn | 51cto | harmony > v11.xx (内存分配篇) | 内存有哪些分配方式? < csdn | 51cto | harmony > v10.xx (内存主奴篇) | 紫禁城的主子和奴才如何相处? < csdn | 51cto | harmony > v09.xx (调度故事篇) | 用故事说内核调度过程 < csdn | 51cto | harmony > v08.xx (总目录) | 百万汉字注解 百篇博客分析 < csdn | 51cto | harmony > v07.xx (调度机制篇) | 任务是如何被调度执行的? < csdn | 51cto | harmony > v06.xx (调度队列篇) | 内核有多少个调度队列? < csdn | 51cto | harmony > v05.xx (任务管理篇) | 任务池是如何管理的? < csdn | 51cto | harmony > v04.xx (任务调度篇) | 任务是内核调度的单元 < csdn | 51cto | harmony > v03.xx (时钟任务篇) | 调度最大的源动力来自哪里? < csdn | 51cto | harmony > v02.xx (进程管理篇) | 进程是内核资源管理单元 < csdn | 51cto | harmony > v01.xx (双向链表篇) | 谁是内核最重要结构体? < csdn | 51cto | harmony > 进入 >> oschina | csdn | 51cto | 掘金 | harmony 参与贡献 Fork 本仓库 >> 新建 Feat_xxx 分支 >> 提交代码注解 >> 新建 Pull Request 新建 Issue 喜欢请「点赞+关注+收藏」 各大站点搜 「鸿蒙内核源码分析」.欢迎转载,请注明出处.

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册