【S3C2440】第13课、代码重定位之课堂学习笔记


1、第1节:打印结果:aaaaaaaaaabcdefghijklmnopqrstuvwxyaz{|}
可知:1)当拨码开关从Nand调到Nor再调到Nand时,之前的程序运行结果依然存在且程序接着之前的进程继续运行
2)全局变量的改变在Nor中无用,在Nand中有作用,例如(同一程序):Nand: Aa1Bb2Cc3...    Nor: Aa1Aa1Aa1...


程序只能从Nandflash/Norflash启动,SRAM/SDRAM之于Nandflash/Norflash为辅助角色,其功能为重定位复制存储数据段甚至代码段

 

Norflash不需要设置,即可直接调用; 而SDRAM需要设置,然后才能调用。

 

Nandflash前4K是复制到SRAM中,然后在Nand档运行; 超过4k就会运行崩溃,需要设置Nandflash控制器;

====================================================================
2、第13课的第二节问题:
在于main()函数中while(1)打印:ABCDE...
while(sdram_test() == 1)时,持续输出一个不变字符达不到预期目的, 如:UUUU...
解答:在判断或执行sdram_test()函数时,[0x30000000]及之后的100000个字节的内存被该函数赋值重新装数;
当只有一个字符自加结果打印时,只会输出被修改后的数,而主程序要实现字符自加的目的将永远不能实现
当有多个字符自加结果打印时,每次打印两个被修改的数,而主程序要实现字符自加的目的将永远不能实现
=====================================================================
3、问题:关于链接脚本使用的问题,第13课第5节008程序:
SECTIONS
{
. = 0x30000000;
. = ALIGN(4);
.text 0 : {*(.text);}
. = ALIGN(4);
.rodata : {*(.rodata);}
. = ALIGN(4);
.data : {*(.data);}
. = ALIGN(4);
_bss_start = . ;
.bss :
{
*(.bss)  *(.COMMON);
}
_end = . ;
}
#...
int g_i = 0;
int g_j = 0xabcdef12;
int g_k = 0x12;
int g_l = 12;
volatile unsigned char g_char1 = 'A';
volatile unsigned char g_char2 = 'a';
volatile unsigned char g_char3 = '1';
int main(void){...}
程序下载到Nor的打印结果:
0xffffffff
0xabcdef12
0x00000012
0x0000000c
Aa1Aa1Aa1Aa1Aa1
程序下载到Nand/或去0后的打印结果:
0x00000000
0xabcdef12
0x00000012
0x0000000c
Aa1Bb2Cc3Dd4
问题:不自加的原因已经找到,链接脚本中,.text从0开始,整个程序的重定位失效,通过查看.dis可知;
把链接脚本中的.text 0中的0去掉之后,下载到Nor,运行就正常了。但是,没修改前.bss为什么不可以清零?
问题反映到【Linux嵌入式维基百科群 】,回答如下:
百问科技~韦东山(1402284892)  11:43:18
如果使用的编译器不一样 比如更高版本 可能出现不可预料的问题
=======================================================================
4、问题代码: cmp r1, r2
ble clean
当 r1==r2 时,若.bss段末字节不是整对齐4字节的末字节,该整对齐4字节其余字节空间是不是也会被清0?乃至段间空闲字节空间如何处理呢?
答:1)理论上会的,.bss段结尾后是_end即有效程序的结尾,即使_end不是4字节的尾字节也无所谓,但一般.bss段放在最后,所以多清0也无所谓;
2)如果是别的段,如:.text, .rodata, .data段,则不会。因为所有读写操作都是以4字节为单位,且从所有段起始地址就是以4字节对齐的,
.data段(甚至别的段)与下一段之间,即使有全局变量在.data段最后一个字节,但其在该段的位置必然小于等于该段的末地址,且必然小于下一个4字节的
起始地址,而末地址所在的4字节必然服从读写操作。
3)对于在一个段实际有效的结束字节和下一段的开始字节间的空间,是程序未用到的字节空间(1-3字节),是程序不用的空间,任意操作无所谓?
虽然任意改写对程序没有影响,但是访问的话,得到的将是不可预料的数,应该让程序慎重运行在可控的内存空间。
关于问题3第一小问的解决意见(修改如下):
1- sdram.lds:
. = ALIGN(4);
_end = . ;
2- cmp r1, r2
blt clean
代入程序运行结果:结果见问题5结果。
========================================================================
5、问题代码:bl sdram_init
/* 所有程序重定位 */
mov r1, #0 //程序在.bin文件中的地址,即加载地址
ldr r2, =_start //第一条指令运行时的地址
ldr r3, =_bss_start //程序结束地址
cpy:
ldr r4, [r1]
str r4, [r2]
add r1, r1, #4
add r2, r2, #4
cmp r2, r3
ble cpy
问题及分析:重定位的代码,除了.text, .rodata, .data段,由于ble是判断 r2 <= r3 时即执行cpy; 
因此,当cpy到 _bss_start 地址时,r2=r3 仍成立,仍然要复制.bss段的头4字节空间的内容到SDRAM;
修改意见:ble 改为 blt(小于执行xxx)
代入程序运行结果:

经问题4/5的修改意见修改之后,打印效果和修改之前一模一样,实验例程路径:relocate>008_2。

 

======================================================================

6、关于外部变量__code_start替换为_start的使用验证

/* 重定位全部程序.text, .rodata, .data段 */
void copy_sdram(void)
{
extern int __code_start, _bss_start, _start; //_start在.text中; __code_start, _bss_start,在sdram.lds中;
volatile unsigned int * src = (volatile unsigned int *)0; //加载起始地址
//volatile unsigned int * dest = (volatile unsigned int *)&__code_start; //1号:重定位起始地址
volatile unsigned int * dest = (volatile unsigned int *)&_start; //2号:重定位起始地址
volatile unsigned int * end = (volatile unsigned int *)&_bss_start; //重定位起始地址

while(dest < end)
{
*dest++ = *src++;
}
}
经验证,1号2号的打印结果一样,均为正常打印; 
2号的反汇编为:
| Disassembly of section .text: |
| 30000000 <_start>: |



 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章