一、源文件
二、数据段重定位
2.1 修改链接脚本imx6ull.lds
SECTIONS {
. = 0x80200000;
. = ALIGN(4);
.text :
{
*(.text)
}
. = ALIGN(4);
__rodata_start = .;
.rodata : { *(.rodata) }
. = ALIGN(4);
.data : { *(.data) }
. = ALIGN(4);
__bss_start = .;
.bss : { *(.bss) *(.COMMON) }
__bss_end = .;
}
2.2 修改程序start.s
.text
.global _start
_start:
/* 设置sp */
ldr sp, =(0x80000000+0x100000)
/* rodata/data重定位 */
ldr r0, =__rodata_start
ldr r2, =_start /* link addr */
adr r3, _start /* load addr */
sub r2, r2, r3
sub r1, r0, r2 /* 源 */
ldr r3, =__bss_start
sub r2, r3, r0
bl memcpy /* r0: 目的, r1: 源, r2:长度 */
/* 调用main函数 */
bl main
2.3 添加重定位函数
添加到string.c函数中,添加的函数不需要在头文件声明,直接添加就可以跳转使用
void memcpy(void *dest, void *src, unsigned int len)
{
unsigned char *pcDest = dest;
unsigned char *pcSrc = src;
while (len--)
{
*pcDest = *pcSrc;
pcSrc++;
pcDest++;
}
}
三、 清除BSS段
3.1 修改链接脚本imx6ull.lds
SECTIONS {
. = 0x80200000;
. = ALIGN(4);
.text :
{
*(.text)
}
. = ALIGN(4);
__rodata_start = .;
.rodata : { *(.rodata) }
. = ALIGN(4);
.data : { *(.data) }
. = ALIGN(4);
__bss_start = .;
.bss : { *(.bss) *(.COMMON) }
__bss_end = .;
}
3.2 修改程序start.s
.text
.global _start
_start:
/* 设置sp */
ldr sp, =(0x80000000+0x100000)
/* rodata/data重定位 */
ldr r0, =__rodata_start
ldr r2, =_start /* link addr */
adr r3, _start /* load addr */
sub r2, r2, r3
sub r1, r0, r2 /* 源 */
ldr r3, =__bss_start
sub r2, r3, r0
bl memcpy /* r0: 目的, r1: 源, r2:长度 */
/* clear bss */
ldr r0, =__bss_start
mov r1, #0
ldr r2, =__bss_end
sub r2, r2, r0
bl memset /* r0: dest, r1: val(0), r2: len */
/* 调用main函数 */
bl main
3.3 添加重定位函数
void memcpy(void *dest, void *src, unsigned int len)
{
unsigned char *pcDest = dest;
unsigned char *pcSrc = src;
while (len--)
{
*pcDest = *pcSrc;
pcSrc++;
pcDest++;
}
}
void memset(void *dest, unsigned char val, unsigned int len)
{
unsigned char *pcDest = dest;
while (len--)
{
*pcDest = val;
pcDest++;
}
}
四、代码段重定位
4.1 修改链接脚本imx6ull.lds
SECTIONS {
. = 0x80200000;
. = ALIGN(4);
.text :
{
*(.text)
}
. = ALIGN(4);
__rodata_start = .;
.rodata : { *(.rodata) }
. = ALIGN(4);
.data : { *(.data) }
. = ALIGN(4);
__bss_start = .;
.bss : { *(.bss) *(.COMMON) }
__bss_end = .;
}
4.2 修改程序start.s
.text
.global _start
_start:
/* 设置sp */
ldr sp, =(0x80000000+0x100000)
/* text/rodata/data重定位 */
ldr r0, =_start
adr r1, _start /* 源 */
ldr r3, =__bss_start
sub r2, r3, r0
bl memcpy /* r0: 目的, r1: 源, r2:长度 */
/* clear bss */
ldr r0, =__bss_start
mov r1, #0
ldr r2, =__bss_end
sub r2, r2, r0
bl memset /* r0: dest, r1: val(0), r2: len */
/* 调用main函数 */
//bl main
ldr pc, =main
4.3 添加重定位函数
void memset(void *dest, unsigned char val, unsigned int len)
{
unsigned char *pcDest = dest;
while (len--)
{
*pcDest = val;
pcDest++;
}
}
五、重定位的纯C函数实现
5.1 修改start.s
.text
.global _start
_start:
/* 设置sp */
ldr sp, =(0x80000000+0x100000)
adr r0, _start
bl SystemInit /* 调用SystemInit函数 */
/* 调用main函数 */
//bl main
ldr pc, =main
5.2 修改链接脚本imx6ull.di
SECTIONS {
. = 0x80200000;
. = ALIGN(4);
__text_start = .;
.text :
{
*(.text)
}
. = ALIGN(4);
__rodata_start = .;
.rodata : { *(.rodata) }
. = ALIGN(4);
.data : { *(.data) }
. = ALIGN(4);
__bss_start = .;
.bss : { *(.bss) *(.COMMON) }
__bss_end = .;
}
5.3 添加init.c文件
在string.h中声明这两个函数
#include "string.h"
#if 0
void SystemInit(void *loadaddr)
{
extern char __text_start;
extern char __bss_start;
extern char __bss_end;
unsigned int len;
/* text/rodata/data重定位 */
len = &__bss_start - &__text_start;
memcpy(&__text_start, loadaddr, len); /* 目的, 源, 长度 */
/* clear bss */
len = &__bss_end - &__bss_start;
memset(&__bss_start, 0, len); /* dest, val(0), len */
}
#else
void SystemInit(void *loadaddr)
{
extern char __text_start[];
extern char __bss_start[];
extern char __bss_end[];
unsigned int len;
/* text/rodata/data重定位 */
len = __bss_start - __text_start;
memcpy(__text_start, loadaddr, len); /* 目的, 源, 长度 */
/* clear bss */
len = __bss_end - __bss_start;
memset(__bss_start, 0, len); /* dest, val(0), len */
}
#endif
5.4 问题1: C 语言如何获得链接脚本中的地址
5.4.1 使用方法
extern unsigned int __bss_start;
extern unsigned int __bss_end;
unsigned int len;
len = (unsigned int)&__bss_end - (unsigned int)&__bss_start;
memset(&__bss_start, 0, len);
extern char __bss_start[];
extern char __bss_end[];
unsigned int len;
len = __bss_end - __bss_start;
memset(__bss_start, 0, len);
5.4.2 怎么理解上述代码
对于这样的C变量:
int g_a
编译的时候会有一个符号表(symbol table),如下:
对于链接脚本中的各类Symbol,有2中声明方式:
extern unsigned int __bss_start; // 声明为一般变量
extern char __bss_start[]; // 声明为数组
不管是哪种方式,它们都会保存在符号表里,比如:
Name | Address |
---|
g_a | xxxxxxxx |
__bss_start | yyyyyyyy |