本篇关键词:、、、
下载 >> 离线文档.鸿蒙内核源码分析(百篇博客分析.挖透鸿蒙内核).pdf
内核汇编相关篇为:
- v74.01 鸿蒙内核源码分析(编码方式) | 机器指令是如何编码的
- v75.03 鸿蒙内核源码分析(汇编基础) | CPU上班也要打卡
- v76.04 鸿蒙内核源码分析(汇编传参) | 如何传递复杂的参数
- v77.01 鸿蒙内核源码分析(链接脚本) | 正在制作中 ...
- v78.01 鸿蒙内核源码分析(内核启动) | 从汇编到main()
- v79.01 鸿蒙内核源码分析(进程切换) | 正在制作中 ...
- v80.03 鸿蒙内核源码分析(任务切换) | 看汇编如何切换任务
- v81.05 鸿蒙内核源码分析(中断切换) | 系统因中断活力四射
- v82.06 鸿蒙内核源码分析(异常接管) | 社会很单纯 复杂的是人
- v83.01 鸿蒙内核源码分析(缺页中断) | 正在制作中 ...
链接器
board.ld
#include "los_vm_zone.h"
#define TEXT_BASE KERNEL_VADDR_BASE //代码区为内核起始地址
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
MEMORY //链接器的默认配置允许分配所有可用内存,描述链接器可以使用哪些内存区域
{ //ram,sram为存储区域的名字,可以随意取
ram : ORIGIN = KERNEL_VADDR_BASE, LENGTH = KERNEL_VADDR_SIZE //内核运行空间范围
sram : ORIGIN = 0x40000000, LENGTH = 0x1000
user_ram : ORIGIN = 0x1000000, LENGTH = 0x100000 //用户运行空间范围 USER_ASPACE_BASE ,此大小不是真正最后映射到用户空间的大小
}
SECTIONS
{
/DISCARD/ : { *(.comment .note) } //过滤掉所有输入文件的 .comment .note 段
.ram_vectors TEXT_BASE : { //内核中断向量区开始位置,此处用 TEXT_BASE 宏有误导嫌疑, 因为真正的(.text)并不在此 @notethinking
__ram_vectors_vma = .; //定位到当前位置,即TEXT_BASE处
KEEP (*(.vectors)) //告诉链接器 强制保留所有输入文件中的 .vectors 节
} > ram //中断向量是开机代码的位置 , 可翻看 鸿蒙内核源码分析(开机启动篇) 和 (中断管理篇)
__ram_vectors_lma = LOADADDR(.ram_vectors);//启动时对向量的初始化,加载地址和链接地址一致,说明内核设计者希望从加载地址处运行指令
}
//LMA:加载存储地址,指加载到存储器的地址,即加载或烧写到哪里
//VMA:虚拟存储地址,也就是链接地址,即代码和数据运行的时候应在哪里
USER_INIT_VM_START = 0x1000000; //用户空间初始地址
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
liteos.ld
ENTRY(reset_vector) /*指定程序入口地址*/
INCLUDE board.ld // > ram 指放入ram这个地址范围中, ram在board.ld中定义
/* SECTIONS 是脚本中最重要的命令,所有的LD脚本都会有这个命令,用来指定如何将输入文件映射到输出文件等等 */
SECTIONS
{
//节地址是指该节的VMA地址。如果改地未明确指定,连接器会在考虑严格对齐情况下,首先按照region参数分配内存,其次根据当前位置计数器向下分地址。
_start = .; //特殊符号 .表示当前位置计数器,即紧挨着中断向量结束的位置
.set_sysinit_set : {
__start_set_sysinit_set = ABSOLUTE(.); //
KEEP (*(.set_sysinit_set))//所有输入文件中的 .set_sysinit_set 链接到此
__stop_set_sysinit_set = ABSOLUTE(.);//定位结束 .set_sysinit_set 区结束位置
} > ram
.got ALIGN(0x4) : { *(.got.plt) *(.got) } > ram
.gcc_except_table ALIGN (0x8) : { . = .; } > ram .gcc_except_table : { KEEP(*(.gcc_except_table*)) }
.exception_ranges ALIGN (0x8) : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) } > ram
.ARM.extab ALIGN(0x4) : { *(.ARM.extab* .gnu.linkonce.armextab.*) } > ram
/* .ARM.exidx is sorted, so has to go in its own output section. */
.ARM.exidx ALIGN(0x8) : { __exidx_start = .; *(.ARM.exidx* .gnu.linkonce.armexidx.*) ;__exidx_end = .;} > ram
/* text/read-only data */
.text ALIGN(0x1000) : { //代码区 按4K对齐
__text_start = .; //当前位置为 __text_start 开始位置
*(.text* .sram.text.glue_7* .gnu.linkonce.t.*) //*(.text)
} > ram
//重定向代码 Relocation ,包括 代码区和数据区的重定位
.rel.text : { *(.rel.text) *(.rel.text.*) *(.rel.gnu.linkonce.t*) } > ram
.rela.text : { *(.rela.text) *(.rela.text.*) *(.rela.gnu.linkonce.t*) } > ram
.rel.data : { *(.rel.data) *(.rel.data.*) *(.rel.gnu.linkonce.d*) } > ram
.rela.data : { *(.rela.data) *(.rela.data.*) *(.rela.gnu.linkonce.d*) } > ram
.rel.rodata : { *(.rel.rodata) *(.rel.rodata.*) *(.rel.gnu.linkonce.r*) } > ram
.rela.rodata : { *(.rela.rodata) *(.rela.rodata.*) *(.rela.gnu.linkonce.r*) } > ram
.rel.got : { *(.rel.got) } > ram
.rela.got : { *(.rela.got) } > ram
.rel.ctors : { *(.rel.ctors) } > ram
.rela.ctors : { *(.rela.ctors) } > ram
.rel.dtors : { *(.rel.dtors) } > ram
.rela.dtors : { *(.rela.dtors) } > ram
.rel.init : { *(.rel.init) } > ram
.rela.init : { *(.rela.init) } > ram
.rel.fini : { *(.rel.fini) } > ram
.rela.fini : { *(.rela.fini) } > ram
.rel.bss : { *(.rel.bss) } > ram
.rela.bss : { *(.rela.bss) } > ram
.rel.plt : { *(.rel.plt) } > ram
.rela.plt : { *(.rela.plt) } > ram
.rel.dyn : { *(.rel.dyn) } > ram
.dummy_post_text : {
__text_end = .; //代码区结束位置
} > ram
.rodata ALIGN(0x1000) : {
__rodata_start = .; // 只读数据区开始位置
__kernel_init_level_0 = ABSOLUTE(.);
KEEP(*( SORT (.rodata.init.kernel.0.*)));
__kernel_init_level_1 = ABSOLUTE(.);
KEEP(*( SORT (.rodata.init.kernel.1.*)));
__kernel_init_level_2 = ABSOLUTE(.);
KEEP(*( SORT (.rodata.init.kernel.2.*)));
__kernel_init_level_3 = ABSOLUTE(.);
KEEP(*( SORT (.rodata.init.kernel.3.*)));
__kernel_init_level_4 = ABSOLUTE(.);
KEEP(*( SORT (.rodata.init.kernel.4.*)));
__kernel_init_level_5 = ABSOLUTE(.);
KEEP(*( SORT (.rodata.init.kernel.5.*)));
__kernel_init_level_6 = ABSOLUTE(.);
KEEP(*( SORT (.rodata.init.kernel.6.*)));
__kernel_init_level_7 = ABSOLUTE(.);
KEEP(*( SORT (.rodata.init.kernel.7.*)));
__kernel_init_level_8 = ABSOLUTE(.);
KEEP(*( SORT (.rodata.init.kernel.8.*)));
__kernel_init_level_9 = ABSOLUTE(.);
KEEP(*( SORT (.rodata.init.kernel.9.*)));
__kernel_init_level_10 = ABSOLUTE(.);
*(.rodata .rodata.* .gnu.linkonce.r.*)
__exc_table_start = .; //异常表开始位置
KEEP(*(__exc_table))
__exc_table_end = .; //异常表结束位置
} > ram
/*
* extra linker scripts tend to insert sections just after .rodata,
* so we want to make sure this symbol comes after anything inserted above,
* but not aligned to the next section necessarily.
*/
.dummy_post_rodata : {
_hdf_drivers_start = .;
KEEP(*(.hdf.driver)) // 统一驱动框架也放在了只读区
_hdf_drivers_end = .;
__rodata_end = .; //数据只读区结束
} > ram
.data ALIGN(0x1000) : {
/* writable data */
__ram_data_start = .; //可写入数据开始位置
__vdso_data_start = LOADADDR(.data); // vdso区 (virtual dynamic shared object)开始位置
KEEP(*(.data.vdso.datapage)) //vdso由数据区+代码区两部分组成, 可翻看 鸿蒙内核源码分析(vdso篇)
. = ALIGN(0x1000);//vdso 的特性是 代码在内核区, 但运行却在用户区
KEEP(*(.data.vdso.text))//vdso 的代码区
. = ALIGN(0x1000);//按4K对齐,因啥要按4K对齐,因为需要页表映射,而一页为4K
__vdso_text_end = .;//vdso区结束位置
*(.data .data.* .gnu.linkonce.d.*)
. = ALIGN(0x4);
KEEP(*( SORT (.liteos.table.*)));
} > ram
.ctors : ALIGN(0x4) {
__ctor_list__ = .;
KEEP (*(.ctors .init_array))
__ctor_end__ = .;
} > ram
.dtors : ALIGN(0x4) {
__dtor_list__ = .;
KEEP (*(.dtors .fini_array))
__dtor_end__ = .;
} > ram
/*
* extra linker scripts tend to insert sections just after .data,
* so we want to make sure this symbol comes after anything inserted above,
* but not aligned to the next section necessarily.
*/
.dummy_post_data : {
__ram_data_end = .; //可写入数据区结束
} > ram
//这里指的是 init 应用程度的位置
.user_init USER_INIT_VM_START : ALIGN(0x1000) {//开始地址设为 USER_INIT_VM_START = 0x1000000;
. = ALIGN(0x4);
__user_init_load_addr = LOADADDR(.user_init);//应用程序的加载地址
__user_init_entry = .;//应用程序的入口地址
KEEP(libuserinit.O (.user.entry))
KEEP(libuserinit.O (.user.text))
KEEP(libuserinit.O (.user.rodata))
. = ALIGN(0X4);
__user_init_data = .;//设置数据段开始位置 __user_init_data
KEEP(libuserinit.O (.user.data))
. = ALIGN(0X4);
__user_init_bss = .;//init 进程的 bss开始位置
KEEP(libuserinit.O (.user.bss))
. = ALIGN(0x1000);
__user_init_end = .; //init 进程结束位置
} > user_ram AT > ram
__user_init_size = __user_init_end - __user_init_entry; //计算init进程占用大小
/* uninitialized data (in same segment as writable data) | 未初始化数据 */
.bss : {
. = ALIGN(0x800); //当前位置按 0x800对齐
__int_stack_start = .; //内核栈开始位置
*(.int_stack);
. = ALIGN(0x4);//4字节对齐
KEEP(*(.bss.prebss.*))
. = ALIGN(0x8);
__bss_start = .; //将当前位置给__bss_start,将所有的目标*(.bss .bss.*) .. 链接到 .bss中
*(.bss .bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
. = ALIGN(0x8);
__bss_end = .;
} > ram
. = ALIGN(0x1000);
_end = .;
/* mmu temp page table(sys aviliable mem is start with __bss_end) */
. = ALIGN(0x4000);
__mmu_ttlb_begin = .;//临时页表开始位置
/* Strip unnecessary stuff */
/DISCARD/ 0 : { *(.comment .note) } > ram //过滤不需要的块
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
百文说内核 | 抓住主脉络
- 百文相当于摸出内核的肌肉和器官系统,让人开始丰满有立体感,因是直接从注释源码起步,在加注释过程中,每每有心得处就整理,慢慢形成了以下文章。内容立足源码,常以生活场景打比方尽可能多的将内核知识点置入某种场景,具有画面感,容易理解记忆。说别人能听得懂的话很重要! 百篇博客绝不是百度教条式的在说一堆诘屈聱牙的概念,那没什么意思。更希望让内核变得栩栩如生,倍感亲切。
- 与代码需不断
debug
一样,文章内容会存在不少错漏之处,请多包涵,但会反复修正,持续更新,v**.xx
代表文章序号和修改的次数,精雕细琢,言简意赅,力求打造精品内容。 - 百文在 < 鸿蒙研究站 | 开源中国 | 博客园 | 51cto | csdn | 知乎 | 掘金 > 站点发布,百篇博客系列目录如下。
按功能模块:
百万注源码 | 处处扣细节
百万汉字注解内核目的是要看清楚其毛细血管,细胞结构,等于在拿放大镜看内核。内核并不神秘,带着问题去源码中找答案是很容易上瘾的,你会发现很多文章对一些问题的解读是错误的,或者说不深刻难以自圆其说,你会慢慢形成自己新的解读,而新的解读又会碰到新的问题,如此层层递进,滚滚向前,拿着放大镜根本不愿意放手。
好物推荐 | 捐助名单
奋斗者永远年轻!推荐一本能让您少走十年弯路的好书,只需一顿饭钱
公众号 | 视频号
据说喜欢 点赞 + 分享 的,后来都成了大神。😃