对于2440而言,nand启动,nand的前4k内容由硬件复制到sram。

nor flash,可以像内存一样读,但是不能像内存一样写,执行写操作需要特殊的操作。

程序中包含有需要写的全局或者静态变量,它们在bin文件中,写在nor flash上,直接修改这样的变量是无效的。

到底什么意思呢?还是看例子比较有说服力。

在学习C语言的过程中,我们或多或少知道一些东西,c/c++可执行文件需要预处理,编译,汇编,连接。

程序有text段,data段,bss段,rodata段等等,今天,就和它们来个亲密接触吧。

还是先说上面的问题吧,看例子:

在之前的程序代码基础上,启动代码增加自动识别是nand还是nor启动:

    /* 设置内存: sp 栈 */
/* 分辨是nor/nand启动
* 写0到0地址, 再读出来
* 如果得到0, 表示0地址上的内容被修改了, 它对应ram, 这就是nand启动
* 否则就是nor启动
*/
mov r1, #
ldr r0, [r1] /* 读出原来的值备份 */
str r1, [r1] /* ->[] */
ldr r2, [r1] /* r2=[] */
cmp r1, r2 /* r1==r2? 如果相等表示是NAND启动 */
ldr sp, =0x40000000+ /* 先假设是nor启动 */
ldreq sp, = /* nand启动 */
streq r0, [r1] /* 恢复原来的值 */

nor flash启动,写入和读出不会相等,即执行ldr sp, =0x40000000+4096 /* 先假设是nor启动 */

而nand启动,由于写入读出都相等,会执行

ldreq sp, =4096 /* nand启动 */
streq r0, [r1] /* 恢复原来的值 */

上面也说了,由于nor flash 的特性,导致像内存一样读可以,可是写操作需要特殊处理,后面的例子你将会看到按内存方式直接写nor flash是无效的。

start.S:

.text
.global _start _start:
/* 关闭看门狗 */
ldr r0, =0x53000000
ldr r1, =
str r1, [r0] /* 设置内存: sp 栈 */
/* 分辨是nor/nand启动
* 写0到0地址, 再读出来
* 如果得到0, 表示0地址上的内容被修改了, 它对应ram, 这就是nand启动
* 否则就是nor启动
*/
mov r1, #
ldr r0, [r1] /* 读出原来的值备份 */
str r1, [r1] /* ->[] */
ldr r2, [r1] /* r2=[] */
cmp r1, r2 /* r1==r2? 如果相等表示是NAND启动 */
ldr sp, =0x40000000+ /* 先假设是nor启动 */
ldreq sp, = /* nand启动 */
streq r0, [r1] /* 恢复原来的值 */ bl SystemInit
//调用main函数
bl main halt:
b halt

main.c:

#include "s3c2440_gpio.h"
#include "s3c2440_soc.h"
#include "uart.h"
#include "init.h"
unsigned char glob_a='a';
unsigned char glob_b='b'; const char p=1;
char *q="char *q"; static int golb_c;
static int golb_d; int glob_e=1;
int glob_f;
void SystemInit(void)
{
//配置LOCKTIME(0x4C000000) = 0xFFFFFFFF
*(volatile unsigned int *)0x4C000000=0xFFFFFFFF;
//CLKDIVN(0x4C000014) = 0X5, tFCLK:tHCLK:tPCLK = 1:4:8
*(volatile unsigned int *)0x4C000014=0x5;
//协处理指仿
__asm__(
"mrc p15, 0, r1, c1, c0, 0\n" /* 读出控制寄存噿*/
"orr r1, r1, #0xc0000000\n" /* 设置为“asynchronous bus mode‿*/
"mcr p15, 0, r1, c1, c0, 0\n" /* 写入控制寄存噿*/
);
/* 设置MPLLCON(0x4C000004) = (92<<12)|(1<<4)|(1<<0)
* m = MDIV+8 = 92+8=100
* p = PDIV+2 = 1+2 = 3
* s = SDIV = 1
* FCLK = 2*m*Fin/(p*2^s) = 2*100*12/(3*2^1)=400M
*/
*(volatile unsigned int *)0x4C000004=(<<)|(<<)|(<<);
}
void Delay(uint32_t count)
{
while(count--);
}
int main(void)
{ uart_init();
puts("Hello, world!\n\r");
//sdram_init(); while ()
{
putchar(glob_a);
glob_a++;
Delay();
}
return ;
}

注意,上面的红色部分,此前的代码我们都没有使用全局变量,这样加上之后,我们编译生成bin文件,其他文件夹都是前面例子的,其实这里只是使用了配置时钟,区分是nand还是nor启动以及前面的串口程序。把这个程序烧写在nand flash上运行,和我们想象中的一致,但是,烧写在nor flash 上,代码却和我们预想的不一致了。

在nand 上 运行,串口会打印abcde。。。。

在nor上运行,串口一直打印a!

这是为什么呢?

我们程序不是做了++处理吗?

查看反汇编:

Disassembly of section .data:

 <__data_start>:
: andeq r6, r0, r1, ror # <glob_b>:
: d0000062 andle r0, r0, r2, rrx <q>:
: 000005d0 ldreqd r0, [r0], -r0 <glob_e>:
: andeq r0, r0, r1
Disassembly of section .rodata: 000005cc <p>:
5cc: andeq r0, r0, r1
5d0: rsbvc r6, r1, # ; 0x630000
5d4: 00712a20 rsbeqs r2, r1, r0, lsr #d8: 6c6c6548 cfstr64vs mvdx6, [ip], #-dc: 77202c6f strvc r2, [r0, -pc, ror #]!
5e0: 646c726f strvsbt r7, [ip], #-e4: 000d0a21 andeq r0, sp, r1, lsr #
Disassembly of section .bss: 0000080c <golb_c>:
80c: andeq r0, r0, r0 <golb_d>:
: andeq r0, r0, r0 <glob_f>:
: andeq r0, r0, r0
Disassembly of section .comment: <.comment>:
: cmpmi r3, # ; 0x0
: 4728203a undefined
: 2029554e eorcs r5, r9, lr, asr #
c: 2e342e33 mrccs , , r2, cr4, cr3, {}
: smladxmi r0, r5, r0, r0
: 203a4343 eorcss r4, sl, r3, asr #
: 554e4728 strplb r4, [lr, #-]
1c: 2e332029 cdpcs , , cr2, cr3, cr9, {}
: 00352e34 eoreqs r2, r5, r4, lsr lr
: cmpmi r3, # ; 0x0
: 4728203a undefined
2c: 2029554e eorcs r5, r9, lr, asr #
: 2e342e33 mrccs , , r2, cr4, cr3, {}
: smladxmi r0, r5, r0, r0
: 203a4343 eorcss r4, sl, r3, asr #c: 554e4728 strplb r4, [lr, #-]
: 2e332029 cdpcs , , cr2, cr3, cr9, {}
: 00352e34 eoreqs r2, r5, r4, lsr lr

这个我们知道了一点(上面例子的第一个static给个非零初始值就更好了,但我不想开虚拟机了,没动手的你可要试试哦),全局或者静态变量初始化为0或者不初始化的都放在.bss段,初始化了的全局或者静态变量放在.data段,const修饰的变量放在.rodata段,.comment段是注释段,比如上面的注释前面几个机器码,我们可以看出它注释的是编译器是gnu gcc。(如果你感兴趣可以全部打出来看看注释信息,采用的UE查看的)

小端模式,所以是反着输入的。

然后就应该是Makefile了,上面的代码需要连接一个data段,否则生成的bin文件会非常大。

.PHONY:clean
objcts :=start.o main.o init.o uart.o s3c2440_gpio.o
sdram.bin:$(objcts)
arm-linux-ld -Ttext -Tdata 0x800 $^ -o sdram.elf
arm-linux-objcopy -O binary -S sdram.elf $@
arm-linux-objdump -S -D sdram.elf > sdram.dis
%.o:%.c
arm-linux-gcc -o $@ -c -g $<
%.o:%.S
arm-linux-gcc -o $@ -c -g $<
clean:
-rm *.bin *.o *.elf *.dis

是不是发现好像makefile变了,是的,是时候加进一步了,之前为了不附加难度,都是使用的最基本的方式书写Makefile,现在熟悉了2440大部分裸机代码了,就该写出点其他的make了。这个Makefile还不是最终版,有潜藏bug,后面再说怎么进一步优化。其中增加了一个连接地址

-Tdata 0x800
这是把数据段从0x800开始存储。为什么要从0x800开始连接数据段呢?
先看看我们没有指定这个选项的时候:
可以看到这个bin文件的大小居然有30多k,而我们的代码是非常小的,这显然是不正常的,我们加上连接时指定数据段地址之后:
这样之后,我们发现文件的大小就比较好接受了。这个数据段地址,需要根据实际情况调整,这里只是演示作用。

好的,现在回到Makefile:

Makefile命令中的带有-(减号)时,表示忽略错误,继续执行make。
@:使命令在被执行前不被回显。

这里主要说明-(减号):

.PHONY:clean

app:main.o

gcc -o app main.o

main.o:main.c

gcc -c main.c

clean:

rm *.o

rm app

main函数只有一个printf函数,此时执行make

.PHONY:clean
app:main.o
gcc -o app main.o
main.o:main.c
gcc -c main.c
clean:
-rm *.o
rm app

关于2440上面的那个Makefile,在我之前的随笔中是有说明的,

Makefile学习之路——2

Makefile 7——自动生成依赖关系 三颗星

看了这两篇之后,你就会知道上面的Makefile存在什么潜在bug。

我们的2440依赖了一个头文件(s3c2440_soc.h),而这个头文件是没有对应源文件的,这样更改这个头文件之后,必须make clean之后,再make才能确保是最新的,如果更改了这个头文件,还是直接make,那么make是不会响应你最新改动的,所以需要我们使用sed指令来进行Makefile的书写,也就是上面的Makefile7所说明的东西。

以前学过了的东西,一定要试着拿在实验或者项目上应用,否则,学那么不使用又有什么意义呢?

Question:

main函数中的

char *q="char *q";

q变量倒是存在.data段中,那么“char *q”这个字符串存放在哪里呢?后面的随笔会给出答案,其实这也是C语言中接触过的知识点。

s3c2440代码重定位和段的引入——学以致用,综合Makefile的锻炼的更多相关文章

  1. s3c2440裸机-代码重定位(1.重定位的引入,为什么要代码重定位)

    1.重定位的引入(为什么要代码重定位) 我们知道s3c2440的cpu从0地址开始取指令执行,当从nor启动时,0地址对应nor,nor可以像内存一样读,但不能像内存一样写.我们能够从nor上取指令执 ...

  2. S3C2440—10.代码重定位

    文章目录 一.启动方式 1.1 NAND FLASH 启动 1.2 NOR FLASH 启动 二. 段的概念 2.1 重定位数据段 2.2 加载地址的引出 三.链接脚本 3.1 链接脚本的引入 3.2 ...

  3. s3c2440裸机-代码重定位(2.编程实现代码重定位)

    代码重定位(2.编程实现代码重定位) 1.引入链接脚本 我们上一节讲述了为什么要重定位代码,那么怎么去重定位代码呢? 上一节我们发现"arm-linux-ld -Ttext 0 -Tdata ...

  4. s3c2440裸机-代码重定位、清bss的改进和位置无关码

    1.代码重定位的改进 用ldr.str代替ldrb, strb加快代码重定位的速度. 前面重定位时,我们使用的是ldrb命令从的Nor Flash读取1字节数据,再用strb命令将1字节数据写到SDR ...

  5. s3c6410_uboot中的代码重定位(nand->sdram)

    本文仅探讨s3c6410从nand flash启动u-boot时的代码重定位过程 参考: 1)<USER'S MANUAL-S3C6410X>第二章 MEMORY MAP 第八章 NAND ...

  6. 代码重定位和位置无关码——运行于nor flash

    通过前面的学习,我们知道,把可执行程序从一个位置复制到另一个位置的过程叫做重定位. 现在有两种方式,第一种是只重定位data段到内存(sdram),为什么需要重定位?因为有些flash的写操作,不是简 ...

  7. Linux从头学06:16张结构图,彻底理解【代码重定位】的底层原理

    作 者:道哥,10+年的嵌入式开发老兵. 公众号:[IOT物联网小镇],专注于:C/C++.Linux操作系统.应用程序设计.物联网.单片机和嵌入式开发等领域. 公众号回复[书籍],获取 Linux. ...

  8. uboot 与 代码重定位

    ref: https://blog.csdn.net/dhauwd/article/details/78566668 https://blog.csdn.net/yueqian_scut/articl ...

  9. U-Boot中关于TEXT_BASE,代码重定位,链接地址相关说明

    都知道U-BOOT分为两个阶段,第一阶段是(~/cpu/arm920t/start.S中)在FLASH上运行(一般情况 下),完成对硬件的初始化,包括看门狗,中断缓存等,并且负责把代码搬移到SDRAM ...

随机推荐

  1. 对IT技术开发职业生涯的思考

    对职业生涯的思考 从刚毕业到目前所在公司,差不多6年了,想想这六年里面,自己的能力和刚毕业比有了很大的提升,但是现在在什么能力上,我不知道,毕竟没有去过别的公司.最近也在思考自己未来,算是比较迷茫阶段 ...

  2. 数十种TensorFlow实现案例汇集:代码+笔记

    这是使用 TensorFlow 实现流行的机器学习算法的教程汇集.本汇集的目标是让读者可以轻松通过案例深入 TensorFlow. 这些案例适合那些想要清晰简明的 TensorFlow 实现案例的初学 ...

  3. Android Studio 2.3 正式版新功能,你不来看看?!

    2017.3.3 Google老大发布了Android Studio 2.3正式版. 在许多2.3beta版本的基础上修复了bug然后推出了正式版.提供了一些新特性,和对部分已有功能的修改完善. Bu ...

  4. oracle三大范式(转载)

    标准化表示从你的数据存储中移去数据冗余 (redundancy)的过程.如果数据库设计达到了完全的标准化,则把所有的表通过关键字连接在一起时,不会出现任何数据的复本 (repetition).标准化的 ...

  5. Android adjustresize全屏无效问题

    屏模式下,即使将activity的windowSoftInputMode的属性设置为:adjustResize,在键盘显示时它未将Activity的Screen向上推动,所以你Activity的vie ...

  6. top 学习

    通常top命令是会持续运行而不终止的. 要在脚本里用,需要添加一些选项参数,尤其是-b.例如:top -b -n 2 -d 3 >/tmp/log -b表示批处理模式(Batch mode),以 ...

  7. 如何在osx的终端下使用字典

    因为各种原因我经常要在osx上查英文单词,在osx系统下,查字典其实是一件非常优雅的事情,三指轻触,简单快速.在terminal中其实也是这样,3指轻触需要查询的单词,释义一触即发,用户体验非常好.不 ...

  8. T-SQL查询进阶--理解SQL Server中索引的概念,原理以及其他

    简介 在SQL Server中,索引是一种增强式的存在,这意味着,即使没有索引,SQL Server仍然可以实现应有的功能.但索引可以在大多数情况下大大提升查询性能,在OLAP中尤其明显.要完全理解索 ...

  9. windows系统安装ubuntu双系统

    近期由于要学习python开发,经常需要用到linux环境.但是一般的编辑和办公在windows环境下有非常的舒服,所以就想装一个双系统.经过几经周折,终于在我的系统上装成功了,在这分享一些安装过程. ...

  10. 在js中嵌套java代码

    jsp中有时候在js中操作某些java后台传递过来的数据逻辑比较复杂,比如list内容的遍历,可以直接在页面上添加java脚本来执行内容,代码如下: //在js中插入java代码操作 <% // ...