單片機
返回首頁

S3c2440代碼重定位詳解2---鏈接腳本的引入與簡單測試

2021-09-09 來源:eefocus

前面程序運行,發現從Nand Flash啟動和從Nor Flash啟動表現是不一樣的。


設置成Nand Flash啟動沒有問題 顯示ABCDE…


設置成NOor Flash啟動則顯示AAA…


這是什么原因呢?


Nor啟動

在這里插入圖片描述

Nor Flash就被認為是0地址,g_Char被放在0x700后面。CPU上電后從0地址開始執行,它能讀取Nor Flash上的代碼,打印出A,當進行g_Char++的時候,寫操作操作無效,下次讀取的數據仍然是A。


NAND啟動

在這里插入圖片描述

上電后,Nand Flash前4K代碼就被自動的復制到SRAM里面,SRAM是CPU認為的0地址。CPU上電后從0地址開始執行,它讀取SRAM上的代碼,并g_Char++修改變量,下次讀取的數據就依次增加了


為了解決Nor Flash里面的變量不能寫的問題,我們把變量所在的數據段放在SDRAM里面,看行不行。


修改Makefile 指定數據段為0x30000000 -Tdata 0x30000000:


 arm-linux-ld -Ttext 0 -Tdata 0x30000000  start.o led.o uart.o init.o main.o -o sdram.elf


這樣的話編譯出來的bin文件 從0地址 到 0x30000000地址 文件大小有700多MB,代碼段和數據段直接有間隔,稱之為黑洞

在這里插入圖片描述

解決黑洞有兩個辦法:

第一個方法:

①把數據段的g_Char和代碼段靠在一起

②燒寫在Nor Flash上面

③運行時把g_char(全局變量)復制到SDRAM,即0x3000000位置(重定位);

第一種辦法如何實現

修改Makefile的代碼段地址,使用鏈接腳本sdram.lds指定。


注釋:#arm-linux-ld -Ttext 0 -Tdata 0x30000000  start.o led.o uart.o init.o main.o -o sdram.elf

修改為: arm-linux-ld -T sdram.lds start.o led.o uart.o init.o main.o -o sdram.elf


鏈接腳本的語法:


SECTIONS {

...

secname start BLOCK(align) (NOLOAD) : AT ( ldadr )

  { contents } >region :phdr =fill

...

}


我們需要依次排列 代碼段、只讀數據段、數據段、.bss段、.common。


其中數據段放在0x800,但運行時在0x3000000:


SECTIONS {

   .text   0  : { *(.text) }//所有文件的.text

   .rodata  : { *(.rodata) } //只讀數據段

   .data 0x30000000 : AT(0x800) { *(.data) } //放在0x700,但運行時在0x3000000

   .bss  : { *(.bss) *(.COMMON) }//所有文件的bss段,所有文件的.COMMON段

}


重新編譯后燒寫bin文件,發現啟動后顯示亂碼。原因是我們從0x30000000處獲取g_Char,但在這之前,并沒有在0x30000000處準備好數據。因此需要重定位數據段,將0x700的數據移動到0x30000000處,在start.S加入:


 bl sdram_init


 /* 重定位data段 */

 mov r1, #0x700 

 ldr r0, [r1]

 mov r1, #0x30000000

 str r0, [r1]


 bl main


上面的這種方法,只能復制0x800處的一位數據,不太通用,下面寫一個更加通用的復制方法:

鏈接腳本修改如下:


SECTIONS {

   .text   0  : { *(.text) }

   .rodata  : { *(.rodata) }

   .data 0x30000000 : AT(0x700) 

   { 

      data_load_addr = LOADADDR(.data);

      data_start = . ;//等于當前位置

      *(.data)  //等于數據段的大小

      data_end = . ;//等于當前位置

   }

   .bss  : { *(.bss) *(.COMMON) }

}


修改start.S


    bl sdram_init   


    /* 重定位data段 */

    ldr r1, =data_load_addr  /* data段在bin文件中的地址, 加載地址 */

    ldr r2, =data_start      /* data段在重定位地址, 運行時的地址 */

    ldr r3, =data_end        /* data段結束地址 */


cpy:

    ldrb r4, [r1] //從r1讀到r4

    strb r4, [r2] //r4存放到r2

    add r1, r1, #1 //r1+1

    add r2, r2, #1 //r2+1

    cmp r2, r3 //r2 r3比較

    bne cpy //如果不等則繼續拷貝


    bl main


第二個方法

①讓文件直接從0x30000000開始,全局變量在0x3……;

②燒寫Nor Flash上 0地址處;

③運行會把整個代碼段數據段(整個程序)從0地址復制到SDRAM的0x30000000(重定位);


這兩個方法的區別是前者只重定位了數據段,后者重定位了數據段和代碼段。

進入單片機查看更多內容>>
相關視頻
  • TI 新一代 C2000? 微控制器:全方位助力伺服及馬達驅動應用

  • MSP430電容觸摸技術 - 防水Demo演示

  • 直播回放: Microchip Timberwolf? 音頻處理器在線研討會

  • 新唐 8051單片機教程

  • 基于靈動MM32W0系列MCU的指夾血氧儀控制及OTA升級應用方案分享

  • 基于靈動MM32SPIN系列MCU的無感FOC便攜冰箱應用方案分享

    相關電子頭條文章
萝卜大香蕉