1 /*
2 * MPC8349E-mITX ltib U-Boot-1.1.3 GOT PIC --- by starby
3 *
4 * 题记: 最开始看U-Boot源码时,对此部分特别茫然,特专门详细分析了一遍,作为交流:
5 *
6 * 下面是对ltib自带u-boot-1.1.3(PIC: Position Indepedent Code)位置无关代码的分析(基于PowerPC)
7 * 动态库运用PIC的目的是要解决代码/变量地址编译时不能确定的问题;而U-Boot在运行时要从Flash搬运到RAM高端,
8 * 且RAM大小是在运行时检测出来的,编译时不能确定。这样U-Boot和动态库面对的问题相同,需要实现代码位置无关。
9 *
10 *
11 * U-Boot中用GOT表(Global Offset Table 全局偏移量表)实现PIC代码位置无关。
12 *
13 * 总的来讲,U-Boot依靠维护GOT表来实现,在GOT表中存放一些全局label的表项,这些表项记录重要的地址;
14 * 运行在Flash时,GOT表中存放的是编译时全局label的值(地址);当U-Boot运行时检测RAM大小进行代码搬运之后,
15 * 利用代码搬运前后产生的地址偏移对(相对偏移)GOT表中的各个表项值进行更新,使其记录RAM中的相应的地址。
16 * 这样代码运行时不会出现代码/变量地址出错的问题。
17 *
18 */
19
20 // 重要参考文件board/mpc8349itx/u-boot.lds
21
22 // 以下宏定义include/ppc_asm.tmpl文件中
23
24 #define START_GOT \
25 .section ".got2","aw"; \ // 定义了 .got2段,GOT起始地址
26 .LCTOC1 = . + 32768 // .LCTOC1值为[当前地址 + 0x8000(2^15)] (.LCTOC1没占用内存,理解为常值)
27 // 对"."的理解是编译时对应二进制代码地址,参考u-boot.lds理解
28
29 #define END_GOT \ // GOT段结束地址
30 .text
31 // START_GOT和END_GOT两个宏联合起来定义了 .got2段,在这个段里面就定义了一个可供调用的全局表
32
33 #define GET_GOT \
34 bl 1f ; \ // 前向跳转到符号1处,将下条指令的链接地址赋给链接寄存器lr
35 .text 2 ; \
36 0: .long .LCTOC1-1f ; \ // .LCTOC1值减去符号1地址 : 即 GOT表起始地址与符号1的偏移,再加上32768(0x8000)
37 .text ; \
38 1: mflr r14 ; \ // 将链接寄存器lr值(即符号1所处的地址)赋给r14
39 lwz r0,0b-1b(r14) ; \ // 将(0b-1b) + r14处存储的值赋给r0 即符号0处的值加载给r0
40 add r14,r0,r14 ; // r14 <= r0 + r14 即得到.LCTOC1的值 .got2+0x8000
41 // 即通过计算得到.LCTOC1的值(.got2+0x8000),并存放在r14寄存器中(.got2+0x8000)
42
43 #define GOT_ENTRY(NAME) .L_ ## NAME = . - .LCTOC1 ; .long NAME
44 // GOT_ENTRY定义两个字段: .L_(NAME)偏移 和 (NAME)值,实际存储只有第二个字段
45 // .L_(NAME)值为[当前表项地址 - .LCTOC1],即一个相对偏移值。同.LCTOC1,不占用内存,可理解为编译时的常值label
46 // (NAME)值为此"NAME"符号对应的编译时的值,此"NAME"符号多对应位置无关代码(PIC)的重要段地址符号(参见u-boot.lds)
47 // 如GOT_ENTRY(__init_end),对应编译时的值为u-boot.lds中的 __init_end = . ;
48 // GOT_ENTRY的真正作用是将编译时全局lable (NAME)的值存储到GOT表中
49
50
51 #define GOT(NAME) .L_ ## NAME (r14) // 用于计算GOT表中(NAME)表项的地址,即GOT表中(NAME)的存储地址
52 // .L_(NAME)值为[GOT表中此表项地址 - .LCTOC1]
53 // r14为 .LCTOC1
54
55
56 // 以下代码摘自cpu/mpc83xx/start.S中
57
58 START_GOT // .got2段起始
59 GOT_ENTRY(_GOT2_TABLE_) // 4字节存储_GOT2_TABLE_的值(.got2起始地址). u-boot.lds中 _GOT2_TABLE_ = .;
60 GOT_ENTRY(_FIXUP_TABLE_) // 4字节存储_FIXUP_TABLE_的值(.got2结束地址). u-boot.lds中 _FIXUP_TABLE_ = .;
61
62 GOT_ENTRY(_start) // 函数入口地址符号
63 GOT_ENTRY(_start_of_vectors) // ?
64 GOT_ENTRY(_end_of_vectors) // 异常向量代码的结束地址 ?
65 GOT_ENTRY(transfer_to_handler) // 和中断有关
66
67 GOT_ENTRY(__init_end) // 对应u-boot镜像text的结束地址
68 GOT_ENTRY(_end) // u-boot镜像结束地址
69 GOT_ENTRY(__bss_start) // bss段起始地址
70 END_GOT
71 // 上面的代码定义了一个.got2段,在这个段里定义了可供调用的全局表,
72 // 此表中每个表项存储了该表项对应的编译时的值. 参见u-boot.lds
73 // 通过GOT_ENTRY(NAME)宏定义: 第一个字段为此当前表项地址与.LCTOC1(.got2+0x8000)的相对偏移;第二个字段对应编译时符号的值
74 // START_GOT和END_GOT定义GOT表起止;GOT_ENTRY添加一个表项到GOT表中,定义了一个本地label给as用;
75 // .LCTOC1是个symbol,as中的LOCAL symbol的命名规范 (求确认)
76
77
78 /* Some Codes ... */
79
80 GET_GOT // 此代码尚运行在flash中,获得GOT表地址(.got2+0x8000),初始化r14寄存器
81
82 /* Some Codes ... relocate_code: still running in flash */
83
84 lis r4, CFG_MONITOR_BASE@h /* Source Address */
85 ori r4, r4, CFG_MONITOR_BASE@l // r4 <= CFG_MONITOR_BASE
86 lwz r5, GOT(__init_end) // 对GOT表中__init_end的值赋给r5寄存器;宏展开为: lwz r5, .L___init_end (r14)
87 // .L___init_end + r14为GOT表中该表项的地址,此处存储的是 __init_end的值
88 // __init_end的值为u-boot镜像text的结束地址
89 sub r5, r5, r4 // r5 <= r5 - r4,计算u-boot镜像的长度
90
91 /*
92 * relocate_code:
93 *
94 * Fix GOT pointer:
95 *
96 * New GOT-PTR = (old GOT-PTR - CFG_MONITOR_BASE) + Destination Address
97 * That is: new r14 = old r14 - r4 + r10
98 */
99 sub r15, r10, r4 // r15 <= r10 - r4
100 add r14, r14, r15 // r14 <= r14 + r15
101 // 上面的代码中实现更新GOT表起始地址r14(old got2+0x8000)
102 // 原r14为Flash中GOT表起始地址;r4为Flash中u-boot镜像起始地址;r10为RAM中u-boot镜像起始地址
103 // 更新后的r14为RAM中GOT表起始地址(new got2+0x8000)
104
105
106
107 /* Some Codes ... */
108
109 /*
110 * in_ram: Now running from RAM
111 *
112 * Relocation Function, r14 point to got2+0x8000 (got2 + 2^15)
113 *
114 * Adjust got2 pointers, no need to check for 0, this code
115 * already puts a few entries in the table.
116 */
117 // 以下代码更新RAM中GOT表里的内容
118 li r0,__got2_entries@sectoff@l // sectoff段中__got2_entries的低16bit。 __got2_entries为.got2段GOT表项的个数 [9]
119 // u-boot.lds中定义__got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >> 2;
120 // sectoff是section offset的缩写
121 la r3,GOT(_GOT2_TABLE_) // r3 <= r14 + .L__GOT2_TABLE_ ; 将RAM中.got2段起始地址赋给r3 (new .got2 + 0x8000)
122 lwz r11,GOT(_GOT2_TABLE_) // 将RAM中.got2段GOT表表项_GOT2_TABLE_的值赋给r11, (old .got2 + 0x8000)
123 // _GOT2_TABLE_值其实是old GOT表(in Flash)的起始地址(编译时的值)
124 mtctr r0 // ctr <= r0 ; GOT表项个数做循环次数
125 sub r11,r3,r11 // r11 <= r3 - r11 ; 新旧GOT表的相对偏移,所有表项偏移都相同. 高!
126 addi r3,r3,-4 // r3 <= r3 - 4
127 1: lwzu r0,4(r3) // 有效地址(EA)r3+4, 将EA的内容加载到r0, 同时EA存入r3; 取出表项中的值存入r0
128 add r0,r0,r11 // r0 <= r0 + r11 ; 利用相对偏移值r11更新表项值
129 stw r0,0(r3) // 有效地址0+r3, 将r0存储到有效地址; 写回。
130 bdnz 1b // ctr减, 当ctr非零时后向跳转到
131
132
133 /* Some Codes ... */
134
135 /*
136 * clear_bss:
137 *
138 * Now clear BSS segment
139 */
140 lwz r3,GOT(__bss_start) // 将RAM中的GOT表的__bss_start值赋给r3
141 // __bss_start对应RAM中bss段起始地址
142 // 利用了更新后的GOT表,实现了PIC代码位置无关
143
阅读(2609) | 评论(1) | 转发(0) |