s3c2440裸机-代码重定位、清bss的优化和位置无关码

发布时间:2023-08-09  

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

 ...

用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的改进

用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

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都是要加取址符。


保证所有段的起始地址以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("nrg_A = ");

 printHex(g_A);

 puts("nr");

 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*/


文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

相关文章

    方法分类 (1)M法测速 编码器输出的脉冲个数代表了位置,那么单位时间里的脉冲个数表示这段时间里的平均速度。因此,我们可以通过计量单位时间脉冲个数即可以估算出平均速度,称为M法测速(测脉冲个数)测速......
    ,每个位置编码唯一不重复,而无需记忆。多圈编码器另一个优点是由于测量范围大,实际使用往往富余较多,这样在安装时不用费劲找零点, 将某一中间位置作为起始点就可以了,从而大大简化了安装调试的难度,如图2.9......
    编程 相信看了上面的一些描述,大家应该对编码器有所理解了。其实,在STM32中,可以通过配置编码器模式对应的函数,就能实现获取编码器传感器上面的信息了。 使用STM32提供的标准外设库,或者......
    电机控制反馈系统 什么是位置编码器编码器通过跟踪旋转轴的速度和位置来提供闭环反馈信号。光学和磁编码器技术使用非常广泛,如图2所示。在通用伺服驱动器中,编码器用于测量轴位置,从中......
    看下接线图。(如果需要使用绝对位置控制,即是使用绝对编码器的话还需要通讯,绝对位置控制本身照比相对位置控制更加准确,且不受外界因素影响,缺点是绝对位置编码器不好维护,出现问题后需要手动复位,复位过程较麻烦,而且松下的驱动器为了保证绝对编码器......
    较低性能应用中的许多电机驱动器采用开环速度控制,而不需要编码器。但是,这种方法有几个缺点: ● 由于没有反馈,速度精度很有限 ● 由于无法优化电流控制,电机效率很低 ● 必须严格限制瞬态响应,以免电机丧失同步 图1.闭环电机控制反馈系统 什么是位置编码器......
    一文详解无传感器PMSM 马达FOC控制算法详解;      PMSM应用 高效率和高可靠性 设计用于高性能伺服应用 可实现有1无位置编码器的运行方式 比ACIM体积更小、效率更高、重量更轻 采用......
    量级多层感知(MLPs)解码器结合起来。SegFormer有两个吸引人的特点: 1 SegFormer包含一个新的层次结构的Transformer编码器,输出多尺度特征。它不需要位置编码,这样就不用对位置编码......
    。但是,此方法有几个缺点: 速度精度有限,因为没有反馈 电机效率差,因为电流控制无法优化 必须严格限制瞬态响应,以免电机失去同步 图1.闭环电机控制反馈系统。 什么是位置编码器编码器通过跟踪旋转轴的速度和位置......
    Response无反馈,表示不成功,可重新上下电重复⑥⑦ 9)地址设置成功后,开关拨到【正常】,重新上下电 10)设置编码器工作模式为0(具体说明参照YL69说明书) 依次选择【串口选择】、【波特......

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>