13 IMX6ULL裸机开发:程序示例(代码重定位测试)

创建时间:2022/1/18 16:18
更新时间:2022/1/21 14:35
作者:gi51wa2j
标签:100ask_IMX6ULL_v11, bingo, 操作, 正文

一、源文件

relocate.zip

二、数据段重定位

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函数中,添加的函数不需要在头文件声明,直接添加就可以跳转使用
汇编传参数给C语言函数,请温习笔记汇编程序调用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),如下:

Name
Address
g_a
xxxxxxxx

对于链接脚本中的各类Symbol,有2中声明方式:

extern unsigned int __bss_start;     // 声明为一般变量 extern char __bss_start[];           // 声明为数组

不管是哪种方式,它们都会保存在符号表里,比如:

Name
Address
g_a
xxxxxxxx
__bss_start
yyyyyyyy