zoukankan      html  css  js  c++  java
  • s3c2440裸机-代码重定位、清bss的优化和位置无关码

    1.代码重定位的改进

    1. 用ldr、str代替ldrb, strb加快代码重定位的速度

      前面重定位时,我们使用的是ldrb命令从的Nor Flash读取1字节数据,再用strb命令将1字节数据写到SDRAM里面。
      我们2440开发板的Nor Flash是16位,SDRAM是32位。 假设现在需要复制16byte数据。

      不同的读写指令 cpu读取nor的次数 cpu写入sdram的次数
      ldrb、strb 16 16
      ldr、str 8 4

      可以看出我们更换读写指令后读写次数变少了,提升了cpu的访问效率。

      修改后的start.s代码如下图所示,这里我只简单的列出了重定位的实现:

       ...
       cpy:
       	ldr r4, [r1]
       	str r4, [r2]
       	add r1, r1, #4 //r1加4
       	add r2, r2, #4 //r2加4
       	cmp r2, r3 //如果r2 =< r3继续拷贝
       	ble cpy
       ...
      
    2. 用c语言实现重定位

    添加如下链接脚本:

    SECTIONS
    {
    	. = 0x30000000;
    
    	__code_start = .;
    
    	. = ALIGN(4);
    	.text      :
    	{
    	  *(.text)
    	}
    
    	. = ALIGN(4);
    	.rodata : { *(.rodata) }
    
    	. = ALIGN(4);
    	.data : { *(.data) }
    
    	. = ALIGN(4);
    	__bss_start = .;
    	.bss : { *(.bss) *(.COMMON) }
    	_end = .;
    }
    

    在main.c中添加如下函数实现:

    void copy2sdram(void)
    {
    		//要从lds文件中获得 __code_start, __bss_start
    		//然后从0地址把数据复制到__code_start
    
    	extern int __code_start, __bss_start;
    
    	volatile unsigned int *dest = (volatile unsigned int *)&__code_start;
    	volatile unsigned int *end = (volatile unsigned int *)&__bss_start;
    	volatile unsigned int *src = (volatile unsigned int *)0;
    
    	while (dest < end)
    	{
    		*dest++ = *src++; //从0地址依次copy到__code_start(代码段的运行地址)
    	}
    }
    

    然后在start.s中设置栈指针sp后,即可执行bl copy2sdram进行重定位代码。如何设置栈指针请参考
    时钟编程(二、配置时钟寄存器)中有实现,重复代码我就不贴上来了。

    2.清bss的改进

    1. 用ldr、str代替ldrb, strb加快清bss的速度

      和上面重定位类似,代码如下:

           ldr r1, =__bss_start
           ldr r2, =_end
           mov r3, #0
       clean:
           str r3, [r1]
           add r1, r1, #4
           cmp r1, r2
           ble clean
      
           bl main
       halt:
      		b halt
      
    2. c语言实现清bss

      和上面重定位的代码实现一样,就是往bss段全部写0. 执行完bl copy2sdram, 然后再bl clean_bss即可完成清除bss段。

       void clean_bss(void)
       {
       	/* 从lds文件中获得 __bss_start, _end*/
       	extern int _end, __bss_start;
       
       	volatile unsigned int *start = (volatile unsigned int *)&__bss_start;
       	volatile unsigned int *end = (volatile unsigned int *)&_end;
       
       	while (start <= end)
       	{
       		*start++ = 0;
       	}
       }
      

      注意:汇编代码获取的是链接脚本中的变量的地址,而C语言代码中获取的是链接脚本中的变量的值,所以这里的用C语言改进重定位还是清bss都是要加取址符。

    3. 保证所有段的起始地址以4字节对齐

      我们前面为了加快重定位和清bss的速度,用到了ldr,str这样以4字节为单位进行读写,但是还可能导致一个问题,假设现在链接脚本没有进行用ALIGN(4)让不同的段以4字节对齐,那么就会出现访问错乱的情况。

      我举个例子:

       #include "s3c2440_soc.h"
       #include "uart.h"
       #include "init.h"
       
       char g_Char = 'A'; //.data
       char g_Char3 = 'a';
       const char g_Char2 = 'B'; //.rodata
       int g_A = 0; //bss
       int g_B; //bss
       
       int main(void)
       {
       	uart0_init();
       
       	puts("
      
      g_A = ");
       	printHex(g_A);
       	puts("
      
      ");
       	putchar(g_Char);
       	return 0;
       }
      

      将链接脚本中.data段和.bss之间的ALIGN(4)去掉。那么我们会发现程序执行的时候输出的g_A=0,为什么呢,我们明明初始化g_A=‘A’呀?

      我们分析下反汇编看看:

      我们的.bss段紧接着.data段后面,可知在对bss段进行清除的时候,由于我们是以4字节为单位操作的,所以我们清除g_A的时候,连带g_Char,g_Char的值也一起清除了。所以data段和数据段之间添加ALIGN(4)。修改后就会发现bss段的地址以0x30000248开始了,如下图:

    3.位置无关码

    我们对‘bl sdram_init’指令进行分析:
    查看反汇编:(代码段的链接地址为0x3000,0000)

    这里的bl 3000036c不是跳转到3000036c,这个时候sdram并未初始化,那么这个物理地址是无法访问的;
    为了验证,我们做另一个实验,修改连接脚本sdram.lds, 链接地址改为0x3000,0800,编译,查看反汇编:

    可以看到现在变成了bl 300003ec,但两个的机器码e1a0c00d都是一样的,机器码一样,执行的内容肯定都是一样的。 因此这里并不是跳转到显示的地址,而是跳转到: pc + offset,这个由链接器决定。

    假设程序从0x30000000执行,当前指令地址:0x3000005c ,那么就是跳到0x3000036c;如果程序从0运行,当前指令地址:0x5c 调到:0x000003ec

    跳转到某个地址并不是由bl指令所决定,而是由当前pc值决定。反汇编显示这个值只是为了方便读代码。

    重点: 反汇编文件里, B或BL 某个值,只是起到方便查看的作用,并不是真的跳转。

    怎么写位置无关码?

    使用相对跳转命令 b或bl;
    重定位之前,不可使用绝对地址,不可访问全局变量/静态变量,也不可访问有初始值的数组(因为初始值放在rodata里,使用绝对地址来访问);
    重定位之后,使用ldr pc = xxx,跳转到/runtime地址;
    写位置无关码,其实就是不使用绝对地址,判断有没有使用绝对地址,除了前面的几个规则,最根本的办法看反汇编。

    因此,前面的例子程序使用bl命令相对跳转,程序仍在NOR/sram执行,要想让main函数在SDRAM执行,需要修改代码:

      //bl main  /*bl相对跳转,程序仍在NOR/sram执行*/
      ldr pc, =main/*绝对跳转,跳到SDRAM*/
    
  • 相关阅读:
    ZOJ 1002 Fire Net
    Uva 12889 One-Two-Three
    URAL 1881 Long problem statement
    URAL 1880 Psych Up's Eigenvalues
    URAL 1877 Bicycle Codes
    URAL 1876 Centipede's Morning
    URAL 1873. GOV Chronicles
    Uva 839 Not so Mobile
    Uva 679 Dropping Balls
    An ac a day,keep wa away
  • 原文地址:https://www.cnblogs.com/fuzidage/p/12056680.html
Copyright © 2011-2022 走看看