zoukankan      html  css  js  c++  java
  • Tiny6410之重定位代码到SRAM+4096

    重定位代码
      两个不同的地址概念:
      对于程序而言,需要理解两个地址,一个是程序当前所处的地址,即程序运行时所处的当前地址。二是程序应该位于的运行地址,即编译程序时所指定的程序的链接地址。在Tiny6410中板子上电启动时只会从NAND Flash/MMC等启动设备中拷贝前8K的代码到SRAM中,然后跳转到SRAM中运行代码。那么问题就来了,如果我们的程序超过8K会出现什么问题呢?程序拷贝不完整运行当然出错。所以就需要我们在前8K的代码中实现将整个程序完整的拷贝到DRAM等其他更大的存储空间,然后在跳转到DRAM中运行我们的程序。这个拷贝然后跳转的过程就叫重定位。前几次的实验都是直接将.bin文件下载到DRAM中运行所以不需要重定位,而这一次,将通过NAND启动然后通过重定位的方式来运行程序。

    第一步:编写连接脚本
      链接脚本就是程序链接的参考文件其主要目的是描述如何把输入文件中的段(SECTION)映射到输出文件中,并控制输出文件的存储布局链接脚本的基本命令是SECTION命令,一个SECTION命令包含一个或多个段,段(SECTION)是链接脚本的基本单元,他表示输入文件中每个段是、如何防止的。

      1)链接脚本中单独的(.)代表当前位置 .=0x1000;表示代码的运行地址是0x1000;
      2)link.dls中的.text/.data/.bss分别是text段,data段和bss段。.text段包含的是start.o和其他代码中的所有text段,.data段包含的是其他代码中的所有.data段,.bss段包含的是其他代码中的所有.bss段
      3)bss_start和bss_end分别保存bss断的的起始和结束地址,在start.S 中将会用到。

    data段:
      数据段(data segment)通常是指用来存放程序中已初始化的全局变量的一块内存区域。数据段属于静态内存分配。

    text段:
      代码段(code segment/text segment)通常是用来存放程序执行代码的的一块内存区域,这部分的内存大小在程序运行前就已经确定并且内存区域通常属于只读,某些架构也代码段为可写。,即允许修改程序。在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。

    bss段:
      BSS段(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域。BSS是英文Block Started by Symbol的简称。BSS段属于静态内存分配。

    堆(heap):

      堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)

    栈(stack):

      栈又称堆栈, 是用户存放程序临时创建的局部变量,也就是说我们函数括弧“{}”中定义的变量(但不包括static声明的变量,static意味着在数据段中存放变量)。除此以外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中。由于栈的先进后出特点,所以栈特别方便用来保存/恢复调用现场。从这个意义上讲,我们可以把堆栈看成一个寄存、交换临时数据的内存区。它是由操作系统分配的,内存的申请与回收都由OS管理。

    第二步:编写代码
      该章节的代码与前几次的大同小异,主要区别在start.S link.lds 和Makefile
    start.S存在四个需要注意的地方
      1)设置SP
        将栈顶sp 指向8*1024 Nand Flash 启动时Tiny6410的内部8K的SRAM被映射到0x0而ARM默认的栈是递减的,所以可以将SP指向881024
      2)增加重定位代码
        首先获取_start标号的当前地址(即0x0)然后取_start的链接地址(即0x100)因为bin文件不需要保存bss段,所以拷贝长度为bss_start的地址减去_start的地址。
      3)清bss段
        首先获取bss_start的链接地址,然后获取bss_end 的链接地址,然后将该部分的内存清零。bss_start和bss_end的地址有Link.dls决定
      4)跳转
        ldr pc ,=main
      由于ldr指令获取的是main函数的连接诶地址,所以执行该句后程序就跳转到0x1000+main函数的offset的地址处

      1 //start.S
      2 // 启动代码
      3 .global _start
      4 
      5 _start:
      6 
      7     // 把外设的基地址告诉CPU
      8     ldr r0, =0x70000000                     
      9     orr r0, r0, #0x13                    
     10     mcr p15,0,r0,c15,c2,4                
     11     
     12     // 关看门狗
     13     ldr r0, =0x7E004000
     14     mov r1, #0
     15     str r1, [r0] 
     16     
     17     // 设置栈
     18     ldr sp, =8*1024
     19     
     20     // 开启icaches
     21 #ifdef  CONFIG_SYS_ICACHE_OFF
     22     bic r0, r0, #0x00001000                 @ clear bit 12 (I) I-cache
     23 #else
     24     orr r0, r0, #0x00001000                 @ set bit 12 (I) I-cache
     25 #endif
     26     mcr p15, 0, r0, c1, c0, 0
     27 
     28     // 设置时钟
     29     bl clock_init
     30     
     31     //重定位
     32     adr r0,_start      //_start的当前地址
     33     ldr r1, =_start   //_start的连接地址
     34     ldr r2, =bss_start
     35     cmp r0,r1
     36     beq clean_bss
     37 //搬移代码    
     38 copy_loop:
     39     ldr r3,[r0],#4
     40     str r3,[r1],#4
     41     cmp r1,r2
     42     bne copy_loop
     43     
     44     //清bss段
     45 clean_bss:
     46     ldr r0, =bss_start
     47     ldr r1, =bss_end
     48     mov r2, #0 
     49     cmp r0, r1
     50     beq on_addr
     51 clean_loop:
     52     str r2, [r0],#4
     53     cmp r0, r1
     54     bne clean_loop
     55 on_addr:
     56     ldr pc, =main
     57 
     58 halt:
     59     b halt
     60     
     61 //Tiny6410Addr.h
     62 #ifndef _Tiny6410Addr_H
     63 #define _Tiny6410Addr_H
     64 //GPK 
     65 #define GPKIO_BASE (0x7F008800)
     66 #define rGPKCON0 (*((volatile unsigned long *)(GPKIO_BASE+0x00)))
     67 #define rGPKDAT  (*((volatile unsigned long *)(GPKIO_BASE+0x08)))
     68 
     69 //CLOCK
     70 #define APLL_LOCK (*((volatile unsigned long *)0x7E00F000))
     71 #define MPLL_LOCK (*((volatile unsigned long *)0x7E00F004))
     72 #define EPLL_LOCK (*((volatile unsigned long *)0x7E00F008))
     73 #define OTHERS    (*((volatile unsigned long *)0x7e00f900))
     74 #define CLK_DIV0  (*((volatile unsigned long *)0x7E00F020))
     75 #define APLL_CON  (*((volatile unsigned long *)0x7E00F00C))
     76 #define MPLL_CON  (*((volatile unsigned long *)0x7E00F010))
     77 #define CLK_SRC   (*((volatile unsigned long *)0x7E00F01C))
     78 
     79 
     80 
     81 //GPA /uart
     82 #define ULCON0     (*((volatile unsigned long *)0x7F005000))
     83 #define UCON0      (*((volatile unsigned long *)0x7F005004))
     84 #define UFCON0     (*((volatile unsigned long *)0x7F005008))
     85 #define UMCON0     (*((volatile unsigned long *)0x7F00500C))
     86 #define UTRSTAT0   (*((volatile unsigned long *)0x7F005010))
     87 #define UFSTAT0    (*((volatile unsigned long *)0x7F005018))
     88 #define UTXH0      (*((volatile unsigned char *)0x7F005020))
     89 #define URXH0      (*((volatile unsigned char *)0x7F005024))
     90 #define UBRDIV0    (*((volatile unsigned short *)0x7F005028))
     91 #define UDIVSLOT0  (*((volatile unsigned short *)0x7F00502C))
     92 #define GPACON     (*((volatile unsigned long *)0x7F008000))
     93 
     94 #endif
     95 
     96 //main.c
     97 
     98 #include "Tiny6410Addr.h"
     99 #define GPK4_OUT  (1<<4*4)
    100 #define GPK5_OUT  (1<<4*5)
    101 #define GPK6_OUT  (1<<4*6)
    102 #define GPK7_OUT  (1<<4*7)
    103 //延时函数
    104 void delay()
    105 {
    106    volatile int i = 0x10000;
    107    while (i--);
    108 }
    109 
    110 int main()
    111 {
    112     unsigned int i = 0x10;
    113     //将GPK4-7设置为输出
    114     rGPKCON0 = GPK4_OUT | GPK5_OUT |GPK6_OUT |GPK7_OUT;
    115     //跑马灯式
    116     while (1)
    117     {
    118         rGPKDAT = i;
    119         i++;
    120         if(i == 0x100)
    121             i=0x10;
    122         delay();
    123     }
    124     
    125     return 0;
    126     }
    127 
    128 //link.lds
    129 SECTIONS
    130 {
    131     . =0x1000;
    132     .text :
    133     {
    134        start.o
    135        *(.text)
    136     }
    137     . = ALIGN(4);
    138     .rodata :
    139     {
    140        * (.rodata)
    141     }
    142     . =ALIGN(4);
    143     .data :
    144     {
    145        *(.data)
    146     }
    147     . = ALIGN(4);
    148     bss_start =.;
    149     .bss :
    150     {
    151        *(.bss)
    152        *(.common)
    153     }
    154     bss_end =.;
    155 
    156 }
    157 //Makefile
    158 link.bin: start.o main.o clock.o uart.o
    159     arm-linux-ld -T link.lds -o link_elf $^
    160     arm-linux-objcopy -O binary -S link_elf link.bin
    161     arm-linux-objdump -D -m arm link_elf > link.dis
    162 
    163 %.o : %.S
    164     arm-linux-gcc -g -c -O2 -o $@ $^
    165 
    166 %.o : %.c
    167     arm-linux-gcc -g -c -O2 -o $@ $^ -fno-builtin 
    168 .PHONY :clean
    169 clean:
    170     rm *.o *.elf *.bin *.dis -f
    View Code
    海阔凭鱼跃,天高任鸟飞。
  • 相关阅读:
    继承在WCF中的问题和解决办法
    bootstrap插件学习-bootstrap.dropdown.js
    C#山寨版本拨号客户端
    关于Certificate、Provisioning Profile、App ID的介绍及其之间的关系
    [源码]Literacy 快速反射读写对象属性,字段
    Hadoop Streaming框架学习(一)
    AOP详解
    SESSION会话技术
    mongodb 备份、还原、导入、导出
    Qt 技巧: 解决未解析的SSL问题
  • 原文地址:https://www.cnblogs.com/chenshikun/p/5840128.html
Copyright © 2011-2022 走看看