單片機
返回首頁

S3c2440代碼重定位詳解6---重定位清除BSS段的C函數實現

2021-09-10 來源:eefocus

在前面,我們使用匯編程序來實現了重定位和清bss段,本節我們將使用C語言,實現重定位和清除bss段。


1.打開start.S把原來的匯編代碼刪除改為調用C函數


    /* 重定位text, rodata, data段整個程序 */

    mov r1, #0

    ldr r2, =_start         /* 第1條指令運行時的地址 */

    ldr r3, =__bss_start    /* bss段的起始地址 */


cpy:

    ldr r4, [r1]

    str r4, [r2]

    add r1, r1, #4

    add r2, r2, #4

    cmp r2, r3

    ble cpy


    /* 清除BSS段 */

    ldr r1, =__bss_start

    ldr r2, =_end

    mov r3, #0

clean:

    str r3, [r1]

    add r1, r1, #4

    cmp r1, r2

    ble clean


改為:


    /* 重定位text, rodata, data段整個程序 */

    mov r0, #0

    ldr r1, =_start         /* 第1條指令運行時的地址 */

    ldr r2, =__bss_start    /* bss段的起始地址 */

    sub r2, r2, r1          /*長度*/



    bl copy2sdram  /* src, dest, len */


    /* 清除BSS段 */

    ldr r0, =__bss_start

    ldr r1, =_end


    bl clean_bss  /* start, end */


1、在init.c 實現如上兩個C函數


void copy2sdram(volatile unsigned int *src, volatile unsigned int *dest, unsigned int len)  /* src, dest, len */

{

    unsigned int i = 0;


    while (i < len)

    {

        *dest++ = *src++;

        i += 4;

    }

}



void clean_bss(volatile unsigned int *start, volatile unsigned int *end)  /* start, end */

{

    while (start <= end)

    {

        *start++ = 0;

    }

}


匯編中,為C語言傳入的參數,依次就是R1、R2、R3。

編譯,燒寫運行沒有問題。


我們假設不想匯編傳入參數,而是C語言直接取參數。

1、修改start.S 跳轉到C函數不需要任何參數


    bl sdram_init

    //bl sdram_init2     /* 用到有初始值的數組, 不是位置無關碼 */


    /* 重定位text, rodata, data段整個程序 */

    bl copy2sdram


    /* 清除BSS段 */

    bl clean_bss


2、修改鏈接腳本,讓__code_start 等于當前地址,也就是這里的0x30000000


SECTIONS

{

    . = 0x30000000;


    __code_start = .; //定義__code_start地址位當前地址


    . = ALIGN(4);

    .text      :

    {

      *(.text)

    }


    . = ALIGN(4);

    .rodata : { *(.rodata) }


    . = ALIGN(4);

    .data : { *(.data) }


    . = ALIGN(4);

    __bss_start = .;

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

    _end = .;

}


3、修改init.c 用函數來獲取參數


void copy2sdram(void)

{

    /* 要從lds文件中獲得 __code_start, __bss_start

     * 然后從0地址把數據復制到__code_start

     */


    extern int __code_start, __bss_start;//聲明外部變量


    volatile unsigned int *dest = (volatile unsigned int *)&__code_start;

    volatile unsigned int *end = (volatile unsigned int *)&__bss_start;

    volatile unsigned int *src = (volatile unsigned int *)0;


    while (dest < end)

    {

        *dest++ = *src++;

    }

}



void clean_bss(void)

{

    /* 要從lds文件中獲得 __bss_start, _end

     */

    extern int _end, __bss_start;


    volatile unsigned int *start = (volatile unsigned int *)&__bss_start;

    volatile unsigned int *end = (volatile unsigned int *)&_end;



    while (start <= end)

    {

        *start++ = 0;

    }

}


編譯燒寫運行 ,沒有問題。


總結:

C函數怎么使用lds文件總的變量abc?

1、在C函數中聲明改變量為extern外部變量類型,比如extern int abc;

2、使用時,要取址,比如:int *p = &abc;//p的只即為lds文件中abc的值

匯編文件中可以直接使用外部鏈接腳本中的變量,但C函數中要加上取址符號。


解釋一下原因:

C函數中,定義一個全局變量int g_i;程序中必然有4字節的空間留出來給這個變量g_i

假如我們的lds文件中有很多變量


lds{

    a1 = ;

    a2 = ;

    a3 = ;

    ...

}


如果我們C程序只用到幾個變量,完全沒必要全部存儲lds里面的所有變量,C程序是不保存lds中的變量的。


對于萬一要用到的變量,編譯程序時,有一個symbol table符號表:

在這里插入圖片描述

如何使用symbol table符號表?

1、對于常規變量g_i,得到里面的值,使用&g_i得到addr;

2、為了保持代碼的一致,對于lds中的a1,使用&a1得到里面的值;


結論:

1、C程序中不保存lds文件中的變量,lds再大也不影響;

2、借助symbol table保存lds的變量,使用時加上”&”得到它的值,鏈接腳本的變量要在C程序中聲明為外部變量,任何類型都可以;

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

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

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

  • 新唐 8051單片機教程

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

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

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