jz2440裸机开发与分析:S3c2440代码重定位详解6---重定位清除BSS段的C函数实现

在前面,我们使用汇编程序来实现了重定位和清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程序中声明为外部变量,任何类型都可以;

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值