Chinaunix首页 | 论坛 | 博客
  • 博客访问: 496712
  • 博文数量: 174
  • 博客积分: 2502
  • 博客等级: 少校
  • 技术积分: 1923
  • 用 户 组: 普通用户
  • 注册时间: 2008-09-28 09:47
文章分类

全部博文(174)

文章存档

2011年(8)

2010年(16)

2009年(68)

2008年(82)

我的朋友

分类: 嵌入式

2009-09-02 09:47:59

  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     

阅读(2230) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~