s3c2440代码重定位和段的引入——学以致用,综合Makefile的锻炼

对于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, #0
    ldr r0, [r1] /* 读出原来的值备份 */
    str r1, [r1] /* 0->[0] */
    ldr r2, [r1] /* r2=[0] */
    cmp r1, r2   /* r1==r2? 如果相等表示是NAND启动 */
    ldr sp, =0x40000000+4096 /* 先假设是nor启动 */
    ldreq sp, =4096  /* 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, =0
    str r1, [r0]

    /* 设置内存: sp 栈 */
    /* 分辨是nor/nand启动
     * 写0到0地址, 再读出来
     * 如果得到0, 表示0地址上的内容被修改了, 它对应ram, 这就是nand启动
     * 否则就是nor启动
     */
    mov r1, #0
    ldr r0, [r1] /* 读出原来的值备份 */
    str r1, [r1] /* 0->[0] */
    ldr r2, [r1] /* r2=[0] */
    cmp r1, r2   /* r1==r2? 如果相等表示是NAND启动 */
    ldr sp, =0x40000000+4096 /* 先假设是nor启动 */
    ldreq sp, =4096  /* 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=(92<<12)|(1<<4)|(1<<0);
}
void Delay(uint32_t count)
{
    while(count--);
}
int main(void)
{

    uart_init();
    puts("Hello, world!\n\r");
    //sdram_init();

    while (1)
    {
        putchar(glob_a);
        glob_a++;
        Delay(100000);
    }
    return 0;
}

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

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

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

这是为什么呢?

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

查看反汇编:

Disassembly of section .data:

00000800 <__data_start>:
 800:    00006261     andeq    r6, r0, r1, ror #4

00000801 <glob_b>:
 801:    d0000062     andle    r0, r0, r2, rrx

00000804 <q>:
 804:    000005d0     ldreqd    r0, [r0], -r0

00000808 <glob_e>:
 808:    00000001     andeq    r0, r0, r1
Disassembly of section .rodata:

000005cc <p>:
 5cc:    00000001     andeq    r0, r0, r1
 5d0:    72616863     rsbvc    r6, r1, #6488064    ; 0x630000
 5d4:    00712a20     rsbeqs    r2, r1, r0, lsr #20
 5d8:    6c6c6548     cfstr64vs    mvdx6, [ip], #-288
 5dc:    77202c6f     strvc    r2, [r0, -pc, ror #24]!
 5e0:    646c726f     strvsbt    r7, [ip], #-623
 5e4:    000d0a21     andeq    r0, sp, r1, lsr #20
Disassembly of section .bss:

0000080c <golb_c>:
 80c:    00000000     andeq    r0, r0, r0

00000810 <golb_d>:
 810:    00000000     andeq    r0, r0, r0

00000814 <glob_f>:
 814:    00000000     andeq    r0, r0, r0
Disassembly of section .comment:

00000000 <.comment>:
   0:    43434700     cmpmi    r3, #0    ; 0x0
   4:    4728203a     undefined
   8:    2029554e     eorcs    r5, r9, lr, asr #10
   c:    2e342e33     mrccs    14, 1, r2, cr4, cr3, {1}
  10:    47000035     smladxmi    r0, r5, r0, r0
  14:    203a4343     eorcss    r4, sl, r3, asr #6
  18:    554e4728     strplb    r4, [lr, #-1832]
  1c:    2e332029     cdpcs    0, 3, cr2, cr3, cr9, {1}
  20:    00352e34     eoreqs    r2, r5, r4, lsr lr
  24:    43434700     cmpmi    r3, #0    ; 0x0
  28:    4728203a     undefined
  2c:    2029554e     eorcs    r5, r9, lr, asr #10
  30:    2e342e33     mrccs    14, 1, r2, cr4, cr3, {1}
  34:    47000035     smladxmi    r0, r5, r0, r0
  38:    203a4343     eorcss    r4, sl, r3, asr #6
  3c:    554e4728     strplb    r4, [lr, #-1832]
  40:    2e332029     cdpcs    0, 3, cr2, cr3, cr9, {1}
  44:    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 0 -Tdata 0x800 $^ -o sdram.elf
    arm-linux-objcopy -O binary -S sdram.elf [email protected]
    arm-linux-objdump -S -D sdram.elf > sdram.dis
%.o:%.c
    arm-linux-gcc -o [email protected] -c -g $<
%.o:%.S
    arm-linux-gcc -o [email protected] -c -g $<
clean:
    -rm *.bin *.o *.elf *.dis

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

-Tdata 0x800这是把数据段从0x800开始存储。

未完待续。。。。

时间: 2024-10-18 05:40:40

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

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

代码重定位(2.编程实现代码重定位) 1.引入链接脚本 我们上一节讲述了为什么要重定位代码,那么怎么去重定位代码呢? 上一节我们发现"arm-linux-ld -Ttext 0 -Tdata 0x30000000"这种方式编译出来的bin文件有800多M,这肯定是不行的,那么需要怎么把.data段重定位到sdram呢? 可以通过AT参数指定.data段在编译时的存放位置,我们发现这样指定太不方便了,而且不好确定要放在bin文件的哪个位置.这里就要引入链接脚本,它可以帮我们解决这个不必要

s3c6410_uboot中的代码重定位(nand-&gt;sdram)

本文仅探讨s3c6410从nand flash启动u-boot时的代码重定位过程 参考: 1)<USER'S MANUAL-S3C6410X>第二章 MEMORY MAP 第八章 NAND FLASH CONTROLLER 2)u-boot源码: u-boot-x.x.x/board/samsumg/smdk6410/lowlevel_init.S u-boot-x.x.x/cpu/s3c64xx/start.S u-boot-x.x.x/cpu/s3c64xx/nand_cp.c 代码重定位

代码重定位和位置无关码

通过前面的学习,我们知道,把可执行程序从一个位置复制到另一个位置的过程叫做重定位. 现在有两种方式,第一种是只重定位data段到内存(sdram),为什么需要重定位?因为有些flash的写操作,不是简单地内存访问,通常我们使用sdram这个介质作为程序运行的载体.但是只重定位data段这种方式存在弊端.第一,我们的调试工具通常不支持这种分体形式(比如我们的之前的代码在0地址开始存放text和rodata段,而在间隔很远处sdram 0x30000000存放data段,这就是分体的形式)的代码:第

总结:代码重定位

什么是重定位?为什么要代码重定位? 要弄清楚上面的这两个问题,首先要理解下面这几个概念 一.编码 (1)位置无关编码:PIC,可执行程序运行时与代码在内存中的地址无关,代码中没有使用绝对地址,而是使用的相对地址.(例如:B.BL.MOV等指令) (2)位置有关编码:可执行程序运行时与代码在内存中的地址有关系.(例如:LDR PC, =MAIN等指令) 二.地址 (1)链接地址:程序编译链接时指定的地址(使用makefile或者链接脚本可以指定链接地址) (2)运行地址:程序在内存中实际运行的地址

代码重定位

局部变量存储在栈上,栈指向SDRAM可读可写 全局变量包含在.bin文件中,烧写在nor文件中 静态变量 nor_flash不能直接的写 程序中至少包含有代码段和数据段(rodata .bss(初值为0,无初值的全局变量).common注释) const char g_char2 = 'B'   //const是固定的,只能读不能改 rodata 只读数据段 原文地址:https://www.cnblogs.com/rose-/p/12630595.html

重定位引入和链接脚本

1.一个事实:大部分指令是位置有关编码位置无关编码(PIC,position independent code):汇编源文件被编码成二进制可执行程序时编码方式与位置(内存地址)无关.位置有关编码:汇编源码编码成二进制可执行程序后和内存地址是有关的. 我们在设计一个程序时,会给这个程序指定一个运行地址(链接地址).就是说我们在编译程序时其实心里是知道我们程序将来被运行时的地址(运行地址)的,而且必须给编译器链接器指定这个地址(链接地址)才行.最后得到的二进制程序理论上是和你指定的运行地址有关的,将

链接脚本与重定位

目录 链接脚本与重定位 总结 链接脚本格式 COMM段BSS段 elf和bin文件 获得链接脚本的值 重定位 1-直接指定数据段位置(代码黑洞) 2-分散加载(数据段) 3-全局重定位(一体式) BL跳转指令 bss段处理 汇编处理 C处理 位置无关码 title: 链接脚本与重定位 tags: ARM date: 2018-10-12 19:25:53 --- 链接脚本与重定位 学习视频 韦东山 总结 尽量使用一体式的链接脚本,方便简单,灵活 学会使用链接脚本的值 bss段和comm段是需要我

重定位与链接脚本

1.为什么需要重定位 位置无关编码(PIC,position independent code):汇编源文件被编码成二进制可执行程序时编码方式与位置(内存地址)无关. 位置有关编码:汇编源码编码成二进制可执行程序后和内存地址是有关的. 我们在设计一个程序时,会给这个程序指定一个运行地址(链接地址).就是说我们在编译程序时其实心里是知道我们程序将来被运行时的地址(运行地址)的,而且必须给编译器链接器指定这个地址(链接地址)才行.最后得到的二进制程序理论上是和你指定的运行地址有关的,将来这个程序被执

ELF 动态链接 - so 的 重定位表

动态链接下,无论时可执行文件还是共享对象,一旦对其他共享对象有依赖,也就是所有导入的符号时,那么代码或数据中就会有对于导入符号的引用.而在编译时期这些导入符号的确切地址时未知的.只有在运行期才能确定真正确切的地址 静态编译下,这些未知的地址会被编译器一一修正. 对于动态链接来说,共享文件有两种编译方式(gcc -shared 和 gcc -fPIC -shared) 如果不使用PIC模式编译,那么装载时肯定是要重定位的,而且时每个进程都有一个副本(相对比较占用内存) 如果使用PIC模式编译,将会