Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1270609
  • 博文数量: 482
  • 博客积分: 13297
  • 博客等级: 上将
  • 技术积分: 2890
  • 用 户 组: 普通用户
  • 注册时间: 2009-10-12 16:25
文章分类

全部博文(482)

文章存档

2012年(9)

2011年(407)

2010年(66)

分类: LINUX

2011-08-12 08:45:12

116页的定义为:unsigned long  const    mem_cfg_val [ ] ...,mem_cfg_val 的值是保留在代码段中的,这要求运行时的地址和程序的编译地址一致,这不是位置无关的代码;
168页这样赋值:“p[0] = 0x22011110;    //BWSCON”,这些值是在栈中临时生成的,这是位置无关的代码

上面是位置相关的解释。
请问,在95页的mem_cfg_val是在代码段中还是栈中?或是其他方式?
而这个程序的链接地址是0x30000000,却可以在Steppingstone中正确执行,这是为什么?
在/work/hardware/timer Head.S 的48行 ldr pc,=on_sdram 执行后就会跳到sdram中执行,而不是继续在Steppingstone中执行,这是为什么?

能不能详细解释位置相关与无关?如何区分和编写位置相关与无关的代码?

谢谢
----------------------------------------------------------------------------------------------
 
回复: 位置相关与无关
1. 从指令级来看:
请参考书的3.1.2中的第1小节

2. 从C语言来看,如果要使用全局变量、静态变量,那么肯定就是位置相关的。
    要理解这点,需要看汇编代码。
  比如使用静态变量mem_cfg_val的memsetup函数(这里说是静态变量也许不合适,但是mem_cfg_val是保存在数据段中的):

CODE:
/*
* 设置存储控制器以使用SDRAM
*/
void memsetup(void)
{
    /* SDRAM 13个寄存器的值 */
    unsigned long  const    mem_cfg_val[]={ 0x22011110,    //BWSCON
                                            0x00000700,    //BANKCON0
                                            0x00000700,    //BANKCON1
                                            0x00000700,    //BANKCON2
                                            0x00000700,    //BANKCON3 
                                            0x00000700,    //BANKCON4
                                            0x00000700,    //BANKCON5
                                            0x00018005,    //BANKCON6
                                            0x00018005,    //BANKCON7
                                            0x008C07A3,    //REFRESH
                                            0x000000B1,    //BANKSIZE
                                            0x00000030,    //MRSRB6
                                            0x00000030,    //MRSRB7
                                    };
    int    i = 0;
    volatile unsigned long *p = (volatile unsigned long *)MEM_CTL_BASE;
    for(; i < 13; i++)
        p[i] = mem_cfg_val[i];
}


连接地址是0时,它的反汇编代码是:

CODE:
00000048 :
  48: e59f0030  ldr r0, [pc, #48] ; 80     // r0等于内存地址0x80处的数值,往后看“80: 00000160  ”,就是0x160
  4c: e5902000  ldr r2, [r0]                                                // 0x160就是mem_cfg_val数组的地址,取值,r2就是mem_cfg_val[i]数组的值
  50: e3a03312  mov r3, #1207959552 ; 0x48000000      // 存储控制器的基址
  54: e5832000  str r2, [r3]                                                // 把r2的值写入寄存器
  58: e2831004  add r1, r3, #4 ; 0x4                                  // 寄存器地址增4
  5c: e0813000  add r3, r1, r0
  60: e283332e  add r3, r3, #-1207959552 ; 0xb8000000
  64: e5932000  ldr r2, [r3]
  68: e3a03312  mov r3, #1207959552 ; 0x48000000
  6c: e4812004  str r2, [r1], #4
  70: e2833034  add r3, r3, #52 ; 0x34
  74: e1510003  cmp r1, r3
  78: 1afffff7  bne 5c
  7c: e12fff1e  bx lr
  80: 00000160  .word 0x00000160
……
00000160 :
160: 22011110  .word 0x22011110
164: 00000700  .word 0x00000700
168: 00000700  .word 0x00000700
16c: 00000700  .word 0x00000700
170: 00000700  .word 0x00000700
174: 00000700  .word 0x00000700
178: 00000700  .word 0x00000700
17c: 00018005  .word 0x00018005
180: 00018005  .word 0x00018005
184: 008c07a3  .word 0x008c07a3
188: 000000b1  .word 0x000000b1
18c: 00000030  .word 0x00000030
190: 00000030  .word 0x00000030
194: 43434700  .word 0x43434700
198: 4728203a  .word 0x4728203a
19c: 2029554e  .word 0x2029554e
1a0: 2e322e34  .word 0x2e322e34
1a4: 0f410032  .word 0x0f410032
1a8: 61000000  .word 0x61000000
1ac: 69626165  .word 0x69626165
1b0: 00050100  .word 0x00050100
1b4: 00000000  .word 0x00000000


可以看到,使用“unsigned long  const    mem_cfg_val”时,这些数值不是在栈中的,而是通过它的“编译地址”去内存中读取。
这就不是位置无头的代码,而是位置相关:如果编译地址是0x30000000,那么就会去SDRAM中取值。


3. 从C语言来看,如果使用“p[0] = 0x22011110;”这样的方式,是位置无关的。
    比如:

CODE:
/*
* 设置存储控制器以使用SDRAM
*/
void memsetup(void)
{
    volatile unsigned long *p = (volatile unsigned long *)MEM_CTL_BASE;
    /* 这个函数之所以这样赋值,而不是像前面的实验(比如mmu实验)那样将配置值
    * 写在数组中,是因为要生成”位置无关的代码”,使得这个函数可以在被复制到
    * SDRAM之前就可以在steppingstone中运行
    */
    /* 存储控制器13个寄存器的值 */
    p[0] = 0x22011110;    //BWSCON
    p[1] = 0x00000700;    //BANKCON0
    p[2] = 0x00000700;    //BANKCON1
    p[3] = 0x00000700;    //BANKCON2
    p[4] = 0x00000700;    //BANKCON3 
    p[5] = 0x00000700;    //BANKCON4
    p[6] = 0x00000700;    //BANKCON5
    p[7] = 0x00018005;    //BANKCON6
    p[8] = 0x00018005;    //BANKCON7
   
    /* REFRESH,
    * HCLK=12MHz:  0x008C07A3,
    * HCLK=100MHz: 0x008C04F4
    */
    p[9]  = 0x008C04F4;
    p[10] = 0x000000B1;    //BANKSIZE
    p[11] = 0x00000030;    //MRSRB6
    p[12] = 0x00000030;    //MRSRB7
}


它的反汇编代码如下:

CODE:
30000100 :
30000100: e3a03422  mov r3, #570425344 ; 0x22000000                // 直接赋值
30000104: e2833a11  add r3, r3, #69632 ; 0x11000                          // 相加,就是0x22011000
30000108: e3a01312  mov r1, #1207959552 ; 0x48000000              // 直接赋值,就是BWSCON的地址
3000010c: e2833e11  add r3, r3, #272 ; 0x110                                  // 相加,就是0x22011110,这就是“ p[0] = 0x22011110”中右边的值
30000110: e5813000  str r3, [r1]                                                        // 相当于: p[0] = 0x22011110
30000114: e3a03723  mov r3, #9175040 ; 0x8c0000
30000118: e3a02c07  mov r2, #1792 ; 0x700
3000011c: e3a00906  mov r0, #98304 ; 0x18000
30000120: e2833e4f  add r3, r3, #1264 ; 0x4f0
30000124: e5812004  str r2, [r1, #4]
30000128: e2800005  add r0, r0, #5 ; 0x5
3000012c: e5812008  str r2, [r1, #8]
30000130: e3a0c030  mov ip, #48 ; 0x30
30000134: e581200c  str r2, [r1, #12]
30000138: e2833004  add r3, r3, #4 ; 0x4
3000013c: e5812010  str r2, [r1, #16]
30000140: e5812014  str r2, [r1, #20]
30000144: e5812018  str r2, [r1, #24]
30000148: e3a020b1  mov r2, #177 ; 0xb1
3000014c: e581001c  str r0, [r1, #28]
30000150: e5810020  str r0, [r1, #32]
30000154: e5813024  str r3, [r1, #36]
30000158: e5812028  str r2, [r1, #40]
3000015c: e581c02c  str ip, [r1, #44]
30000160: e581c030  str ip, [r1, #48]
30000164: e12fff1e  bx lr


可见,memsetup的操作不涉及编译地址,所以它的位置无关的。

4.
请问,在95页的mem_cfg_val是在代码段中还是栈中?或是其他方式?
而这个程序的链接地址是0x30000000,却可以在Steppingstone中正确执行,这是为什么?
在/work/hardware/timer Head.S 的48行 ldr pc,=on_sdram 执行后就会跳到sdram中执行,而不是继续在Steppingstone中执行,这是为什么?

① 95页中使用汇编代码赋值,都是使用adrl、mov、ldr等与位置无关的指令,所以“链接地址是0x30000000,却可以在Steppingstone中正确执行”
② ldr pc,=on_sdram 的结果是这样,你看看反汇编:

CODE:
30000034: e59ff03c  ldr pc, [pc, #60] ; 30000078   // 当前PC值是0x34+8(流水线,PC值是当前指令+8)=0x3c,pc+60=0x78;放条指令就是从0x78的内存取值,赋给PC
30000078: 30000038  .word 0x30000038                                          // 0x78的值就是0x30000038,所以,上面的指令执行完后,PC的值就是0x30000038,在SDRAM中了


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